GNAT Toolchain Basics

This chapter presents a couple of basic commands from the GNAT toolchain.

Basic commands

Now that the toolchain is installed, you can start using it. From the command line, you can compile a project using gprbuild. For example:

gprbuild -P project.gpr

You can find the binary built with the command above in the obj directory. You can the run it in the same way as you would do with any other executable on your platform. For example:

obj/main

A handy command-line option for gprbuild you might want to use is -p, which automatically creates directories such as obj if they aren't in the directory tree:

gprbuild -p -P project.gpr

Ada source-code are stored in .ads and .adb files. To view the content of these files, you can use GNAT Studio. To open GNAT Studio, double-click on the .gpr project file or invoke GNAT Studio on the command line:

gps -P project.gpr

To compile your project using GNAT Studio, use the top-level menu to invoke BuildProjectmain.adb (or press the keyboard shortcut F4). To run the main program, click on BuildRunmain (or press the keyboard shortcut Shift + F2).

Compiler warnings

One of the strengths of the GNAT compiler is its ability to generate many useful warnings. Some are displayed by default but others need to be explicitly enabled. In this section, we discuss some of these warnings, their purpose, and how you activate them.

-gnatwa switch and warning suppression

Section author: Robert Duff

We first need to understand the difference between a warning and an error. Errors are violations of the Ada language rules as specified in the Ada Reference Manual; warnings don't indicate violations of those rules, but instead flag constructs in a program that seem suspicious to the compiler. Warnings are GNAT-specific, so other Ada compilers might not warn about the same things GNAT does or might warn about them in a different way. Warnings are typically conservative; meaning that some warnings are false alarms. The programmer needs to study the code to determine if each warning is describing a real problem.

Some warnings are produced by default while others are produced only if a switch enables them. Use the -gnatwa switch to turn on (almost) all warnings.

Warnings are useless if you don't do anything about them. If you give your team member some code that causes warnings, how are they supposed to know whether they represent real problems? If you don't address each warning, people will soon starting ignoring warnings and there'll be lots of things that generates warnings scattered all over your code. To avoid this, you may want to use the -gnatwae switch to both turn on (almost) all warnings and to treat warnings as errors. This forces you to get a clean (no warnings or errors) compilation.

However, as we said, some warnings are false alarms. Use pragma Warnings (Off) to suppress those warnings. It's best to be as specific as possible and narrow down to a single line of code and a single warning. Then use a comment to explain why the warning is a false alarm if it's not obvious.

Let's look at the following example:

with Ada.Text_IO; use Ada.Text_IO;

package body Warnings_Example is

   procedure Mumble (X : Integer) is
   begin
      Put_Line ("Mumble processing...");
   end Mumble;

end Warnings_Example;

We compile the above code with -gnatwae:

gnat compile -gnatwae ./src/warnings_example.adb

This causes GNAT to complain:

warnings_example.adb:5:22: warning: formal parameter "X" is not referenced

But the following compiles cleanly:

with Ada.Text_IO; use Ada.Text_IO;

package body Warnings_Example is

   pragma Warnings (Off, "formal parameter ""X"" is not referenced");
   procedure Mumble (X : Integer) is
   pragma Warnings (On, "formal parameter ""X"" is not referenced");

   --  X is ignored here, because blah blah blah...
   begin
      Put_Line ("Mumble processing...");
   end Mumble;

end Warnings_Example;

Here we've suppressed a specific warning message on a specific line.

If you get many warnings of a specific type and it's not feasible to fix all of them, you can suppress that type of message so the good warnings won't get buried beneath a pile of bogus ones. For example, you can use the -gnatwaeF switch to silence the warning on the first version of Mumble above: the F suppresses warnings on unreferenced formal parameters. It would be a good idea to use it if you have many of those.

As discussed above, -gnatwa activates almost all warnings, but not all. Refer to the section on warnings of the GNAT User's Guide to get a list of the remaining warnings you could enable in your project. One is -gnatw.o, which displays warnings when the compiler detects modified but unreferenced out parameters. Consider the following example:

package Warnings_Example is

   procedure Process (X : in out Integer;
                      B :    out Boolean);

end Warnings_Example;
package body Warnings_Example is

   procedure Process (X : in out Integer;
                      B :    out Boolean) is
   begin
      if X = Integer'First or else X = Integer'Last then
         B := False;
      else
         X := X + 1;
         B := True;
      end if;
   end Process;

end Warnings_Example;
with Ada.Text_IO; use Ada.Text_IO;

with Warnings_Example; use Warnings_Example;

procedure Main  is
   X : Integer := 0;
   Success : Boolean;
begin
   Process (X, Success);
   Put_Line (Integer'Image (X));
end Main;

If we build the main application using the -gnatw.o switch, the compiler warns us that we didn't reference the Success variable, which was modified in the call to Process:

main.adb:8:16: warning: "Success" modified by call, but value might not be referenced

In this case, this actually points us to a bug in our program, since X only contains a valid value if Success is True. The corrected code for Main is:

-- ...
begin
   Process (X, Success);

   if Success then
      Put_Line (Integer'Image (X));
   else
      Put_Line ("Couldn't process variable X.");
   end if;
end Main;

We suggest turning on as many warnings as makes sense for your project. Then, when you see a warning message, look at the code and decide if it's real. If it is, fix the code. If it's a false alarm, suppress the warning. In either case, we strongly recommend you make the warning disappear before you check your code into your configuration management system.

Style checking

GNAT provides many options to configure style checking of your code. The main compiler switch for this is -gnatyy, which sets almost all standard style check options. As indicated by the section on style checking of the GNAT User's Guide, using this switch "is equivalent to -gnaty3aAbcefhiklmnprst, that is all checking options enabled with the exception of -gnatyB, -gnatyd, -gnatyI, -gnatyLnnn, -gnatyo, -gnatyO, -gnatyS, -gnatyu, and -gnatyx."

You may find that selecting the appropriate coding style is useful to detect issues at early stages. For example, the -gnatyO switch checks that overriding subprograms are explicitly marked as such. Using this switch can avoid surprises when you didn't intentionally want to override an operation for some data type. We recommend studying the list of coding style switches and selecting the ones that seem relevant for your project. When in doubt, you can start by using all of them — using -gnatyy and -gnatyBdIL4oOSux, for example — and deactivating the ones that cause too much noise during compilation.