3.10.3 Integrated Preprocessing

As noted above, a file to be preprocessed consists of Ada source code in which preprocessing lines have been inserted. However, instead of using gnatprep to explicitly preprocess a file as a separate step before compilation, you can carry out the preprocessing implicitly as part of compilation. Such ‘integrated preprocessing’, which is the common style with C, is performed when either or both of the following switches are passed to the compiler:

Integrated preprocessing applies only to Ada source files, it is not available for configuration pragma files.

With integrated preprocessing, the output from the preprocessor is not, by default, written to any external file. Instead it is passed internally to the compiler. To preserve the result of preprocessing in a file, either run gnatprep in standalone mode or else supply the -gnateG switch (described below) to the compiler.

When using project files:

Note that the gnatmake switch -m will almost always trigger recompilation for sources that are preprocessed, because gnatmake cannot compute the checksum of the source after preprocessing.

The actual preprocessing function is described in detail in Preprocessing with gnatprep. This section explains the switches that relate to integrated preprocessing.

-gnatep=`preprocessor_data_file'

This switch specifies the file name (without directory information) of the preprocessor data file. Either place this file in one of the source directories, or, when using project files, reference the project file’s directory via the project_name'Project_Dir project attribute; e.g:

project Prj is
   package Compiler is
      for Switches ("Ada") use
        ("-gnatep=" & Prj'Project_Dir & "prep.def");
   end Compiler;
end Prj;

A preprocessor data file is a text file that contains ‘preprocessor control lines’. A preprocessor control line directs the preprocessing of either a particular source file, or, analogous to others in Ada, all sources not specified elsewhere in the preprocessor data file. A preprocessor control line can optionally identify a ‘definition file’ that assigns values to preprocessor symbols, as well as a list of switches that relate to preprocessing. Empty lines and comments (using Ada syntax) are also permitted, with no semantic effect.

Here’s an example of a preprocessor data file:

"toto.adb"  "prep.def" -u
--  Preprocess toto.adb, using definition file prep.def
--  Undefined symbols are treated as False

* -c -DVERSION=V101
--  Preprocess all other sources without using a definition file
--  Suppressed lined are commented
--  Symbol VERSION has the value V101

"tata.adb" "prep2.def" -s
--  Preprocess tata.adb, using definition file prep2.def
--  List all symbols with their values

A preprocessor control line has the following syntax:

<preprocessor_control_line> ::=
   <preprocessor_input> [ <definition_file_name> ] { <switch> }

<preprocessor_input> ::= <source_file_name> | '*'

<definition_file_name> ::= <string_literal>

<source_file_name> := <string_literal>

<switch> := (See below for list)

Thus each preprocessor control line starts with either a literal string or the character ‘*’:

  • A literal string is the file name (without directory information) of the source file that will be input to the preprocessor.
  • The character ‘*’ is a wild-card indicator; the additional parameters on the line indicate the preprocessing for all the sources that are not specified explicitly on other lines (the order of the lines is not significant).

It is an error to have two lines with the same file name or two lines starting with the character ‘*’.

After the file name or ‘*’, an optional literal string specifies the name of the definition file to be used for preprocessing (Form of Definitions File). The definition files are found by the compiler in one of the source directories. In some cases, when compiling a source in a directory other than the current directory, if the definition file is in the current directory, it may be necessary to add the current directory as a source directory through the -I switch; otherwise the compiler would not find the definition file.

Finally, switches similar to those of gnatprep may optionally appear:

-b

Causes both preprocessor lines and the lines deleted by preprocessing to be replaced by blank lines, preserving the line number. This switch is always implied; however, if specified after -c it cancels the effect of -c.

-c

Causes both preprocessor lines and the lines deleted by preprocessing to be retained as comments marked with the special string ‘–!’.

-D`symbol'=`new_value'

Define or redefine symbol to have new_value as its value. The permitted form for symbol is either an Ada identifier, or any Ada reserved word aside from if, else, elsif, end, and, or and then. The permitted form for new_value is a literal string, an Ada identifier or any Ada reserved word. A symbol declared with this switch replaces a symbol with the same name defined in a definition file.

-s

Causes a sorted list of symbol names and values to be listed on the standard output file.

-u

Causes undefined symbols to be treated as having the value FALSE in the context of a preprocessor test. In the absence of this option, an undefined symbol in a #if or #elsif test will be treated as an error.

-gnateD`symbol'[=`new_value']

Define or redefine symbol to have new_value as its value. If no value is supplied, then the value of symbol is True. The form of symbol is an identifier, following normal Ada (case-insensitive) rules for its syntax, and new_value is either an arbitrary string between double quotes or any sequence (including an empty sequence) of characters from the set (letters, digits, period, underline). Ada reserved words may be used as symbols, with the exceptions of if, else, elsif, end, and, or and then.

Examples:

-gnateDToto=Tata
-gnateDFoo
-gnateDFoo=\"Foo-Bar\"

A symbol declared with this switch on the command line replaces a symbol with the same name either in a definition file or specified with a switch -D in the preprocessor data file.

This switch is similar to switch -D of gnatprep.

-gnateG

When integrated preprocessing is performed on source file filename.extension, create or overwrite filename.extension.prep to contain the result of the preprocessing. For example if the source file is foo.adb then the output file will be foo.adb.prep.