Installing GNAT & Alire, and Your First Program
Install the GNAT compiler (via Alire or a standalone GNAT FSF build), understand what gnatmake, gcc, gnatbind and gnatlink do, compile and run your first Ada program, and use Put, Put_Line and New_Line to produce output.
Before writing real Ada you need a compiler. The standard open-source toolchain is GNAT, the Ada front end of GCC. The easiest way to get it today is Alire, Ada's package manager, which downloads a GNAT toolchain and the gprbuild project builder for you; you can also download a standalone GNAT FSF build. This lesson shows the installation options, walks through what actually happens when you build an Ada program (compile, bind, link), and writes and runs a first program that prints text.
Getting a Compiler: Alire or GNAT FSF
Alire (command 'alr') is the recommended starting point on Windows, Linux and macOS. After installing it, 'alr toolchain --select' downloads a GNAT compiler and gprbuild, and 'alr init --bin hello' creates a ready-to-build project with a GNAT project file (hello.gpr), a src folder and a main procedure. 'alr build' compiles it and 'alr run' runs it. Alire also manages library dependencies ('alr with <crate>') from its community index.
Alternatively, download a standalone GNAT FSF build (the same builds Alire uses, published on GitHub by the Alire project), unpack it, and add its bin directory to your PATH. On Linux distributions GNAT is usually available as a package (for example 'gnat' on Debian/Ubuntu). Editors: GNAT Studio (a full Ada IDE) or VS Code with the official Ada & SPARK extension (powered by the Ada Language Server) give completion, navigation and error highlighting. Check your installation with 'gnat --version' — on the machine used to verify this course it prints 'GNAT 16.1.0'.
• Alire: alr toolchain --select, alr init --bin name, alr build, alr run, alr with crate. • Standalone: GNAT FSF build or Linux package; add bin/ to PATH. • IDEs: GNAT Studio, or VS Code + Ada & SPARK extension (Ada Language Server). • Verify with gnat --version.
From Source to Executable: Compile, Bind, Link
Ada source files use the extensions .ads (specifications) and .adb (bodies), and GNAT expects the file name to match the unit name in lower case: procedure Hello lives in hello.adb, package Stacks in stacks.ads/stacks.adb. The simplest build command is 'gnatmake hello.adb', which runs three steps. First gcc -c compiles each unit to an object file (.o) plus an Ada Library Information file (.ali) recording dependencies. Second, gnatbind reads the .ali files, checks that every unit is consistent and up to date, and determines a legal elaboration order (the order in which packages are initialized). Third, gnatlink links everything, including the Ada run-time library, into an executable.
The binder step is special to Ada: it guarantees you never link stale or inconsistent units, and that library-level initialization runs in a valid order. In larger projects you use gprbuild with a .gpr project file instead of gnatmake; it handles multiple directories, languages and build switches. Useful switches: -gnat2022 (language version), -gnata (enable assertions and contracts), -gnatwa (enable most warnings), -g (debug info), -O2 (optimize).
• .ads = specification, .adb = body; file name = unit name in lower case. • gnatmake = gcc -c (compile) + gnatbind (bind) + gnatlink (link). • .ali files store dependency/consistency information. • Binder checks consistency and computes elaboration order. • Common switches: -gnat2022, -gnata, -gnatwa, -g, -O2.
Output with Ada.Text_IO
Ada.Text_IO is the standard package for text input and output. Put writes text without a line terminator, Put_Line writes text followed by a newline, and New_Line ends the current line (New_Line (3) writes three). Put and Put_Line take a String; to print a number, convert it with the 'Image attribute (Integer'Image (42) gives " 42" — note the leading space reserved for the sign of non-negative numbers) or use the numeric I/O packages covered later. The & operator concatenates strings.
A 'use' clause (use Ada.Text_IO;) lets you write Put_Line instead of Ada.Text_IO.Put_Line. Many Ada style guides prefer fully qualified names in large programs for clarity, but use clauses are perfectly fine for small programs and for Text_IO in particular.
• Put (text) — no newline; Put_Line (text) — with newline; New_Line — end the line. • Numbers must be converted to text: Integer'Image (N) (adds a leading space for non-negative values). • & concatenates strings. • use Ada.Text_IO; removes the need for the package prefix.
Code Examples
A real build transcript (GNAT 16.1 on Windows). gnatmake shows each step it runs: compiling to hello.o and hello.ali, binding, and linking into hello.exe. The .o and .ali files are build artefacts; hello.adb is your source.
The equivalent workflow with Alire. These commands are shown for reference; Alire generates my_app.gpr, alire.toml and src/my_app.adb for you.
Put writes without a newline, so the year appears on the same line; Integer'Image (1983) produces " 1983" with a leading space. New_Line outputs an empty line. Output: Ada was standardized in 1983 Current standard: Ada 2022 -- file: Main_Program.adb procedure Hello is...
-- file: hello.adb procedure Hello is ...
GNAT's default naming rule expects the file name to be the unit name in lower case with .adb/.ads. A mismatch gives a 'file name does not match unit name' warning or build failure.
Put_Line ("Total: " & 42);
Put_Line ("Total:" & Integer'Image (42));
& concatenates Strings; an Integer is not a String. Convert with 'Image (or use Ada.Integer_Text_IO).
Put_Line ("Line one") Put_Line ("Line two");
Put_Line ("Line one"); Put_Line ("Line two");
Every Ada statement ends with a semicolon, including the last one before 'end'.
Which three steps does gnatmake perform? A. Parse, interpret, run B. Compile, bind, link C. Preprocess, assemble, load D. Download, compile, test
B. Compile, bind, link — gcc -c compiles units, gnatbind checks consistency and elaboration order, gnatlink produces the executable.
Which file extension holds an Ada package specification? A. .adb B. .ali C. .ads D. .gpr
C. .ads — specifications; bodies use .adb; .ali is binder information; .gpr is a GNAT project file.
What is the difference between Put and Put_Line? A. Put prints numbers, Put_Line prints strings B. Put_Line adds a line terminator after the text C. Put is faster D. There is none
B. Put_Line adds a line terminator after the text; Put leaves the cursor on the same line.
Why does Integer'Image (5) produce " 5" rather than "5"? A. A bug in GNAT B. It reserves a leading position for the sign of non-negative numbers C. It pads to width 2 D. It adds a tab
B. It reserves a leading position for the sign — negative values print as "-5" in the same width.
Write a program that prints your name on one line and, on the next line, 'Year:' followed by the current year using 'Image.
with Ada.Text_IO; use Ada.Text_IO; procedure About_Me is Year : constant Integer := 2026; begin Put_Line ("Ada Learner"); Put_Line ("Year:" & Integer'Image (Year)); end About_Me;
Save as about_me.adb and build with gnatmake about_me.adb. 'Image provides the leading space, so the second line reads 'Year: 2026'.
$ gnatmake -gnat2022 hello.adb
gcc -c -gnat2022 hello.adb
gnatbind -x hello.ali
gnatlink hello.ali
$ ./hello
Hello, Ada!
Named after Ada Lovelace, the first programmer.
$ ls
hello.adb hello.ali hello.exe hello.o$ alr init --bin my_app # create a new executable project
$ cd my_app
$ alr build # builds with gprbuild using my_app.gpr
$ alr run # runs bin/my_appwith Ada.Text_IO; use Ada.Text_IO;
procedure L2_Greet is
Year : constant Integer := 1983;
begin
Put ("Ada was standardized in"); -- Put: no newline
Put_Line (Integer'Image (Year)); -- 'Image turns a number into text
New_Line; -- blank line
Put_Line ("Current standard: Ada 2022");
end L2_Greet;