GNAT User's Guide

GNAT, The GNU Ada 95 Compiler

Document revision level 1.122 $

GNAT Version 3.11p

August 30, 1998

Ada Core Technologies, Inc.


Table of Contents


\

(C) Copyright 1995-1998, Ada Core Technologies, Inc.

Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.

Silicon Graphics and IRIS are registered trademarks and IRIX is a trademark of Silicon Graphics, Inc.

IBM PC is a trademark of International Business Machines Corporation.

UNIX is a registered trademark of AT&T Bell Laboratories. DIGITAL

The following are trademarks of Digital Equipment Corporation: DEC, DEC Ada, DECthreads, DIGITAL, DECset, OpenVMS, and VAX.

About This Guide

This guide describes the use of GNAT, the full language compiler for the Ada 95 programming language. It describes the features of the compiler, and details how you can use it to build Ada 95 applications.

What This Guide Contains

This guide contains the following chapters:

What You Should Know Before Reading This Guide

This user's guide assumes that you are familiar with Ada 95 language, as described in the International Standard ANSI/ISO/IEC-8652:1995, Jan 1995.

Related Information

For further information about related tools, refer to the following documents:

Conventions

Following are examples of the typographical and graphic conventions used in this guide:

Commands that are entered by the user are preceded in this manual by the characters "$ " (dollar sign followed by space). If your system uses this sequence as a prompt, then the commands will appear exactly as you see them in the manual. If your system uses some other prompt, then the command will appear with the $ replaced by whatever prompt character you are using.

Getting Started With GNAT

This chapter describes the simplest ways of using GNAT to compile Ada programs.

Running GNAT

Three steps are needed to create an executable file from an Ada source file:

  1. The source file(s) must be compiled.
  2. The file(s) must be bound using the GNAT binder.
  3. All appropriate object files must be linked to produce an executable.

All three steps are most commonly handled by using the gnatmake utility program that, given the name of the main program, automatically performs the necessary compilation, binding and linking steps.

Running a Simple Ada Program

Any editor may be used to prepare an Ada program. If emacs is used, the optional Ada mode may be helpful in laying out the program. The program text is a normal text file. We will suppose in our initial example that you have used your editor to prepare the following standard format text file:

with Text_IO; use Text_IO;
procedure Hello is
begin
   Put_Line ("Hello WORLD!");
end Hello;

This file should be named `hello.adb'. Using the normal default file naming conventions, By default, GNAT requires that each file contain a single compilation unit whose file name corresponds to the unit name with periods replaced by hyphens, and whose extension is `.ads' for a spec and `.adb' for a body. This default file naming convention can be overridden by use of the special pragma Source_File_Name see section Using Other File Names. Alternatively, if you want to rename your files according to this default convention, which is probably more convenient if you will be using GNAT for all your compilation requirements, then the gnatchop utility can be conveniently used to perform this renaming operation see section Renaming Files Using gnatchop).

You can compile the program using the following command:

$ gcc -c hello.adb

gcc is the command used to access the compiler. This compiler is capable of compiling programs in several languages including Ada 95 and C. It determines you have given it an Ada program by the extension (`.ads' or `.adb'), and will call the GNAT compiler to compile the specified file.

The -c switch is required. It tells gcc to do a compilation. (For C programs, gcc can also do linking, but this capability is not used directly for Ada programs, so the -c switch must always be present.)

This compile command generates a file `hello.o' which is the object file corresponding to your Ada program. It also generates a file `hello.ali' which contains additional information used to check that an Ada program is consistent. To get an executable file, we then use gnatbind to bind the program and gnatlink to link it to produce the executable.

$ gnatbind hello.ali
$ gnatlink hello.ali

A simpler method of carrying out these steps is to use gnatmake, which is a master program which invokes all of the required compilation, binding and linking tools in the correct order. In particular, gnatmake automatically recompiles any sources that have been modified since they were last compiled, or sources that depend on such modified sources, so that a consistent compilation is ensured.

$ gnatmake hello.adb

The result is an executable program called `hello', which can be run by entering:

./hello

and, if all has gone well, you will see

Hello WORLD!

appear in response to this command.

Running a Program With Multiple Units

Consider a slightly more complicated example that has three files: a main program, and the spec and body of a package:

package Greetings is
   procedure Hello;
   procedure Goodbye;
end Greetings;

with Text_IO; use Text_IO;
package body Greetings is
   procedure Hello is
   begin
      Put_Line ("Hello WORLD!");
   end Hello;
   procedure Goodbye is
   begin
      Put_Line ("Goodbye WORLD!");
   end Goodbye;
end Greetings;

with Greetings;
procedure Gmain is
begin
   Greetings.Hello;
   Greetings.Goodbye;
end Gmain;

Following the one-unit-per-file rule, place this program in the following three separate files:

`greetings.ads'
spec of package Greetings
`greetings.adb'
body of package Greetings
`gmain.adb'
body of main program

To build an executable version of this program, we could use four separate steps to compile, bind, and link the program, as follows:

$ gcc -c gmain.adb
$ gcc -c greetings.adb
$ gnatbind gmain.ali
$ gnatlink gmain.ali

Note that there is no required order of compilation when using GNAT. In particular it is perfectly fine to compile the main program first. Also, it is not necessary to compile package specs in the case where there is a separate body, only the body need be compiled. If you want to submit these programs to the compiler for semantic checking purposes, then you use the -gnatc switch:

$ gcc -c greetings.ads -gnatc

Although the compilation can be done in separate steps as in the above example, in practice it is almost always more convenient to use the gnatmake capability. All you need to know in this case is the name of the main program source file. The effect of the above four commands can be achieved with a single one:

$ gnatmake gmain.adb

In the next section we discuss the advantages of using gnatmake in more detail.

Using the gnatmake Utility

If you work on a program by compiling single components at a time using gcc, you typically keep track of the units you modify. In order to build a consistent system, you compile not only these units, but also any units that depend on the units you have modified. For example, in the preceding case, if you edit `gmain.adb', you only need to recompile that file. But if you edit `greetings.ads', you must recompile both `greetings.adb' and `gmain.adb', because both files contain units that depend on `greetings.ads'.

gnatbind will warn you if you forget one of these compilation steps, so that it is impossible to generate an inconsistent program as a result of forgetting to do a compilation. Nevertheless it is tedious and error-prone to keep track of dependencies among units. One approach to handle the dependency-bookkeeping is to use a make file. However, make files present maintenance problems of their own: if the dependencies change as you change the program, you must make sure that the make file is kept up-to-date manually, which is also an error-prone process.

The gnatmake utility takes care of these details automatically. Invoke it using either one of the following forms:

$ gnatmake gmain.adb
$ gnatmake gmain

The argument is the name of the file containing the main program from which you may omit the extension. gnatmake examines the environment, automatically recompiles any files that need recompiling, and binds and links the resulting set of object files, generating the executable file, `gmain'. In a large program, it can be extremely helpful to use gnatmake, because working out by hand what needs to be recompiled can be difficult.

Note that gnatmake takes into account all the intricate Ada 95 rules that establish dependencies among units. These include dependencies that result from inlining subprogram bodies, and from generic instantiation. Unlike some other Ada make tools, gnatmake does not rely on the dependencies that were found by the compiler on a previous compilation, which may possibly be wrong when sources change. gnatmake determines the exact set of dependencies from scratch each time it is run.

The GNAT Compilation Model

This chapter describes the compilation model used by GNAT. Although similar to that used by other languages, such as C and C++, this model is substantially different from the traditional Ada compilation models, which are based on a library. The model is initially described without reference to the library-based model. If you have not previously used an Ada compiler, you need only read the first part of this chapter. The last section describes and discusses the differences between the GNAT model and the traditional Ada compiler models. If you have used other Ada compilers, this section will help you to understand those differences, and the advantages of the GNAT model.

Source Representation

Ada source programs are represented in standard text files, using Latin-1 coding. Latin-1 is an 8-bit code that includes the familiar 7-bit ASCII set, plus additional characters used for representing foreign languages (see section Foreign Language Representation for support of non-USA character sets). The format effector characters are represented using their standard ASCII encodings, as follows:

VT
Vertical tab, 16#0B#
HT
Horizontal tab, 16#09#
CR
Carriage return, 16#0D#
LF
Line feed, 16#0A#
FF
Form feed, 16#0C#

Source files are in standard text file format. In addition, GNAT will recognize a wide variety of stream formats, in which the end of physical physical lines is marked by any of the following sequences: LF, CR, CR-LF, or LF-CR. This is useful in accomodating files that are imported from other operating systems.

The end of a source file is normally represented by the physical end of file. However the control character 16#1A# (SUB) is also recognized as signalling the end of the source file. Again, this is provided for compatibility with other operating systems where this code is used to represent the end of file.

Each file contains a single Ada compilation unit, including any pragmas associated with the unit. For example, this means you must place a package declaration (a package spec) and the corresponding body in separate files. An Ada compilation (which is a sequence of compilation units) is represented using a sequence of files. Similarly, you will place each subunit or child unit in a separate file.

Foreign Language Representation

GNAT supports the standard character sets defined in Ada 95 as well as several other non-standard character sets for use in localized versions of the compiler.

Latin-1

The basic character set is Latin-1. This character set is defined by ISO standard 8859, part 1. The lower half (character codes 16#00# ... 16#7F#) is identical to standard ASCII coding, but the upper half is used to represent additional characters. These include extended letters used by European languages, such as French accents, the vowels with umlauts used in German, and the extra letter A-ring used in Swedish.

For a complete list of Latin-1 codes and their encodings, see the source file of library unit Ada.Characters.Latin_1 in file `a-chlat1.ads'. You may use any of these extended characters freely in character or string literals. In addition, the extended characters that represent letters can be used in identifiers.

Other 8-Bit Codes

GNAT also supports several other 8-bit coding schemes:

Latin-2
Latin-2 letters allowed in identifiers, with uppercase and lowercase equivalence.
Latin-3
Latin-3 letters allowed in identifiers, with uppercase and lowercase equivalence.
Latin-4
Latin-4 letters allowed in identifiers, with uppercase and lowercase equivalence.
IBM PC (code page 437)
This code page is the normal default for PCs in the U.S. It corresponds to the original IBM PC character set. This set has some, but not all, of the extended Latin-1 letters, but these letters do not have the same encoding as Latin-1. In this mode, these letters are allowed in identifiers with uppercase and lowercase equivalence.
IBM PC (code page 850)
This code page is a modification of 437 extended to include all the Latin-1 letters, but still not with the usual Latin-1 encoding. In this mode, all these letters are allowed in identifiers with uppercase and lowercase equivalence.
Full Upper 8-bit
Any character in the range 80-FF allowed in identifiers, and all are considered distinct. In other words, there are no uppercase and lowercase equivalences in this range. This is useful in conjunction with certain encoding schemes used for some foreign character sets (e.g. the typical method of representing Chinese characters on the PC).
No Upper-Half
No upper-half characters in the range 80-FF are allowed in identifiers. This gives Ada 83 compatibility for identifier names.

For precise data on the encodings permitted, and the uppercase and lowercase equivalences that are recognized, see the file `csets.adb' in the GNAT compiler sources. You will need to obtain a full source release of GNAT to obtain this file.

Wide Character Encodings

GNAT allows wide character codes to appear in character and string literals, and also optionally in identifiers, by means of the following possible encoding schemes:

Hex Coding
In this encoding, a wide character is represented by the following five character sequence:
ESC a b c d
Where a, b, c, d are the four hexadecimal characters (using uppercase letters) of the wide character code. For example, ESC A345 is used to represent the wide character with code 16#A345#. This scheme is compatible with use of the full Wide_Character set.
Upper-Half Coding
The wide character with encoding 16#abcd# where the upper bit is on (in other words, "a" is in the range 8-F) is represented as two bytes, 16#ab# and 16#cd#. The second byte cannot be a format control character, but is not required to be in the upper half. This method can be also used for shift-JIS or EUC, where the internal coding matches the external coding.
Shift JIS Coding
A wide character is represented by a two-character sequence, 16#ab# and 16#cd#, with the restrictions described for upper-half encoding as described above. The internal character code is the corresponding JIS character according to the standard algorithm for Shift-JIS conversion. Only characters defined in the JIS code set table can be used with this encoding method.
EUC Coding
A wide character is represented by a two-character sequence 16#ab# and 16#cd#, with both characters being in the upper half. The internal character code is the corresponding JIS character according to the EUC encoding algorithm. Only characters defined in the JIS code set table can be used with this encoding method.
UTF-8 Coding
A wide character is represented using UCS Transformation Format 8 (UTF-8) as defined in Annex R of ISO 10646-1/Am.2. Depending on the character value, the representation is a one, two, or three byte sequence:
16#0000#-16#007f#: 2#0xxxxxxx#
16#0080#-16#07ff#: 2#110xxxxx# 2#10xxxxxx#
16#0800#-16#ffff#: 2#1110xxxx# 2#10xxxxxx# 2#10xxxxxx#
where the xxx bits correspond to the left-padded bits of the the 16-bit character value. Note that all lower half ASCII characters are represented as ASCII bytes and all upper half characters and other wide characters are represented as sequences of upper-half (The full UTF-8 scheme allows for encoding 31-bit characters as 6-byte sequences, but in this implementation, all UTF-8 sequences of four or more bytes length will be treated as illegal).
Brackets Coding
In this encoding, a wide character is represented by the following eight character sequence:
[ " a b c d " ]
Where a, b, c, d are the four hexadecimal characters (using uppercase letters) of the wide character code. For example, ["A345"] is used to represent the wide character with code 16#A345#. It is also possible (though not required) to use the Brackets coding for upper half characters. For example, the code 16#A3# can be represented as ["A3"]. This scheme is compatible with use of the full Wide_Character set, and is also the method used for wide character encoding in the standard ACVC (Ada Compiler Validation Capability) test suite distributions.

Note: Some of these coding schemes do not permit the full use of the Ada 95 character set. For example, neither Shift JIS, nor EUC allow the use of the upper half of the Latin-1 set.

File Naming Rules

The default file name is determined by the name of the unit that the file contains. The name is formed by taking the full expanded name of the unit and replacing the separating dots with hyphens and using lowercase for all letters.

An exception arises if the file name generated by the above rules starts with one of the characters a,g,i, or s, and the second character is a minus. In this case, the character tilde is used in place of the minus. The reason for this special rule is to avoid clashes with the standard names for child units of the packages System, Ada, Interfaces, and GNAT, which use the prefixes s- a- i- and g- respectively.

The file extension is `.ads' for a spec and `.adb' for a body. The following list shows some examples of these rules.

`main.ads'
Main (spec)
`main.adb'
Main (body)
`arith_functions.ads'
Arith_Functions (package spec)
`arith_functions.adb'
Arith_Functions (package body)
`func-spec.ads'
Func.Spec (child package spec)
`func-spec.adb'
Func.Spec (child package body)
`main-sub.adb'
Sub (subunit of Main)
`a~bad.adb'
A.Bad (child package body)

Following these rules can result in excessively long file names if corresponding unit names are long (for example, if child units or subunits are heavily nested). An option is available to shorten such long file names (called file name "krunching"). This may be particularly useful when programs being developed with GNAT are to be used on operating systems with limited file name lengths. See section Using gnatkr.

Of course, no file shortening algorithm can guarantee uniqueness over all possible unit names; if file name krunching is used, it is your responsibility to ensure no name clashes occur. Alternatively you can specify the exact file names that you want used, as described in the next section. Finally, if your Ada programs are migrating from a compiler with a different naming convention, you can use the gnatchop utility to produce source files that follow the GNAT naming conventions. See (see section Renaming Files Using gnatchop) for details.

Using Other File Names

In the previous section, we have described the default rules used by GNAT to determine the file name in which a given unit resides. It is often convenient to follow these default rules, and if you follow them, the compiler knows without being explicitly told where to find all the files it needs.

However, in some cases, particularly when a program is imported from another Ada compiler environment, it may be more convenient for the programmer to specify which file names contain which units. GNAT allows arbitrary file names to be used by means of the Source_File_Name pragma. The form of this pragma is as shown in the following examples:

pragma Source_File_Name (My_Utilities.Stacks,
  Spec_File_Name => "myutilst_a.ada");
pragma Source_File_name (My_Utilities.Stacks,
  Body_File_Name => "myutilst.ada");

As shown in this example, the first argument for the pragma is the unit name (in this example a child unit). The second argument has the form of a named association. The identifier indicates whether the file name is for a spec or a body; the file name itself is given by a string literal.

The source file name pragma is a configuration pragma, which means that normally it will be placed in the `gnat.adc' file used to hold configuration pragmas that apply to a complete compilation environment. For more details on how the `gnat.adc' file is created and used see See section Handling of Configuration Pragmas.

GNAT allows completely arbitrary file names to be specified using the source file name pragma. However, if the file name specified has an extension other than `.ads' `.adb' or `.ada' it is necesary to use a special syntax when compiling the file. The name in this case must be preceded by the special sequence -x followed by a space, as in:

$ gcc -c -x peculiar_file_name.sim

gnatmake handles non-standard file names in the usual manner (the non-standard file name for the main program is simply used as the argument to gnatmake). Note that if the extension is also non-standard, then it must be included in the gnatmake command, it may not be omitted.

Generating Object Files

An Ada program consists of a set of source files, and the first step in compiling the program is to generate the corresponding object files. These are generated by compiling a subset of these source files. The files you need to compile are the following:

The preceding rules describe the set of files that must be compiled to generate the object files for a program. Each object file has the same name as the corresponding source file, except that the extension is `.o' as usual.

You may wish to compile other files for the purpose of checking their syntactic and semantic correctness. For example, in the case where a package has a separate spec and body, you would not normally compile the spec. However, it is convenient in practice to compile the spec to make sure it is error-free before compiling clients of this spec, because such compilations will fail if there is an error in the spec.

GNAT provides an option for compiling such files purely for the purposes of checking correctness; such compilations are not required as part of the process of building a program. To compile a file in this checking mode, use the -gnatc switch.

Source Dependencies

A given object file clearly depends on the source file which is compiled to produce it. Here we are using depends in the sense of a typical make utility; in other words, an object file depends on a source file if changes to the source file require the object file to be recompiled. In addition to this basic dependency, a given object may depend on additional source files as follows:

These rules are applied transitively: if unit A with's unit B, whose elaboration calls an inlined procedure in package C, the object file for unit A will depend on the body of C, in file `c.adb'.

The set of dependent files described by these rules includes all the files on which the unit is semantically dependent, as described in the Ada 95 Language Reference Manual. However it is a superset of what the ARM describes, because it includes generic, inline, and subunit dependencies.

An object file must be recreated by recompiling the corresponding source file if any of the source files on which it depends are modified. For example, if the make utility is used to control compilation, the rule for an Ada object file must mention all the source files on which the object file depends, according to the above definition. The determination of the necessary recompilations is done automatically when one uses gnatmake.

The Ada Library Information Files

Each compilation actually generates two output files. The first of these is the normal object file that has a `.o' extension. The second is a text file containing full dependency information. It has the same name as the source file, but an `.ali' extension. This file is known as the Ada Library Information (ALI) file.

Normally you need not be concerned with the contents of this file. This section is included in case you want to understand how these files are being used by the binder and other GNAT utilities. Each ALI file consists of a series of lines of the form:

Key_Character parameter parameter ...

The first two lines in the file identify the library output version and Standard version. These are required to be consistent across the entire set of compilation units in your program.

V "xxxxxxxxxxxxxxxx"

This line indicates the library output version, as defined in `gnatvsn.ads'. It ensures that separate object modules of a program are consistent. The library output version must be changed if anything in the compiler changes that would affect successful binding of modules compiled separately. Examples of such changes are modifications in the format of the library information described in this package, modifications to calling sequences, or to the way data is represented.

S "xxxxxxxxxxxxxxxx"

This line contains information regarding types declared in packages Standard as stored in Gnatvsn.Standard_Version. The purpose of this information is to ensure that all units in a program are compiled with a consistent set of options. This is critical on systems where, for example, the size of Integer can be set by command line switches.

M type [priority]

This line is present only for a unit that can be a main program. type is either P for a parameterless procedure or F for a function returning a value of integral type. The latter is for writing a main program that returns an exit status. priority is present only if there was a valid pragma Priority in the corresponding unit to set the main task priority. It is an unsigned decimal integer.

F x

This line is present if a pragma Float_Representation or Long_Float is used to specify other than the default floating-point format. This option applies only to implementations of GNAT for the Digital Alpha Systems. The character x is 'I' for IEEE_Float, 'G' for VAX_Float with Long_Float using G_Float, and 'D' for VAX_Float for Long_Float with D_Float.

P L=x Q=x T=x

This line is present if the unit uses tasking directly or indirectly, and has one or more valid xxx_Policy pragmas that apply to the unit. The arguments are as follows

L=x (locking policy)

This is present if a valid Locking_Policy pragma applies to the unit. The single character indicates the policy in effect (e.g. `C' for Ceiling_Locking).

Q=x (queuing policy)

This is present if a valid Queuing_Policy pragma applies to the unit. The single character indicates the policy in effect (e.g. `P' for Priority_Queuing).

T=x (task_dispatching policy)

This is present if a valid Task_Dispatching_Policy pragma applies to the unit. The single character indicates the policy in effect (e.g. `F' for FIFO_Within_Priorities).

Following these header lines is a set of information lines, one per compilation unit. Each line lists a unit in the object file corresponding to this ALI file. In particular, when a package body or subprogram body is compiled there will be two such lines, one for the spec and one for the body, with the entry for the body appearing first. This is the only case in which a single ALI file contains more than one unit. Note that subunits do not count as compilation units for this purpose, and generate no library information, because they are inlined. The lines for each compilation unit have the following form:

U unit-name source-name version [attributes]

This line identifies the unit to which this section of the library information file applies. unit-name is the unit name in internal format, as described in package Uname, and source-file is the name of the source file containing the unit.

version is the version, given by eight hexadecimal characters with lowercase letters. This value is a hash code that includes contributions from the time stamps of this unit and all the units on which it semantically depends.

The optional attributes are a series of two-letter codes indicating information about the unit. They indicate the nature of the unit and they summarize information provided by categorization pragmas.

EB
Unit has pragma Elaborate_Body.
NE
Unit has no elaboration routine. All subprogram specs are in this category, as are subprogram bodies if access-before-elaboration checks are being generated. Package bodies and specs may or may not have NE set, depending on whether or not elaboration code is required.
PK
Unit is a package.
PU
Unit has pragma Pure.
PR
Unit has pragma Preelaborate.
RC
Unit has pragma Remote_Call_Interface.
RT
Unit has pragma Remote_Types.
SP
Unit has pragma Shared_Passive.
SU
Unit is a subprogram.

The attributes may appear in any order, separated by spaces. The next set of lines in the ALI file have the following form:

W unit-name [source-name lib-name [E] [EA] [ED]]

One of these lines is present for each unit mentioned in an explicit with clause in the current unit. unit-name is the unit name in internal format. source-name is the file name of the file that must be compiled to compile that unit (usually the file for the body, except for packages that have no body). lib-name is the file name of the library information file that contains the results of compiling the unit. The E and EA parameters are present if pragma Elaborate or pragma Elaborate_All, respectively, apply to this unit. ED is used to indicate that the compiler has determined that a pragma Elaborate_All for this unit would be desirable. For details on the use of the ED parameter see See section Elaboration Order Handling in GNAT.

Following the unit information is an optional series of lines that indicate the usage of pragma Linker_Options. For each appearance of pragma Linker_Options in any of the units for which unit lines are present, a line of the form

L string

appears. string is the string from the pragma enclosed in quotes. Within the quotes, the following can occur:

For further details, see Stringt.Write_String_Table_Entry in the file `stringt.ads'. Note that wide characters of the form {hhhh} cannot be produced, because pragma Linker_Option accepts only String, not Wide_String.

Finally, the rest of the ALI file contains a series of lines that indicate the source files on which the compiled units depend. This is used by the binder for consistency checking and looks like:

D source-name time-stamp [comments]

where comments, if present, must be separated from the time stamp by at least one blank. Currently this field is unused.

Blank lines are ignored when the library information is read, and separate sections of the file are separated by blank lines to help readability. Extra blanks between fields are also ignored.

Representation of Time Stamps

All compiled units are marked with a time stamp, which is derived from the source file. The binder uses these time stamps to ensure consistency of the set of units that constitutes a single program. Time stamps are fourteen-character strings of the form YYYYMMDDHHMMSS. The fields have the following meaning:

YYYY
year (4 digits)
MM
month (2 digits 01-12)
DD
day (2 digits 01-31)
HH
hour (2 digits 00-23)
MM
minutes (2 digits 00-59)
SS
seconds (2 digits 00-59)

Time stamps may be compared lexicographically (in other words, the order of Ada comparison operations on strings) to determine which is later or earlier. However, in normal mode, only equality comparisons have any effect on the semantics of the library. Later/earlier comparisons are used only for determining the most informative error messages to be issued by the binder.

The time stamp is the actual stamp stored with the file without any adjustment resulting from time zone comparisons. This avoids problems in using libraries across networks with clients spread across multiple time zones, but it means that the time stamp might differ from that displayed in a directory listing. For example, in UNIX systems, file time stamps are stored in Greenwich Mean Time (GMT), but the ls command displays local times.

Binding an Ada Program

When using languages such as C and C++, once the source files have been compiled the only remaining step in building an executable program is linking the object modules together. This means that it is possible to link an inconsistent version of a program, in which two units have included different versions of the same header.

The rules of Ada do not permit such an inconsistent program to be built. For example, if two clients have different versions of the same package, it is illegal to build a program containing these two clients. These rules are enforced by the GNAT binder, which also determines an elaboration order consistent with the Ada rules.

The GNAT binder is run after all the object files for a program have been created. It is given the name of the main program unit, and from this it determines the set of units required by the program, by reading the corresponding ALI files. It generates error messages if the program is inconsistent or if no valid order of elaboration exists.

If no errors are detected, the binder produces a main program, in C, that contains calls to the elaboration procedures of those compilation unit that require them, followed by a call to the main program. This C program is compiled using the C compiler to generate the object file for the main program. The name of the C file is b_xxx.c where xxx is the name of the main program unit. (In future versions of GNAT, this main program may be created directly in Ada).

Finally, the linker is used to build the resulting executable program, using the object from the main program from the bind step as well as the object files for the Ada units of the program.

Mixed Language Programming

There are two ways to build a program that contains some Ada files and some other language files (depending on whether the main program is in Ada or not). If the main program is in Ada, one proceeds as follows:

  1. Compile the Ada units to produce a set of object files and ALI files.
  2. Compile the other language files to generate object files.
  3. Run the Ada binder on the Ada main program.
  4. Compile the Ada main program.
  5. Link the Ada main program, the Ada objects and the other language objects.

If the main program is in some language other than Ada, you must use a special option of the binder to generate callable routines to initialize and finalize the Ada units (see section Binding for Non-Ada Main Programs). Calls to the initialization and finalization routines must be inserted in the main program, or some other appropriate point in the code. The call to initialize the Ada units must occur before the first Ada subprogram is called, and the call to finalize the Ada units must occur after the last Ada subprogram returns. You use the same procedure for building the program as described previously. In this case, however, the binder places the initialization and finalization subprograms into file `b_xxx.c' instead of the main program.

GNAT follows standard calling sequence conventions and will thus interface to any other language that also follows these conventions. The following Convention identifiers are recognized by GNAT:

Comparison between GNAT and C/C++ Compilation Models

The GNAT model of compilation is close to the C and C++ models. You can think of Ada specs as corresponding to header files in C. As in C, you don't need to compile specs; they are compiled when they are used. The Ada with is similar in effect to the #include of a C header.

One notable difference is that, in Ada, you may compile specs separately to check them for semantic and syntactic accuracy. This is not always possible with C headers because they are fragments of programs that have less specific syntactic or semantic rules.

The other major difference is the requirement for running the binder, which performs two important functions. First, it checks for consistency. In C or C++, the only defense against assembling inconsistent programs lies outside the compiler, in a make file, for example. The binder satisfies the Ada requirement that it be impossible to construct an inconsistent program when the compiler is used in normal mode.

The other important function of the binder is to deal with elaboration issues. There are also elaboration issues in C++ that are handled automatically. This automatic handling has the advantage of being simpler to use, but the C++ programmer has no control over elaboration. Where gnatbind might complain there was no valid order of elaboration, a C++ compiler would simply construct a program that malfunctioned at run time.

Comparison between GNAT and Conventional Ada Library Models

This section is intended to be useful to Ada programmers who have previously used an Ada compiler implementing the traditional Ada library model, as described in the Ada 95 Language Reference Manual. If you have not used such a system, please go on to the next section.

In GNAT, there is no library in the normal sense. Instead, the set of source files themselves acts as the library. Compiling Ada programs does not generate any centralized information, but rather an object file and a ALI file, which are of interest only to the binder and linker. In a traditional system, the compiler reads information not only from the source file being compiled, but also from the centralized library. This means that the effect of a compilation depends on what has been previously compiled. In particular:

In GNAT, compiling one unit never affects the compilation of any other units because the compiler reads only source files. Only changes to source files can affect the results of a compilation. In particular:

The most important result of these differences is that order of compilation is never significant in GNAT. There is no situation in which one is required to do one compilation before another. What shows up as order of compilation requirements in the traditional Ada library becomes, in GNAT, simple source dependencies; in other words, there is only a set of rules saying what source files must be present when a file is compiled.

Compiling Using gcc

This chapter discusses how to compile Ada programs using the gcc command. It also describes the set of switches that can be used to control the behavior of the compiler.

Compiling Programs

The first step in creating an executable program is to compile the units of the program using the gcc command. You must compile the following files:

You need not compile the following files

because they are compiled as part of compiling related units. GNAT package specs when the corresponding body is compiled, and subunits when the parent is compiled. If you attempt to compile any of these files, you will get one of the following error messages (where fff is the name of the file you compiled):

No code generated for file fff (package spec)
No code generated for file fff (subunit)

The basic command for compiling a file containing an Ada unit is

$ gcc -c [switches] `file name'

where file name is the name of the Ada file (usually having an extension `.ads' for a spec or `.adb' for a body). You specify the -c switch to tell gcc to compile, but not link, the file. The result of a successful compilation is an object file, which has the same name as the source file but an extension of `.o' and an Ada Library Information (ALI) file, which also has the same name as the source file, but with `.ali' as the extension. GNAT creates these two output files in the current directory, but you may specify a source file in any directory using an absolute or relative path specification containing the directory information.

gcc is actually a driver program that looks at the extensions of the file arguments and loads the appropriate compiler. For example, the GNU C compiler is `cc1', and the Ada compiler is `gnat1'. These programs are in directories known to the driver program (in some configurations via environment variables you set), but need not be in your path. The gcc driver also calls the assembler and any other utilities needed to complete the generation of the required object files.

It is possible to supply several file names on the same gcc command. This causes gcc to call the appropriate compiler for each file. For example, the following command lists three separate files to be compiled:

$ gcc -c x.adb y.adb z.c

calls gnat1 (the Ada compiler) twice to compile `x.adb' and `y.adb', and cc1 (the C compiler) once to compile `z.c'. The compiler generates three object files `x.o', `y.o' and `z.o' and the two ALI files `x.ali' and `y.ali' from the Ada compilations. Any switches apply to all the files listed, except for -gnatx switches, which apply only to Ada compilations.

Switches for gcc

The gcc command accepts numerous switches to control the compilation process. These switches are fully described in this section.

-b target
Compile your program to run on target, which is the name of a system configuration. You must have a GNAT cross-compiler built if target is not the same as your host system.
-Bdir
Load compiler executables (for example, gnat1, the Ada compiler) from dir instead of the default location. Only use this switch when multiple versions of the GNAT compiler are available. See the gcc manual page for further details. You would normally use the -b or -V switch instead.
-c
Compile. Always use this switch when compiling Ada programs. Note that you may not use gcc without a -c switch to compile and link in one step. This is because the binder must be run, and currently gcc cannot be used to run the GNAT binder.
-g
Generate debugging information. This information is stored in the object file and copied from there to the final executable file by the linker, where it can be read by the debugger. You must use the -g switch if you plan on using the debugger.
-Idir
Direct GNAT to search the dir directory for source files needed by the current compilation (see section Search Paths and the Run-Time Library (RTL)).
-I-
Do not look for source files in the directory containing the source file named in the command line (see section Search Paths and the Run-Time Library (RTL)).
-o file
This switch is used in gcc to redirect the generated object file and its associated ALI file. Beware of this switch with GNAT, because it may cause the object file and ALI file to have different names which in turn may confuse the binder and the linker.
-O[n]
n controls the optimization level.
n = 0
No optimization, the default setting if no -O appears
n = 1
Normal optimization, the default if you specify -O without an operand.
n = 2
Extensive optimization
n = 3
Extensive optimization with automatic inlining. This applies only to inlining within a unit. For details on control of inter-unit inlining see See section Subprogram Inlining Control.
-S
Used in place of -c to cause the assembler source file to be generated, using `.s' as the extension, instead of the object file. This may be useful if you need to examine the generated assembly code.
-v
Show commands generated by the gcc driver. Normally used only for debugging purposes or if you need to be sure what version of the compiler you are executing.
-V ver
Execute ver version of the compiler. This is the gcc version, not the GNAT version.
-Wuninitialized
Generate warnings for uninitialized variables. You must also specify the -O switch (in other words, This switch works only if optimization is turned on).
-gnata
Assertions enabled. Pragma Assert and pragma Debug to be activated.
-gnatb
Generate brief messages to stderr even if verbose mode set.
-gnatc
Check syntax and semantics only (no code generation attempted).
-gnate
Error messages generated immediately, not saved up till end.
-gnatE
Full dynamic elaboration checks.
-gnatf
Full errors. Multiple errors per line, all undefined references.
-gnatg
GNAT style checks enabled.
-gnatic
Identifier char set (c=1/2/3/4/8/p/f/n/w).
-gnath
Output usage information. The output is written to stdout.
-gnatkn
Limit file names to n (1-999) characters (k = krunch).
-gnatl
Output full source listing with embedded error messages.
-gnatmn
Limit number of detected errors to n (1-999).
-gnatn
Activate inlining across unit boundaries for subprograms for which pragma inline is specified.
-gnatN
Activate inlining across unit boundaries for all subprograms (not just those for which pragma inline is specified. This is equivalent to using -gnatn and adding a pragma inline for every subprogram in the program.
-fno-inline
Suppresses all inlining, even if other optimization or inlining switches are set.
-gnato
Enable other checks, not normally enabled by default, including numeric overflow checking, and access before elaboration checks.
-gnatp
Suppress all checks.
-gnatq
Don't quit; try semantics, even if parse errors.
-gnatr
Reference manual column layout required.
-gnats
Syntax check only.
-gnatt
Tree output file to be generated.
-gnatu
List units for this compilation.
-gnatv
Verbose mode. Full error output with source lines to stdout.
-gnatwm
Warning mode (m=s,e,l for suppress, treat as error, elaboration warnings).
-gnatWe
Wide character encoding method (e=n/h/u/s/e/8).
-gnatx
Suppress generation of cross-reference information.
-gnatzm
Distribution stub generation and compilation (m=r/c for receiver/caller stubs).
-gnat83
Enforce Ada 83 restrictions.
-gnat95
Standard Ada 95 mode

You may combine a sequence of GNAT switches into a single switch. For example, the combined switch

-gnatcfi3

is equivalent to specifying the following sequence of switches:

-gnatc -gnatf -gnati3

Error Message Control

The standard default format for error messages is called "brief format." Brief format messages are written to stdout (the standard output file) and have the following form:

e.adb:3:04: Incorrect spelling of keyword "function"
e.adb:4:20: ";" should be "is"

The first integer after the file name is the line number in the file, and the second integer is the column number within the line. emacs can parse the error messages and point to the referenced character. The following switches provide control over the error message format:

-gnatv
The v stands for verbose. The effect of this setting is to write long-format error messages to stdout. The same program compiled with the -gnatv switch would generate:
3. funcion X (Q : Integer)
   |
>>> Incorrect spelling of keyword "function"
4. return Integer;
                 |
>>> ";" should be "is"
The vertical bar indicates the location of the error, and the `>>>' prefix can be used to search for error messages. When this switch is used the only source lines output are those with errors.
-gnatl
The l stands for list. This switch causes a full listing of the file to be generated. The output might look as follows:
 1. procedure E is
 2.    V : Integer;
 3.    function X (Q : Integer)
       |
    >>> Incorrect spelling of keyword "function"
 4.     return Integer;
                      |
    >>> ";" should be "is"
 5.    begin
 6.       return Q + Q;
 7.    end;
 8. begin
 9.    V := X + X;
10.end E;
When you specify the -gnatv or -gnatl switches and standard output is redirected, a brief summary is written to stderr (standard error) giving the number of error messages and warning messages generated.
-gnatb
The b stands for brief. This switch causes GNAT to generate the brief format error messages to stdout as well as the verbose format message or full listing.
-gnatmn
The m stands for maximum. n is a decimal integer in the range of 1 to 999 and limits the number of error messages to be generated. For example, using -gnatm2 might yield
e.adb:3:04: Incorrect spelling of keyword "function"
e.adb:5:35: missing ".."
fatal error: maximum errors reached
compilation abandoned
-gnatf
The f stands for full. Normally, the compiler suppresses error messages that are likely to be redundant. This switch causes all error messages to be generated. In particular, in the case of references to undefined variables. If a given variable is referenced several times, the normal format of messages is
e.adb:7:07: "V" is undefined (more references follow)
where the parenthetical comment warns that there are additional references to the variable V. Compiling the same program with the -gnatf switch yields
e.adb:7:07: "V" is undefined
e.adb:8:07: "V" is undefined
e.adb:8:12: "V" is undefined
e.adb:8:16: "V" is undefined
e.adb:9:07: "V" is undefined
e.adb:9:12: "V" is undefined
-gnatq
The q stands for quit (really "don't quit"). In normal operation mode, the compiler first parses the program and determines if there are any syntax errors. If there are, appropriate error messages are generated and compilation is immediately terminated. This switch tells GNAT to continue with semantic analysis even if syntax errors have been found. This may enable the detection of more errors in a single run. On the other hand, the semantic analyzer is more likely to encounter some internal fatal error when given a syntactically invalid tree.
-gnate
Normally, the compiler saves up error messages and generates them at the end of compilation in proper sequence. This switch (the `e' stands for error) causes error messages to be generated as soon as they are detected. The use of -gnate usually causes error messages to be generated out of sequence. Use this switch when the compiler terminates abnormally because of an internal error. In this case, the error messages may be lost. Sometimes blowups are the result of mishandled error messages, so you may want to run with the -gnate switch to determine whether any error messages were generated before the crash (see section GNAT Abnormal Termination).

In addition to error messages, which correspond to illegalities as defined in the Ada 95 Reference Manual, the compiler detects two kinds of warning situations.

First, the compiler considers some constructs suspicious and generates a warning message to alert you to a possible error. Second, if the compiler detects a situation that is sure to raise an exception at run time, it generates a warning message. The following shows an example of warning messages:

e.adb:4:24: warning: creation of object may raise Storage_Error
e.adb:10:17: warning: static value out of range
e.adb:10:17: warning: "Constraint_Error" will be raised at run time

GNAT considers a large number of situations as appropriate for the generation of warning messages. As always, warnings are not definite indications of errors. For example, if you do an out-of-range assignment with the deliberate intention of raising a Constraint_Error exception, then the warning that may be issued does not indicate an error. Some of the situations for which GNAT issues warnings (at least some of the time) are:

Four switches are available to control the handling of warning messages:

-gnatwu (warn on unused entities)
This switch causes warning messages to be generated for entities that are defined but not referenced, and for units that are with'ed and not referenced. In the case of packages, a warning is also generated if no entities in the package are referenced. This means that if the package is referenced but the only references are in use clauses or renames declarations, a warning is still generated. A warning is also generated for a generic package that is with'ed but never instantiated.
-gnatwe (treat warnings as errors)
This switch causes warning messages to be treated as errors. The warning string still appears, but the warning messages are counted as errors, and prevent the generation of an object file.
-gnatws (suppress warnings)
This switch completely suppresses the output of all warning messages.
-gnatwl (warn on elaboration order errors)
This switch causes the generation of additional warning messages relating to elaboration issues. See the separate chapter on elaboration order handling for full details of the use of this switch.
-gnatx
Normally the compiler generates full cross-referencing information in the `ALI' file. This information is used by a number of tools, including gnatfind and gnatxref. The -gnatx switch suppresses this information. This saves some space and may slightly speed up compilation, but means that these tools cannot be used.

Debugging and Assertion Control

-gnata
The pragmas Assert and Debug normally have no effect and are ignored. This switch, where `a' stands for assert, causes Assert and Debug pragmas to be activated. The pragmas have the form:
pragma Assert (Boolean-expression [, static-string-expression])
pragma Debug (procedure call)
The Assert pragma causes Boolean-expression to be tested. If the result is True, the pragma has no effect (other than possible side effects from evaluating the expression). If the result is False, the exception Assert_Error declared in the package System.Assertions is raised (passing static-string-expression, if present, as the message associated with the exception). If no string expression is given the default is a string giving the file name and line number of the pragma. The Debug pragma causes procedure to be called. Note that pragma Debug may appear within a declaration sequence, allowing debugging procedures to be called between declarations.

Run-time Checks

If you compile with the default options, GNAT will insert many run-time checks into the compiled code, including code that performs range checking against constraints, but not arithmetic overflow checking for integer operations (including division by zero) or checks for access before elaboration on subprogram calls. All other run-time checks, as required by the Ada 95 Reference Manual, are generated by default. The following gcc switches refine this default behavior:

-gnatp
Suppress all run-time checks as though pragma Suppress (all_checks) had been present in the source. Use this switch to improve the performance of the code at the expense of safety in the presence of invalid data or program bugs.
-gnato
Enables overflow checking for integer operations. This causes GNAT to generate slower and larger executable programs by adding code to check for both overflow and division by zero (resulting in raising Constraint_Error as required by Ada semantics). Note that the -gnato switch does not affect the code generated for any floating-point operations; it applies only to integer operations. For floating-point, GNAT has the Machine_Overflows attribute set to False and the normal mode of operation is to generate IEEE NaN and infinite values on overflow or invalid operations (such as dividing 0.0 by 0.0).
-gnatE
Enables dynamic checks for access-before-elaboration on subprogram calls and generic instantiations. For full details of the effect and use of this switch, See section Compiling Using gcc.

The setting of these switches only controls the default setting of the checks. You may modify them using either Suppress (to remove checks) or Unsuppress (to add back suppressed checks) pragmas in the program source.

Using gcc for Syntax Checking

-gnats
The s stands for syntax. Run GNAT in syntax checking only mode. For example, the command
$ gcc -c -gnats x.adb
compiles file `x.adb' in syntax-check-only mode. You can check a series of files in a single command, and can use wild cards to specify such a group of files. Note that you must specify the -c (compile only) flag in addition to the -gnats flag. You may use other switches in conjunction with -gnats. In particular, -gnatl and -gnatv are useful to control the format of any generated error messages. The output is simply the error messages, if any. No object file or ALI file is generated by a syntax-only compilation. Also, no units other than the one specified are accessed. For example, if a unit X with's a unit Y, compiling unit X in syntax check only mode does not access the source file containing unit Y. Normally, GNAT allows only a single unit in a source file. However, this restriction does not apply in syntax-check-only mode, and it is possible to check a file containing multiple compilation units concatenated together. This is primarily used by the gnatchop utility (see section Renaming Files Using gnatchop).

Using gcc for Semantic Checking

-gnatc
The c stands for check. Causes the compiler to operate in semantic check mode, with full checking for all illegalities specified in the Ada 95 Reference Manual, but without generation of any source code (no object or ALI file generated). Because dependent files must be accessed, you must follow the GNAT semantic restrictions on file structuring to operate in this mode: The output consists of error messages as appropriate. No object file or ALI file is generated. The checking corresponds exactly to the notion of legality in the Ada 95 Reference Manual. Any unit can be compiled in semantics-checking-only mode, including units that would not normally be compiled ( subunits, and specifications where a separate body is present).

Compiling Ada 83 Programs

-gnat83
Although GNAT is primarily an Ada 95 compiler, it accepts this switch to specify that an Ada 83 program is to be compiled in Ada83 mode. If you specify this switch, GNAT rejects most Ada 95 extensions and applies Ada 83 semantics where this can be done easily. It is not possible to guarantee this switch does a perfect job; for example, some subtle tests, such as are found in earlier ACVC tests (that have been removed from the ACVC suite for Ada 95), may not compile correctly. However for most purposes, using this switch should help to ensure that programs that compile correctly under the -gnat83 switch can be ported easily to an Ada 83 compiler. This is the main use of the switch. With few exceptions (most notably the need to use <> on unconstrained generic formal parameters, the use of the new Ada 95 keywords, and the use of packages with optional bodies), it is not necessary to use the -gnat83 switch when compiling Ada 83 programs, because, with rare exceptions, Ada 95 is upwardly compatible with Ada 83. This means that a correct Ada 83 program is usually also a correct Ada 95 program.
-gnat95
This switch specifies normal Ada 95 mode, and cancels the effect of any previously given -gnat83 switch.

Style Checking

-gnatr
Normally, GNAT permits any source layout consistent with the Ada 95 reference manual requirements. This switch (`r' is for "reference manual") enforces the layout conventions suggested by the examples and syntax rules of the Ada 95 Language Reference Manual. For example, an else must line up with an if and code in the then and else parts must be indented. The compiler treats violations of the layout rules as syntax errors if you specify this switch.
-gnatg
Enforces a set of style conventions that correspond to the style used in the GNAT source code. All compiler units are always compiled with the -gnatg switch specified. You can find the full documentation for the style conventions imposed by -gnatg in the body of the package Style in the compiler sources (in the file `style.adb'). You should not normally use the -gnatg switch. However, you must use -gnatg for compiling any language-defined unit, or for adding children to any language-defined unit other than Standard.

Character Set Control

-gnatic
Normally GNAT recognizes the Latin-1 character set in source program identifiers, as described in the Ada 95 Reference Manual. This switch causes GNAT to recognize alternate character sets in identifiers. c is a single character indicating the character set, as follows:
1
Latin-1 identifiers
2
Latin-2 letters allowed in identifiers
3
Latin-3 letters allowed in identifiers
4
Latin-4 letters allowed in identifiers
p
IBM PC letters (code page 437) allowed in identifiers
8
IBM PC letters (code page 850) allowed in identifiers
f
Full upper-half codes allowed in identifiers
n
No upper-half codes allowed in identifiers
w
Wide-character codes allowed in identifiers
See section Foreign Language Representation, for full details on the implementation of these character sets.
-gnatWe
Specify the method of encoding for wide characters. e is one of the following:
h
Hex encoding (brackets coding also recognized)
u
Upper half encoding (brackets encoding also recognized)
s
Shift/JIS encoding (brackets encoding also recognized)
e
EUC encoding (brackets encoding also recognized)
8
UTF-8 encoding (brackets encoding also recognized)
b
Brackets encoding only (default value)
For full details on the these encoding methods see See section Wide Character Encodings. Note that brackets coding is always accepted, even if one of the other options is specified, so for example -gnatW8 specifies that both brackets and UTF-8 encodings will be recognized. The units that are with'ed directly or indirectly will be scanned using the specified representation scheme, and so if one of the non-brackets scheme is used, it must be used consistently throughout the program. However, since brackets encoding is always recognized, it may be conveniently used in standard libraries, allowing these libraries to be used with any of the available coding schemes. scheme. If no -gnatW? parameter is present, then the default representation is Brackets encoding only. Note that the wide character representation that is specified (explicitly or by default) for the main program also acts as the default encoding used for Wide_Text_IO files if not specifically overridden by a WCEM form parameter.

File Naming Control

-gnatkn
Activates file name "krunching". n, a decimal integer in the range 1-999, indicates the maximum allowable length of a file name (not including the `.ads' or `.adb' extension). The default is not to enable file name krunching. For the source file naming rules, See section File Naming Rules.

Subprogram Inlining Control

-gnatn
The n here is intended to suggest the first syllable of the word "inline". GNAT recognizes and processes Inline pragmas. However, for the inlining to actually occur, optimization must be enabled. To enable inlining across unit boundaries, this is, inlining a call in one unit of a subprogram declared in a with'ed unit, you must also specify this switch. In the absence of this switch, GNAT does not attempt inlining across units and does not need to access the bodies of subprograms for which pragma Inline is specified if they are not in the current unit. If you specify this switch the compiler will access these bodies, creating an extra source dependency for the resulting object file, and where possible, the call will be inlined. For further details on when inlining is possible see See section Inlining of Subprograms.
-gnatN
This switch enforces a more extreme form of inlining across unit boundaries. It causes the compiler to proceed as though the normal (pragma) inlining switch was set, and to assume that there is a pragma Inline for every subprogram referenced by the compiled unit.

Auxiliary Output Control

-gnatt
Cause GNAT to write the internal tree for a unit to a file (with the extension `.atb' for a body or `.ats' for a spec). This is not normally required, but is used by separate analysis tools. Typically these tools do the necessary compilations automatically, so you should never have to specify this switch in normal operation.
-gnatu
Print a list of units required by this compilation on stdout. The listing includes all units on which the unit being compiled depends either directly or indirectly.

Debugging Control

-gnatdx
Activate internal debugging switches. x is a letter or digit, or string of letters or digits, which specifies the type of debugging outputs desired. Normally these are used only for internal development or system debugging purposes. You can find full documentation for these switches in the body of the Debug unit in the compiler source file `debug.adb'. One particularly useful switch is -gnatdg, which produces a listing of the expanded code in Ada source form. For example, all tasking constructs are reduced to appropriate run-time library calls. The syntax of this listing is close to legal Ada with the following additions:
new xxx [storage_pool = yyy]
Shows the storage pool being used for an allocator.
at end procedure-name;
Shows the finalization (cleanup) procedure for a scope.
(if expr then expr else expr)
Conditional expression equivalent to the x?y:z construction in C.
target^(source)
A conversion with floating-point truncation instead of rounding.
target?(source)
A conversion that bypasses normal Ada semantic checking. In particular enumeration types and fixed-point types are treated simply as integers.
target?^(source)
Combines the above two cases.
x #/ y
x #mod y
x #* y
x #rem y
A division or multiplication of fixed-point values which are treated as integers without any kind of scaling.
free expr [storage_pool = xxx]
Shows the storage pool associated with a free statement.
freeze typename [actions]
Shows the point at which typename is frozen, with possible associated actions to be performed at the freeze point.
reference itype
Reference (and hence definition) to internal type itype.
function-name! (arg, arg, arg)
Intrinsic function call.
labelname : label
Declaration of label labelname.
expr && expr && expr ... && expr
A multiple concatenation (same effect as expr & expr & expr, but handled more efficiently).
[constraint_error]
Raise the Constraint_Error exception.
expression'reference
A pointer to the result of evaluating expression.
target-type!(source-expression)
An unchecked conversion of source-expression to target-type.
[numerator/denominator]
Used to represent internal real literals (that) have no exact representation in base 2-16 (for example, the result of compile time evaluation of the expression 1.0/27.0).

Search Paths and the Run-Time Library (RTL)

With the GNAT source-based library system, the compiler must be able to find source files for units that are needed by the unit being compiled. Search paths are used to guide this process.

The compiler compiles one source file whose name must be given explicitly on the command line. In other words, no searching is done for this file. To find all other source files that are needed (the most common being the specs of units), the compiler examines the following directories, in the following order:

  1. The directory containing the source file of the main unit being compiled (the file name on the command line).
  2. Each directory named by an -I switch given on the gcc command line, in the order given.
  3. Each of the directories listed in the value of the ADA_INCLUDE_PATH environment variable. Construct this value exactly as the PATH environment variable: a list of directory names separated by colons.
  4. The default location for the GNAT Run Time Library (RTL) source files. This is determined at the time GNAT is built and installed on your system.

Specifying the switch -I- inhibits the use of the directory containing the source file named in the command line. You can still have this directory on your search path, but in this case it must be explicitly requested with a -I switch.

The compiler outputs its object files and ALI files in the current working directory. Caution: The object file can be redirected with the -o switch; however, gcc and gnat1 have not been coordinated on this so the ALI file will not go to the right place. Therefore, you should avoid using the -o switch.

The packages Ada, System, and Interfaces and their children make up the GNAT RTL, together with the simple System.IO package used in the "Hello World" example. The sources for these units are needed by the compiler and are kept together in one directory. Not all of the bodies are needed, but all of the sources are kept together anyway. In a normal installation, you need not specify these directory names when compiling or binding. Either the environment variables or the built-in defaults cause these files to be found.

In addition to the language-defined hierarchies (System, Ada and Interfaces), the GNAT distribution provides a fourth hierarchy, consisting of child units of GNAT. This is a collection of generally useful routines. See the GNAT Reference Manual for further details.

Besides simplifying access to the RTL, a major use of search paths is in compiling sources from multiple directories. This can make development environments much more flexible.

Order of Compilation Issues

If, in our earlier example, there was a spec for the hello procedure, it would be contained in the file `hello.ads'; yet this file would not have to be explicitly compiled. This is the result of the model we chose to implement library management. Some of the consequences of this model are as follows:

Examples

The following are some typical Ada compilation command line examples:

$ gcc -c xyz.adb
Compile body in file `xyz.adb' with all default options.
$ gcc -c -O2 -gnata xyz-def.adb
Compile the child unit package in file `xyz-def.adb' with extensive optimizations, and pragma Assert/Debug statements enabled.
$ gcc -c -gnatc abc-def.adb
Compile the subunit in file `abc-def.adb' in semantic-checking-only mode.

Binding Using gnatbind

This chapter describes the GNAT binder, gnatbind, which is used to bind compiled GNAT objects. The gnatbind program performs four separate functions:

  1. Checks that a program is consistent, in accordance with the rules in Chapter 10 of the Ada 95 Reference Manual. In particular, error messages are generated if a program uses inconsistent versions of a given unit.
  2. Checks that an acceptable order of elaboration exists for the program and issues an error message if it cannot find an order of elaboration that satisfies the rules in Chapter 10 of the Ada 95 Language Manual.
  3. Generates a main program incorporating the given elaboration order. This program is a small C source file that must be subsequently compiled using the C compiler. The two most important functions of this program are to call the elaboration routines of units in an appropriate order and to call the main program.
  4. Determines the set of object files required by the given main program. This information is output in the forms of comments in the generated C program, to be read by the gnatlink utility used to link the Ada application.

Running gnatbind

The form of the gnatbind command is

$ gnatbind [switches] mainprog.ali [switches]

where mainprog.adb is the Ada file containing the main program unit body. If no switches are specified, gnatbind constructs a C file whose name is `b_mainprog.c'. For example, if given the parameter `hello.ali', for a main program contained in file `hello.adb', the binder output file would be `b_hello.c'.

When doing consistency checking, the binder takes any source files it can locate into consideration. For example, if the binder determines that the given main program requires the package Pack, whose ALI file is `pack.ali' and whose corresponding source spec file is `pack.ads', it attempts to locate the source file `pack.ads' (using the same search path conventions as previously described for the gcc command). If it can locate this source file, it checks that the time stamps or source checksums of the source and its references to in ALI files match. In other words, any ALI files that mentions this spec must have resulted from compiling this version of the source file (or in the case where the source checksums match, a version close enough that the difference does not matter).

The effect of this consistency checking, which includes source files, is that the binder ensures that the program is consistent with the latest version of the source files that can be located at bind time. Editing a source file without compiling files that depend on the source file cause error messages to be generated by the binder.

For example, suppose you have a main program `hello.adb' and a package P, from file `p.ads' and you perform the following steps:

  1. Enter gcc -c hello.adb to compile the main program.
  2. Enter gcc -c p.ads to compile package P.
  3. Edit file `p.ads'.
  4. Enter gnatbind hello.ali.

At this point, the file `p.ali' contains an out-of-date time stamp because the file `p.ads' has been edited. The attempt at binding fails, and the binder generates the following error messages:

error: "hello.adb" must be recompiled ("p.ads" has been modified)
error: "p.ads" has been modified and must be recompiled

Now both files must be recompiled as indicated, and then the bind can succeed, generating a main program. You need not normally be concerned with the contents of this file, but it is similar to the following:


extern int gnat_argc;
extern char **gnat_argv;
extern char **gnat_envp;
extern int gnat_exit_status;
void adafinal ();
void adainit ()
{
   __gnat_set_globals (
      -1,    /* Main_Priority              */
      -1,    /* Time_Slice_Value           */
      ' ',   /* Locking_Policy             */
      ' ',   /* Queuing_Policy             */
      ' ',   /* Tasking_Dispatching_Policy */
      adafinal);
   system___elabs ();
/* system__standard_library___elabs (); */
/* system__task_specific_data___elabs (); */
/* system__tasking_soft_links___elabs (); */
   system__tasking_soft_links___elabb ();
/* system__task_specific_data___elabb (); */
/* system__standard_library___elabb (); */
/* m___elabb (); */
}
void adafinal () {
}
int main (argc, argv, envp)
    int argc;
    char **argv;
    char **envp;
{
   gnat_argc = argc;
   gnat_argv = argv;
   gnat_envp = envp;

   __gnat_initialize();
   adainit();

   _ada_m ();

   adafinal();
   __gnat_finalize();
   exit (gnat_exit_status);
}
unsigned mB = 0x2B0EB17F;
unsigned system__standard_libraryB = 0x0122ED49;
unsigned system__standard_libraryS = 0x79B018CE;
unsigned systemS = 0x08FBDA7E;
unsigned system__task_specific_dataB = 0x6CC7367B;
unsigned system__task_specific_dataS = 0x47178527;
unsigned system__tasking_soft_linksB = 0x5A75A73C;
unsigned system__tasking_soft_linksS = 0x3012AFCB;
/* BEGIN Object file/option list
./system.o
./s-tasoli.o
./s-taspda.o
./s-stalib.o
./m.o
   END Object file/option list */

The call to __gnat_set_globals establishes program parameters, including the priority of the main task, and parameters for tasking control. It also passes the address of the finalization routine so that it can be called at the end of program execution.

Next there is code to save the argc and argv values for later access by the Ada.Command_Line package. The variable gnat_exit_status saves the exit status set by calls to Ada.Command_Line.Set_Exit_Status and is used to return an exit status to the system.

The call to __gnat_initialize and the corresponding call at the end of execution to __gnat_finalize allow any specialized initialization and finalization code to be hooked in. The default versions of these routines do nothing.

The calls to xxx___elabb and xxx___elabs perform necessary elaboration of the bodies and specs respectively of units in the program. These calls are commented out if the unit in question has no elaboration code.

The call to m is the call to the main program.

The list of unsigned constants gives the version number information. Version numbers are computed by combining time stamps of a unit and all units on which it depends. These values are used for implementation of the Version and Body_Version attributes.

Finally, a set of comments gives the full names of all the object files that must be linked to provide the Ada component of the program. As seen in the previous example, this list includes the files explicitly supplied and referenced by the user as well as implicitly referenced run-time unit files. The latter are omitted if the corresponding units reside in shared libraries. The directory names for the run-time units depend on the system configuration.

Consistency-Checking Modes

As described in the previous section, by default gnatbind checks that object files are consistent with one another and are consistent with any source files it can locate. The following switches control binder access to sources.

-s
Require source files to be present. In this mode, the binder must be able to locate all source files that are referenced, in order to check their consistency. In normal mode, if a source file cannot be located it is simply ignored. If you specify this switch, a missing source file is an error.
-x
Exclude source files. In this mode, the binder only checks that ALI files are consistent with one another. Source files are not accessed. The binder runs faster in this mode, and there is still a guarantee that the resulting program is self-consistent. If a source file has been edited since it was last compiled, and you specify this switch, the binder will not detect that the object file is out of date with respect to the source file. Note that this is the mode that is automatically used by gnatmake because in this case the checking against sources has already been performed by gnatmake in the course of compilation (i.e. before binding).

Binder Error Message Control

The following switches provide control over the generation of error messages from the binder:

-v
Verbose mode. In the normal mode, brief error messages are generated to stderr. If this switch is present, a header is written to stdout and any error messages are directed to stdout. All that is written to stderr is a brief summary message.
-b
Generate brief error messages to stderr even if verbose mode is specified. This is relevant only when used with the -v switch.
-mn
Limits the number of error messages to n, a decimal integer in the range 1-999. The binder terminates immediately if this limit is reached.
-r
Renames the generated main program from main to gnat_main. This is useful in the case of some cross-building environments, where the actual main program is separate from the one generated by gnatbind.
-ws
Suppress all warning messages.
-we
Treat any warning messages as fatal errors.
-t
Ignore time stamp errors. Any time stamp error messages are treated as warning messages. This switch essentially disconnects the normal consistency checking, and the resulting program may have undefined semantics if inconsistent units are present. This means that -t should be used only in unusual situations, with extreme care.

Elaboration Control

The following switches provide additional control over the elaboration order. For full details see See section Elaboration Order Handling in GNAT.

-f
Instructs the binder to ignore directives from the compiler about implied Elaborate_All pragmas, and to use full Ada 95 Reference Manual semantics in an attempt to find a legal elaboration order, even if it seems likely that this order will cause an elaboration exception.
-p
Normally the binder attempts to choose an elaboration order that is likely to minimize the likelihood of an elaboration order error resulting in raising a Program_Error exception. This switch reverses the action of the binder, and requests that it deliberately choose an order that is likely to maximize the likelihood of an elaboration errror. This is useful in ensuring portability and avoiding dependence on accidental fortuitous elaboration ordering.

Output Control

The following switches allow additional control over the output generated by the binder.

-e
Output complete list of elaboration-order dependencies, showing the reason for each dependency. This output can be rather extensive but may be useful in diagnosing problems with elaboration order. The output is written to stdout.
h
Output usa