Appendix A2 continues...

A2.5.0 Binding Ada Programs With gnatbind
A2.5.1 Running gnatbind
A2.5.2 Consistency-Checking Modes
A2.5.3 Error-Message Control
A2.5.4 Output Control
A2.5.5 Binding for Non-Ada Main Programs
A2.5.6 Summary of Binder Switches
A2.5.7 Command-Line Access
A2.5.8 Search Paths for gnatbind
A2.5.9 Examples of gnatbind Usage
A2.6.0 Linking Ada Programs Using gnatlink
A2.6.1 Running gnatlink
A2.6.2 Switches for gnatlink
A2.7.0 The GNAT Make Program gnatmake
A2.7.1 Running gnatmake
A2.7.2 Switches for gnatmake
A2.7.3 Notes on the Command Line
A2.7.4 How gnatmake Works
A2.7.5 Examples of gnatmake Usage
A2.8.0 Handling Files With Multiple Units With gnatchop
A2.8.1 Handling Files With Multiple Units
A2.8.2 Command Line for gnatchop
A2.8.3 Switches for gnatchop
A2.8.4 Examples of gnatchop Usage
A2.9.0 The Front-End/Cross-Reference Utility gnatf
A2.9.1 Overview of gnatf
A2.9.2 Command Line of gnatf
A2.9.3 Compilation Switches
A2.9.4 Cross-Referencing Switches
A2.9.5 Cross Reference Information and Smart Recompilation
A2.9.6 File Structure
A2.9.7 Example of gnatf Usage
A2.10.0 Filename Krunching With gnatk8
A2.10.1 About gnatk8
A2.10.2 Using gnatk8
A2.10.3 Krunching Method
A2.10.4 Examples of gnatk8 Usage
A2.11.0 Other Utility Programs
A2.11.1 Using Other Utility Programs With GNAT
A2.11.2 The Naming Scheme of GNAT
A2.11.3 Ada Mode for Emacs
A2.12.0 Running and Debugging Ada Programs
A2.12.1 Getting Internal Debugging Information
A2.12.2 GNAT Crashes
A2.12.3 Using gdb
A2.13.0 Performance Considerations
A2.13.1 Controlling Runtime Checks
A2.13.2 Optimization Levels
A2.13.3 Inlining of Subprograms

A2.5.0 Binding Ada Programs With 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 Language 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 satisfying the rules in Chapter 10 of the Ada Language Reference 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 as comments in the generated C program, to be read by the gnatlink utility used to link the Ada application.

A2.5.1 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 located this source file, the time stamps must match. In other words, any ALI files mentioning this spec must have resulted from compiling this version of the source file.

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 from 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 since 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:
int
__main_priority ()
{
   return -1;
}
extern int gnat_argc;
extern char **gnat_argv;
extern int gnat_exit_status;
void main (argc, argv)
int argc;
char **argv;
{
   gnat_argc = argc;
   gnat_argv = argv;

   __gnat_initialize();
   system__task_specific_data___elabb ();
   p___elabs ();

   _ada_hello ();
   __gnat_finalize();
   exit (gnat_exit_status);
}
unsigned helloB = 0x86c26330;
unsigned system__standard_libraryS = 0x06371136;
unsigned pS = 0x4361339a;
unsigned systemS = 0x430ca9a6;
unsigned system__storage_elementsB = 0xc925fce2;
unsigned system__storage_elementsS = 0x86195344;
unsigned system__task_specific_dataB = 0x924bf9bc;
unsigned system__task_specific_dataS = 0x86195344;
unsigned system__tasking_soft_linksB = 0x0c32a681;
unsigned system__tasking_soft_linksS = 0x86195344;
/* BEGIN Object file/option list
/usr/local/adainclude/system.o
/usr/local/adainclude/s-stoele.o
/usr/local/adainclude/s-taspda.o
/usr/local/adainclude/s-tasoli.o
/usr/local/adainclude/s-stalib.o
p.o
hello.o
END Object file/option list */

The __main_priority function records the environment task priority. A value of -1 indicates that the main program has no pragma Priority, the normal case.

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 system__task_specific_data___elabb and p___elabs perform necessary elaboration of units in the program. In our example, only the library routine System.Task_Specific_Data (body) and P (spec) required elaboration (the main program 'hello.adb' did not require any elaboration).

The call to _ada_hello 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 full names of all the object files required to be linked for 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 runtime unit files. The directory names for the runtime units depend on the system configuration.


A2.5.2 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 can be used to modify this behavior:

'-s'
Require source files to be present. In this mode, the binder insists on being able to locate all source files that are referenced and checks their consistency. In normal mode, if a source file cannot be located it is simply ignored. If you specify the '-s' 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 the '-x' switch, the binder will not detect that the object file is out of date with the source file.

For most purposes the default mode is appropriate, and this is the mode that is normally used when gnatmake or gnatbind is used to do the bind operation.


A2.5.3 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 the '-v' 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 together 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.
'-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.


A2.5.4 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.
'-l' Output chosen elaboration order. The output is written to stdout.
'-o file' Set name of output file to file instead of the normal 'b_prog.c' default. You would normally give file an extension of '.c' since it will be a C source program.
'-c' Check only. Do not generate the binder output file. In this mode the binder performs all error checks but does not generate an output file.


A2.5.5 Binding for Non-Ada Main Programs

In our description in this chapter so far we have assumed the main program is in Ada and the task of the binder is to generate a corresponding function main to pass control to this Ada main program. GNAT also supports the building of executable programs where the main program is not in Ada, but some of the called routines are written in Ada and compiled using GNAT. The following switch is used in this situation:

'-n' No main program. The main program is not in Ada.

In this case, most of the functions of the binder are still required, but instead of generating a main program, the binder generates a file containing the following callable routines:

adainit You must call this routine to initialize the Ada part of the program by calling the necessary elaboration routines. A call to adainit is required before the first call to an Ada subprogram.
adafinal You must call this routine to perform any library-level finalization required by the Ada subprograms. A call to adafinal is required after the last call to an Ada subprogram, and before the program terminates.

If the '-n' switch is given, more than one ALI file may appear on the command line for gnatbind. The normal closure calculation is performed for each of the specified units. Calculating the closure means finding out the set of units involved by tracing with references. The reason it is necessary to be able to specify more than one ALI file is that a given program may invoke two or more quite separate groups of Ada subprograms.

The binder takes the name of its output file from the first specified ALI file, unless overridden by the use of the '-o' switch. It will be a C source file, which must be compiled using the C compiler.


A2.5.6 Summary of Binder Switches

The following are the switches available with gnatbind:

'-b' Generate brief messages to stderr even if verbose mode set.
'-c' Check only, no generation of binder output file.
'-e' Output complete list of elaboration-order dependencies.
'-I' Specify directory to be searched for source and ALI files.
'-l' Output-chosen elaboration order.
'-mn' Limit number of detected errors to n (1-999).
'-n' No main program.
'-o file' Name the output file (default is 'b_xxx.c').
'-s' Require all source files to be present.
'-t' Ignore time-stamp errors.
'-v' Verbose mode. Write error messages, header, summary output to stdout.
'-wx' Warning mode (x=s/e for suppress/treat as error)
'-x' Exclude source files (check object consistency only

You may obtain this listing by running the program gnatbind with no arguments.


A2.5.7 Command-Line Access

The package Ada.Command_Line provides access to the command-line arguments and program name. In order for this interface to operate correctly, the two variables
int gnat_argc;
char **gnat_argv;
are declared in one of the GNAT library routines. These variables must be set from the actual argc and argv values passed to the main program. With no '-n' switch present, gnatbind generates the C main program to automatically set these variables. If the '-n' switch is used, there is no automatic way to set these variables. If they are not set, the procedures in Ada.Command_Line will not be available, and any attempt to use them will raise Constraint_Error. If command line access is required, your main program must set gnat_argc and gnat_argv from the argc and argv values passed to it.


A2.5.8 Search Paths for gnatbind

The binder must be able to find both the ALI files and the source files. For source files, it follows exactly the same search rules as gcc (see section "A2.4.4 Search Paths and the Run-Time Library (RTL)"). Search paths are used for finding the ALI files.

The binder takes the name of an ALI file as its argument and needs to locate other ALI files in its recursive processing. These are found in the following directories in the following order:
  1. The current working directory.

  2. All directories specified by '-I' switches on the gnatbind command line, in the order given.

  3. Each of the directories listed in the value of the ADA_OBJECTS_PATH environment variable. Construct this value the same as the PATH environment variable; a list of directory names separated by colons.

  4. The default location for the GNAT Run-Time Library (RTL) files, determined when GNAT was built and installed on your system.
For source files accessed by the binder, the search procedure is as described above for object files, except that in step 3 the environment variable ADA_SOURCE_PATH is used. The binder generates the bind file (a C language source file) in the current working directory.

The packages Ada, System, and Interfaces and their children make up the GNAT Run-Time Library, together with the package GNAT and its children which contain a set of useful additional library functions provided by GNAT. The sources for these units are needed by the compiler and are kept together in one directory. The ALI files and object files generated by compiling the RTL are needed by the binder and the linker and are kept together in one directory, typically different from the directory containing the sources. 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.

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


A2.5.9 Examples of gnatbind Usage

This section contains a number of examples of using the GNAT binding utility gnatbind.

gnatbind hello.ali
The main program Hello (source program in 'hello.adb') is bound using the standard switch settings. The generated main program is 'b_hello.c'. This is the normal, default use of the binder.
gnatbind main_program.ali -o mainprog.c -x -e
The main program Main_Program (source program in 'main_program.adb') is bound, excluding source files from the consistency checking. A full list of elaboration dependencies is output to stdout, and the file 'mainprog.c' is generated
gnatbind -xe main_program.ali -o mainprog.c
This command is exactly the same as the previous example. Switches may appear anywhere in the command line, and single letter switches may be combined into a single switch.
gnatbind -n math.ali dbase.ali -o ada-control.c
The main program is in a language other than Ada, but calls to subprograms in packages Math and Dbase appear. This call to gnatbind generates the file 'ada-control.c' containing the adainit and adafinal routines to be called before and after accessing the Ada subprograms.


A2.6.0 Linking Ada Programs Using gnatlink

This chapter discusses gnatlink, a utility program used to link Ada programs and build an executable file. This program is basically a simple process which invokes the Unix linker (via the gcc command) with a correct list of object files and library references. gnatlink automatically determines the list of files and references for the Ada part of a program. It uses the binder file generated by the binder to determine this list.


A2.6.1 Running gnatlink

The form of the gnatlink command is
gnatlink [switches] mainprog[.ali] [non-Ada objects] [linker options]
'mainprog.ali' references the ALI file of the main program. The '.ali' extension of this file can be omitted. From this reference, gnatlink locates the corresponding binder file 'b_mainprog.c' and, using the information in this file along with the list of non-Ada objects and linker options, constructs a Unix linker command file to create the executable.

The arguments following 'mainprog.ali' are passed to the linker uninterpreted. They typically include the names of object files for units written in other languages than Ada and any library references required to resolve references in any of these foreign language units, or in pragma Import statements in any Ada units. This list may also include linker switches.

gnatlink determines the list of objects required by the Ada program and prepends them to the list of objects passed to the linker. gnatlink also gathers any arguments set by the use of pragma Linker_Options and adds them to the list of arguments presented to the linker.


A2.6.2 Switches for gnatlink

The following switches are available with the gnatlink utility:

'-o exec-name' exec-name specifies an alternative name for the generated executable program. If the '-o' switch is omitted, the executable is called the name of the main unit. So gnatlink try.ali creates an executable called 'try'.
'-v' Causes additional information to be output, including a full list of the included object files. This switch option is most useful when you want to see what set of object files are being used in the link step.
'-g' The option to include debugging information causes the C bind file (in other words, 'b_mainprog.c') to be compiled with '-g'. In addition, the binder does not delete the 'b_mainprog.c' and 'b_mainprog.o' files (without '-g', the binder removes these files by default).
'-gnatlink name' name is the name of the linker to be invoked. You normally omit this switch, in which case the default name for the linker is ('gcc').


A2.7.0 The GNAT Make Program gnatmake

A typical development cycle when working on an Ada program consists of the following steps:
  1. Edit some sources to fix bugs.

  2. Add enhancements.

  3. Compile all sources affected.

  4. Rebind and relink.

  5. Test.
The third step can be tricky, because not only do the modified files have to be compiled, but any files depending on these files must also be recompiled. The dependency rules in Ada can be quite complex, especially in the presence of overloading, use clauses, generics and inlined subprograms.

gnatmake automatically takes care of the third and fourth steps of this process. It determines which sources need to be compiled, compiles them, and binds and links the resulting object files.

Unlike some other Ada make programs, the dependencies are always accurately recomputed from the new sources. The source based approach of the GNAT compilation model makes this possible. This means that if changes to the source program cause corresponding changes in dependencies, they will always be tracked exactly correctly by gnatmake.


A2.7.1 Running gnatmake

The gnatmake command has the form:
gnatmake [-a][-c][-f][-g][-jn][-k][-M][-o exec-name][-n][-q][-v]
         [compiler_switch]
         {-Adir}{-aOdir}{-aIdir}{-Idir}{-I-}{-Ldir}
         unit_or_file_name
         {-cargs options} {-bargs options} {-largs options}
Here square brackets indicate optional components in the command, and curly brackets indicate a construction that can occur zero or more times.

The only required argument is unit_or_file_name, which specifies the compilation unit that is the main program. There are two ways to specify this: All gnatmake output (except when you specify '-M') is to stderr. The output produced by the '-M' switch is send to stdout.


A2.7.2 Switches for gnatmake

You may specify any of the following switches to gnatmake:

'-a' Consider all files in the make process, even the GNAT internal system files (for example, the predefined Ada library files). By default, gnatmake does not check these files (however, if there is an installation problem, it will be caught when gnatmake binds your program). You may have to specify this switch if you are working on GNAT itself. The vast majority of gnatmake users never need to specify this switch. By default gnatmake -a compiles all GNAT internal files with gcc -c -gnatg rather than gcc -c.
'-c' Compile only. Do not perform binding and linking. If the root unit specified by unit_or_file_name is not a main unit, this is the default. Otherwise gnatmake will attempt binding and linking unless all objects are up to date and the executable is more recent than the objects.
'-f' Force recompilations. Recompile all sources, even though some object files may be up to date, but don't recompile predefined or GNAT internal files unless the '-a' switch is also specified.
'-g' Compile with debugging information. Same effect as -cargs -g.
'-jn' Use n processes to carry out the (re)compilations. If you have a multiprocessor machine, compilations will occur in parallel. In the event of compilation errors, messages from various compilations might get interspersed (but gnatmake will give you the full ordered list of failing compiles at the end). This can at times be annoying. To get a clean list of error messages don't use '-j'.
'-k' Keep going. Continue as much as possible after a compilation error. To ease the programmers's take in case of compilation errors, the list of sources for which the compile fails is given when gnatmake terminates.
'-M' Check if all objects are up to date. If they are output the object dependences to stdout in a form that can be directly exploited in a 'Makefile'. By default, each source file is prefixed with its (relative or absolute) directory name. This name is whatever you specified in the various '-aI' and '-I' switches. If you use gnatmake -M -q (see '-q' below), only the source file names, without relative paths, are output. If you just specify the '-M' switch, dependencies of the GNAT internal system files are omitted. This is typically what you want. If you also specify the ' T' switch, dependencies of the GNAT internal files are also listed. Note that dependencies of the objects in external Ada libraries (see switch '-aLdir' in the following list) are never reported.
'-n' Don't compile, bind, or link. Output a single command that will recompile an out of date unit, if any. Repeated use of this option, followed by carrying out the indicated compilation, will eventually result in recompiling all required units. If any ALI is missing during the process, gnatmake halts and displays an error message.
'-o exec_name'Output executable name. The name of the final executable program will be exec_name. If the '-o' switch is omitted the default name for the executable will be the name of the input file without the suffix (Unix systems) or the name of the input file with an '.exe' extension (DOS and OS/2). You may prefix exec_name with a relative or absolute directory path.
'-q' Quiet. When this flag is not set, the commands carried out by gnatmake are displayed.
'-v' Verbose. Displays the reason for all recompilations gnatmake decides are necessary.
'gcc switches' The switch '-g' or any upper case switch (other than '-A', or '-L') or switch that is more than one character is passed to gcc (e.g. '-O', '-gnato,' etc.)

Source & Library search path switches:

'-Adir' Equivalent to '-aLdir -aIdir'.
'-aOdir' When looking for library and object files look also in directory dir. The order in which library files search is undertaken is described in section "A2.4.4 Search Paths and the Run-Time Library (RTL)".
'-aIdir' When looking for source files also look in directory dir.
'-Idir' Equivalent to '-aOdir -aIdir'.
'-I-' Do not look for source, library or object files in the default directory.
'-Lvar' Add directory dir to the list of directories in which the linker will search for libraries. This is equivalent to '-largs -Ldir'.

General compiler, binder or linker switches:

'-cargs options'Compiler arguments. Without '-cargs', gnatmake uses gcc -c to perform compilations. Otherwise, gnatmake uses gcc -c c_opts, where c_opts is a list of parameters including all the options encountered in the set of '-cargs' switches present on the gnatmake command line. A given sublist of '-cargs' options is terminated upon encountering another '-cargs', '-bargs' or '-largs'. By default, gnatmake -a compiles all GNAT internal files with gcc -c -gnatg rather than gcc -c.
'-bargs options'Binder arguments. Without '-bargs', gnatmake uses gnatbind unit.ali to bind. Otherwise, gnatmake uses gnatbind b_opts unit.ali. b_opts is akin to c_opts, but is obtained from '-bargs' switches. '-largs options'. Similar to '-bargs', but specifies the options for gnatlink. Note that you are not allowed to use the '-o' switch within a '-largs'. Use the '-o' switch directly to gnatmake to give a specific name to your executable.


A2.7.3 Notes on the Command Line

Please note the following with regard to gnatmake:

A2.7.4 How gnatmake Works

Generally gnatmake automatically performs all necessary recompilations and you don't need to worry about how it works. However, it may be useful to have some basic understanding of the gnatmake approach and in particular to understand how it uses the results of previous compilations without incorrectly depending on them.

First a definition: an object file is considered up to date if the corresponding ALI file exists and if all the source files listed in the dependency section of this ALI file have time stamps matching those in the ALI file. This means that neither the source file itself nor any files that it depends on have been modified, and hence there is no need to recompile this file.

gnatmake works by first checking if the specified main program is up to date. If so, it is done, and no compilations are required. If not, it compiles the main program to build a new ALI file that reflects the latest sources. It examines this ALI file to find all the source files on which the main program depends, and recursively applies the up to date test on all these files.

This process ensures that gnatmake only trusts the dependencies in an existing ALI file if they are known to be correct. Otherwise it always recompiles to determine a new, guaranteed accurate set of dependencies. Thus the program is compiled "upside down" from what may be more familiar as the required order of compilation in some other Ada systems. In particular, clients are compiled before the units on which they depend. The ability of GNAT to compile in any order is critical in allowing an order of compilation to be chosen that guarantees that gnatmake will recompute a correct set of new dependencies if necessary.


A2.7.5 Examples of gnatmake Usage

gnatmake hello.adb
Compile all files necessary to bind and link the main program 'hello.adb' (containing unit Hello) and bind and link the resulting object files to generate an executable file 'hello'.
gnatmake -q Main_Unit -cargs -O2 -bargs -l
Compile all files necessary to bind and link the main program unit Main_Unit (from file 'main_unit.adb'). All compilations will be done with optimization level 2 and the order of elaboration will be listed by the binder. gnatmake will operate in quiet mode, not displaying commands it is executing.


A2.8.0 Handling Files With Multiple Units With gnatchop

This chapter discusses how to handle files with multiple units by using the gnatchop utility.


A2.8.1 Handling Files With Multiple Units

The basic compilation model of GNAT requires a file submitted to the compiler have only one unit and there must be a strict correspondence between the file name and the unit name.

The gnatchop utility allows both of these rules to be relaxed, allowing GNAT to process files which contain multiple compilation units and files with arbitrary filenames. The approach used by gnatchop is to read the specified file and generate one or more output files, containing one unit per file and with proper filenames as required by GNAT.

If you want to permanently restructure a set of "foreign" files so that they match the GNAT rules and do the remaining development using the GNAT structure, you can simply use gnatchop once, generate the new set of files and work with them from that point on.

Alternatively, if you want to keep your files in the "foreign" format, perhaps to maintain compatibility with some other Ada compilation system, you can set up a procedure where you use gnatchop each time you compile, regarding the source files that it writes as temporary files that you throw away.


A2.8.2 Command Line for gnatchop

The gnatchop command has the form:
gnatchop [-k] [-r] [-s] [-w] filename [directory]
The only required argument is the filename of the file to be chopped. There are no restrictions on the form of this filename. The file itself contains one or more Ada files, in normal GNAT format, concatenated together.

When run in default mode, gnatchop generates one output file in the current directory for each unit in the file. For example, given a file called 'hellofiles' containing:
procedure hello;
with Text_IO; use Text_IO;
procedure hello is
begin
   Put_Line ("Hello");
end hello;
the command:
gnatchop hellofiles
generates two files in the current directory, one called 'hello.ads' containing the single line that is the procedure spec, and the other called 'hello.adb' containing the remaining text. The original file is not affected. The generated files can be compiled in the normal manner.


A2.8.3 Switches for gnatchop

gnatchop recognizes the following switches:

'-k' Limit generated filenames to eight characters. This is useful if the resulting set of files is required to be interoperable with systems like MS-DOS which limit the length of filenames.
'-r' Generate Source_Reference pragmas. Use this switch if the output files are regarded as temporary and development is to be done in terms of the original unchopped file. The '-r' switch causes Source_Reference pragmas to be inserted into each of the generated files to refers back to the original filename and line number. The result is that all error messages refer back to the original unchopped file. In addition, the debugging information placed into the object file (when the '-g' switch of gcc or gnatmake is specified) also refers back to this original file so that tools like profilers and debuggers will give information in terms of the original unchopped file.
'-s' Write a compilation script to standard output containing gcc commands to compile the generated files.
'-w' Overwrite existing filenames. Normally gnatchop regards it as a fatal error situation if there is already a file with the same name as a file it would otherwise output. The '-w' switch bypasses this check, and any such existing files will be silently overwritten.

directory, if specified, gives the name of the directory to which the output files will be written. If it is not specified, all files are written to the current directory.


A2.8.4 Examples of gnatchop Usage

gnatchop -w hello_s.ada ~gnat/ichibiah/files
Chops the source file 'hello_s.ada'. The output files will be placed in the directory '~gnat/ichibiah/files', overwriting any files with matching names in that directory (no files in the current directory are modified).
gnatchop -s -r collect
Chops the source file 'collect' into the current directory. A compilation script is also generated, and all output files have Source_Reference pragmas, so error messages will refer back to the file 'collect' with proper line numbers.
gnatchop archive
Chops the source file 'archive' into the current directory. One useful application of gnatchop is in sending sets of sources around, for example in email messages. The required sources are simply concatenated (for example, using a Unix cat command), and then gnatchop is used at the other end to reconstitute the original file names.


A2.9.0 The Front-End/Cross-Reference Utility gnatf

This chapter discusses gnatf, a stripped-down version of the GNAT compiler containing only the front end. gnatf can preform full syntax and semantic checking and also has a cross-reference analyzer built in that can perform a variety of functions.


A2.9.1 Overview of gnatf

The GNAT system provides a stand-alone tool, gnatf, which allows for syntax and semantics checking without any code generation. This is somewhat faster than using gcc -gnatc.

The standard GNAT switches that do not concern code generation are still available in gnatf. However, they should not be proceeded by '-gnat', so to do syntax only checking with gnatf, use gnatf -s file.adb, not gnatf -gnats file.adb.

The real point of gnatf is that it contains a cross reference tool, whose goals are:

A2.9.2 Command Line of gnatf

The gnatf command line is of the following form:
gnatf [switches] files
The effect is similar to a gcc command specifying the '-gnatc' (no code generation) switch, although it is somewhat faster, especially if several files are processed at the same type.


A2.9.3 Compilation Switches

The following compilation switches are similar to the corresponding switches in gcc, except that the names are not preceded by '-gnat'. For example, the gnatf switch for syntax-only checking is '-s' instead of -gnats. For full details on these switches, see section "A2.4.2 Switches for gcc"

'-b' Generate brief messages to stderr even if verbose mode set
'-e' Error messages generated immediately, not saved up till end
'-f' Full errors. Multiple errors/line, all undefined references
'-g' GNAT style checks enabled
'-ic' Identifier char set (c=1/2/3/4/8/p/f/n/w)
'-je' Wide character encoding method (e=n/h/u/s/e)
'-kn' Limit file names to n (1-999) character.
'-l' Output full source listing with embedded error messages
'-mn' Limit number of detected errors to n (1-999)
'-q' Don't quit, try semantics, even if parse errors
'-r' Reference manual column layout required
'-s' Syntax check only
'-t' Tree output file to be generated
'-u' List units for this compilation
'-v' Verbose mode. Full error output with source lines to stdout
'-wm' Warning mode. (m=s/e for suppress/treat as error)
'-83' Enforce Ada 83 restrictions


A2.9.4 Cross-Referencing Switches

The following list contains the descriptions of the cross-referencing flags available with gnatf:
'-x1' Issues warnings for unnecessary, misplaced or redundant with clauses. Specifically, a warning message is generated in the following cases:
  • A compilation unit which is with'ed but never used (this works with child library units as well).

  • A compilation unit that is with'ed in a body (responsible subunit) if the same with clause already appears in the specification (responsible specification or body for subunits).

  • A compilation unit that is with'ed within a specification but is used only by the body or a subunit.
'-x2' Issues warnings on unused entities, that is entities that are declared but never used. Note that no warnings are issued for unreferenced entities such as the following:
  • Record fields, since they could be referenced indirectly by an aggregate.

  • Enumeration entities, since they could be referenced indirectly by enumeration ranges:
    for i in Color'First .. Color'Last

  • Loop parameters:
    for I in 1 .. 80 loop
    Put ('x');
    end loop;
'-x[345]' Generate cross-reference information. The '-x3' switch gives the most succinct cross-referencing information, '-x5' the most comprehensive. The '-x4' switch gives more information than '-x3' but not as much as '-x5'. The information given by switches '-x3' and '-x4' is used in the smart recompilation system currently under development. The '-x5' switch lists all entities defined or used in the analyzed compilation units. It gives the source location of their definition and all their uses in the analyzed units.
'-x6' The cross-reference output is the same as with '-x5', except that with '-x6', all cross-reference information is stored in the single file 'X.ref', and the entity kind of each cross-referenced entity is also given.

A2.9.5 Cross Reference Information and Smart Recompilation

The cross reference information gathered by the '-x3' and '-x4' switches is a subset of the information specified by the '-x5' switch. The former information is specifically tailored to the smart recompilation system currently under development. When '-x3' or '-x4' are specified, the cross-referencing tool gnatf produces the following information for each compilation unit analyzed. We refer to that unit as unit in the following list.

A2.9.6 File Structure

The cross-referencing file is divided into various sections. There is one section for each compilation unit explicitly requested. We call these units, RUs, for "requested units." There is also one section for each AU, (auxiliary unit); that is, those compilation units that are implicitly loaded by the compiler, but whose compilation has not been explicitly requested by the user. Specs of withed packages are typical AUs.

All entities exported by RUs (the '-x3' and '-x4' switches) or all entities belonging to RUs (the '-x5' and '-x6' switches) appear in the cross-referencing file(s).

However, only the entities defined in AUs that are imported in RUs appear in the cross-referencing file. Their order is the order of declaration in the source files.

The sections in the cross reference referring to RUs and AUs are respectively denoted:
%% unit.ad[sb]
     for an RU
-- unit.ad[sb]
     for an AU
Note: An entity defined inside a generic and used through a generic instantiation is listed under the cross-referencing section of the generic unit.


A2.9.7 Example of gnatf Usage

'test.adb'
01 with Part1; -- unused
02 with Part2; use Part2;
03 procedure Test is
04
05 Thing : Number;
06 type Client is record
07 Number : Integer;
08 State : Boolean;
09 end record;
10 type Color is (Red, Green); -- unused
11 My_Client : Client;
12
13 begin
14 My_Client.Number := 1;
15 My_Client.State := True;
16 Thing := 20;
17 Thing := Thing + Thing;
18 end;
'part1.ads'
01 package Part1 is
02 type Useless is new Integer;
03 end;
'part2.ads'
01 package Part2 is
02 type Number is new Integer range 1 .. 1000;
03 The_Number : constant := 42;
04 end;
The result of invoking gnatf -x5 test.adb is the following (just skim the file 'test.xrb', explanations follow:

Warnings on stderr (the screen):
test.adb:1:06: warning: "Part1" withed but unused. test.adb:3:11:
warning: "Test" unused test.adb:10:09: warning: "Color" unused
'test.xrb'
01 V "SGNAT v1.0 "
02 test.adb 941012154746 2 3
03 part1.ads 941012154531
04 part2.ads 941012154620
05
06 %% test.adb
07 test 3:11
08 thing 5:4
09 {16:4 17:4 17:13 17:21}
10 client 6:9
11 {11:16}
12 client.number 7:7
13 {14:14}
14 client.state 8:7
15 {15:14}
16 color 10:9
17 red 10:19
18 green 10:24
19 my_client 11:4
20 {14:4 15:4}
21
22 -- part1.ads
23 part1 1:9
24 {1:6}
25
26 -- part2.ads
27 part2 1:9
28 {2:6 2:17}
29 number 2:9
30 {5:14}

The unit Test is the only RU (requested unit). AUs (auxiliary units) are packages Part1 and Part2. First, the graph of the loaded units with their time stamps is given:
02 test.adb 941012154746 2 3
03 part1.ads 941012154531
04 part2.ads 941012154620
Unit Test requires the loading of units Part1 and Part2 (the second and third units listed in the inclusion graph).

The entry
06 %% test.adb
07 [...]
08 thing 5:4
09 {16:4 17:4 17:13 17:21}
means Thing is an entity (a variable) defined in line 5 column 4; used in line 16 column 4; and in line 17 columns 4, 13, and 21; in file 'test.adb'.

The entity Useless may be used in units other than Test, but that information is not contained in the 'test.xrb' file because Test does not use Useless.


A2.10.0 Filename Krunching With gnatk8

This chapter discusses the gnatk8 filename krunching utility.

A2.10.1 About gnatk8

The normal rule in using GNAT is that the filename must be derived from the unit name. The exact default rule is: Take the unit name and replace all dots by hyphens, except that if such a replacement occurs in the second character position of a name, replace the dot by a plus instead of a hyphen.

The '-gnatknn' switch of the compiler activates a "krunching" circuit that limits filenames to nn characters (where nn is a decimal integer). This is primarily intended for use on MS-DOS and similar systems where nn=8, to fit in the 8+3 limitation on filenames found in these systems.

The gnatk8 utility can be used to determine the krunched name for a given file, when krunched to a specified maximum length.


A2.10.2 Using gnatk8

The gnatk8 command has the form:
gnatk8 name [length]
name can be an Ada name with dots or the GNAT name of the unit where the dots representing child units or subunit are replaced by hyphens. The only confusion arises if a name ends in '.ads' or '.adb'. gnatk8 takes this to be an extension if there are no other dots in the name and the whole name is in lower case.

length represents the length of the krunched name. The default without any argument given is 8 characters. A length of zero stands for unlimited, in other words no chop except for system files which are always 8.

The output is the krunched name. The output has an extension only if the original argument was a filename with an extension.


A2.10.3 Krunching Method

The initial filename 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 lower case for all letter, except that a hyphen in the second character position is replaced by a plus sign. The extension is '.ads' for a specification and '.adb' for a body.

Krunching does not affect the extension, but the filename is shortened to the specified length by following these rules:
our-strings-wide_fixed 22
our strings wide fixed 19
our string wide fixed 18
our stri wide fixed 17
our stri wide fixed 16
our stri wide fixe 14
our str wide fixe 14
our str wid fixe 13
our str wid fix 12
ou str wid fix 11
ou st wid fix 10
ou st wi fix 9
ou st wi fi 8
Final filename: oustwifi.adb
'ada-'       replaced by 'a-'
'gnat-'      replaced by 'g-'
'interfaces-'replaced by 'i-'
'system-'    replaced by 's-'
These system files have a hyphen in the second character position. That is why normal user files replace such a character with a plus sign, to avoid confusion with system filenames. As an example of this special rule, consider 'ada-strings-wide_fixed.adb', which gets krunched as follows:
ada-strings-wide_fixed 22
a- strings wide fixed 18
a- string wide fixed 17
a- strin wide fixed 16
a- stri wide fixed 15
a- stri wide fixe 14
a- str wide fixe 13
a- str wid fixe 12
a- str wid fix 11
a- st wid fix 10
a- st wi fix 9
a- st wi fi 8
Final filename: a-stwifx.adb
Of course no file shortening algorithm can guarantee uniqueness over all possible unit names, and if filename krunching is used then it is your responsibility to ensure that no name clashes occur. The utility program gnatk8 is supplied for conveniently determining the krunched name of a file.


A2.10.4 Examples of gnatk8 Usage

gnatk8 very_long_unit_name.ads ----> velounna.ads
gnatk8 very_long_unit_name.ads 6 ----> vlunna.ads
gnatk8 very_long_unit_name.ads 0 ----> long_unit_name.ads
gnatk8 grandparent-parent-child.ads ----> grparchi.ads
gnatk8 grandparent.parent.child ----> grparchi 

A2.11.0 Other Utility Programs

This chapter discusses some other utility programs available in the Ada environment.


A2.11.1 Using Other Utility Programs With GNAT

The object files generated by GNAT are in standard system format and in particular the debugging information uses this format. This means programs generated by GNAT can be used with existing utilities that depend on these formats.

In general, any utility program that works with C will also work with Ada programs generated by GNAT. This includes software utilities such as gprof (a profiling program), gdb (the FSF debugger), and utilities such as Purify.


A2.11.2 The Naming Scheme of GNAT

In order to interpret the output from GNAT, it is necessary to understand the conventions used to generate link names from the Ada entity names.

All names are in all lower-case letters. With the exception of library procedure names, the mechanism used is simply to use the full expanded Ada name with dots replaced by double underscores. For example, suppose we have the following package spec:
package QRS is MN : Integer; end QRS;
The variable MN has a full expanded Ada name of QRS.MN, so the corresponding link name is qrs__mn.

Of course if a pragma Export is used this may be overridden:
package Exports is
   Var1 : Integer;
   pragma Export (Var1, C, External_Name => "var1_name");
   Var2 : Integer;
   pragma Export (Var2, C, Link_Name => "var2_link_name");
end Exports;
In this case, the link name for Var1 is var1_name, and the link name for Var2 is var2_link_name.

One exception occurs for library level procedures. A potential ambiguity arises between the required name _main for the C main program, and the name we would otherwise assign to an Ada library level procedure called Main (which might well not be the main program).

To avoid this ambiguity, we attach the prefix _ada_ to such names. So if we have a library level procedure such as
procedure Hello (S : String);
the external name of this procedure will be _ada_hello.


A2.11.3 Ada Mode for Emacs

In the subdirectory 'emacs-ada-mode' you will find a set of files implementing an Ada mode under GNU emacs. The mode is still under development, but a number of features are complete.

For instance, the Ada mode has the same indenting friendliness that C programmers get with the c-mode, you can toggle between specification and body with a few keystrokes, etc. This mode also uses 'gnatf' to be able to point to an entity with the mouse, click it and open a window with its definition. This mode is copyrighted by Markus Heritsch and Rolf Ebert.


A2.12.0 Running and Debugging Ada Programs

This chapter discusses how to run and debug Ada programs.


A2.12.1 Getting Internal Debugging Information

Most compilers have secret internal debugging switches and modes. GNAT does also, except GNAT internal debugging switches and modes are not secret. A summary and full description of all the compiler and binder debug flags are in the file 'debug.adb'. You must obtain the sources of the compiler to see the full detailed effects of these flags.

The switches that print the source of the program (reconstructed from the internal tree) are of general interest, as are the options to print the full internal tree, and the entity table (that is the symbol table information).


A2.12.2 GNAT Crashes

GNAT may experience problems in operation, such as aborting with a segmentation fault or illegal memory access, raising an internal exception, or terminating abnormally. If such problems occur, try the solutions described in this section.

The following strategies are presented in increasing order of difficulty, corresponding to the user's skill level and curiosity about the functioning of the compiler.
  1. Run gcc with the -gnatf and -gnate switches. The first switch causes all errors on a given line to be reported. In its absence, only the first error on a line is displayed. The '-gnate' switch causes errors to be displayed as soon as they are encountered, rather than after compilation is terminated. Often this is enough to identify the construct that produced the crash.

  2. Run gcc with the '-v' (verbose) switch. In this mode, gcc produces ongoing information about the progress of the compilation and provides the name of each procedure as code is generated. This switch allows you to find which Ada procedure was being compiled when it encountered a code generation problem.

  3. Run gcc with the '-gnatdc' switch. This is a GNAT specific switch that does for the frontend what '-v' does for the backend. The system prints the name of each unit, either a compilation unit or nested unit, as it is being analyzed.

  4. On systems that have gdb available (most Unix systems), start gdb directly on the gnat1 executable. gnat1 is the front-end of GNAT, and can be run independently (normally it is just called from gcc). You can use gdb on gnat1 as you would on a C program (but see section "A2.12.3 Using gdb"for caveats). The where command is the first line of attack; the variable lineno (seen by print lineno), used by the second phase of gnat1 and by the gcc backend, indicates the source line at which the execution stopped, and input_filename indicates the name of the source file.


A2.12.3 Using gdb

gdb awaits modifications to handle Ada properly, and for now can only be used as it would be for a C program. In the meantime, the following naming conventions allow you to find the Ada entities defined in your program: See section "A2.11.2 The Naming Scheme of GNAT" for more information.

Exceptions can be caught by breaking in the __gnat_raise function and then entering a bt or where command.


A2.13.0 Performance Considerations

The GNAT system provides a number of options that allow a trade off between The defaults if no options are selected are aimed at improving the speed of compilation and minimizing dependences at the expense of performance of the generated code: These options are suitable for most program development purposes. This chapter documentation describes how you can modify these choices.


A2.13.1 Controlling Runtime Checks

By default, GNAT produces all runtime checks except arithmetic overflow checking for integer operations (including division by zero) and checks for access before elaboration on subprogram calls.

Two gnat switches, '-gnatp' and '-gnato' allow this default to be modified. See section "A2.4.3.3 Runtime Checks."

Our experience is that the default is suitable for most development purposes.

We treat integer overflow and elaboration checks specially because these are quite expensive and in our experience are not as important as other runtime checks in the development process.

Note that the setting of the switches controls the default setting of the checks. They may be modified using either pragma Suppress (to remove checks) or pragma Unsuppress (to add back suppressed checks) in the program source.


A2.13.2 Optimization Levels

The default is optimization off. This results in the fastest compile times, but GNAT makes absolutely no attempt to optimize, and the generated programs are considerably larger and slower. You can use the '-On' switch, where n is an integer from 0 to 3, on the gcc command to control the optimization level:

'-O0' no optimization (the default)
'-O1' medium level optimization
'-O2' full optimization
'-O3' full optimization, and also attempt automatic inlining of small subprograms within a unit (see section "A2.13.3 Inlining of Subprograms").

The penalty in compilation time, and the improvement in execution time, both depend on the particular application and the hardware environment. You should experiment to find the best level for your application.

Note: Unlike the case with some other compiler systems, gcc has been tested extensively at all optimization levels. There are some bugs which appear only with optimization turned on, but there have also been bugs which show up only in unoptimized code. Selecting a lower level of optimization does not improve the reliability of the code generator, which in practice is highly reliable at all optimization levels.


A2.13.3 Inlining of Subprograms

A call to a subprogram in the current unit is inlined if all the following conditions are met: Calls to subprograms in with'ed units are normally not inlined. To achieve this level of inlining, the following conditions must all be true: Note that specifying the '-gnatn' switch causes additional compilation dependencies. Consider the following:
package R is
   procedure Q;
   pragma Inline Q;
end R;
package body R is
   ...
end R;
with R;
procedure Main is
begin
   ...
   R.Q;
end Main;
With the default behavior (no '-gnatn' switch specified), the compilation of the Main procedure depends only on its own source, 'main.adb', and the spec of the package in file 'r.ads'. This means that editing the body of R does not require recompiling Main.

On the other hand, the call R.Q is not inlined under these circumstances. If the '-gnatn' switch is present when Main is compiled, the call will be inlined if the body of Q is small enough, but now Main depends on the body of R in 'r.adb' as well as the spec. This means that if the body is edited, the main program must be recompiled. Note that this extra dependency occurs whether or not the call is in fact inlined by gcc.

Note: The gcc switch '-fno-inline' can be used to prevent all inlining. This switch overrides all other conditions and ensures that no inlining occurs. The extra dependencies resulting from '-gnatn' will still be active, even if the '-fno-inline' switch is used.



[ Top of Page ][ Appendix B ][ Table of Contents ]