| .. |with| replace:: *with* |
| .. |withs| replace:: *with*\ s |
| .. |withed| replace:: *with*\ ed |
| .. |withing| replace:: *with*\ ing |
| |
| .. -- Example: A |withing| unit has a |with| clause, it |withs| a |withed| unit |
| |
| |
| .. _The_GNAT_Compilation_Model: |
| |
| ************************** |
| The GNAT Compilation Model |
| ************************** |
| |
| .. index:: ! GNAT compilation model |
| |
| .. index:: 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 centralized program library. The chapter covers |
| the following material: |
| |
| * Topics related to source file makeup and naming |
| |
| * :ref:`Source_Representation` |
| * :ref:`Foreign_Language_Representation` |
| * :ref:`File_Naming_Topics_and_Utilities` |
| |
| * :ref:`Configuration_Pragmas` |
| * :ref:`Generating_Object_Files` |
| * :ref:`Source_Dependencies` |
| * :ref:`The_Ada_Library_Information_Files` |
| * :ref:`Binding_an_Ada_Program` |
| * :ref:`GNAT_and_Libraries` |
| * :ref:`Conditional_Compilation` |
| * :ref:`Mixed_Language_Programming` |
| * :ref:`GNAT_and_Other_Compilation_Models` |
| * :ref:`Using_GNAT_Files_with_External_Tools` |
| |
| |
| .. _Source_Representation: |
| |
| Source Representation |
| ===================== |
| |
| .. index:: Latin-1 |
| |
| .. index:: VT, HT, CR, LF, FF |
| |
| 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 :ref:`Foreign_Language_Representation` |
| for support of non-USA character sets). The format effector characters |
| are represented using their standard ASCII encodings, as follows: |
| |
| =========== ======================= ========= |
| Character Effect Code |
| ----------- ----------------------- --------- |
| :kbd:`VT` Vertical tab `16#0B#` |
| :kbd:`HT` Horizontal tab `16#09#` |
| :kbd:`CR` Carriage return `16#0D#` |
| :kbd:`LF` Line feed `16#0A#` |
| :kbd:`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 lines is marked by any of the following sequences: |
| `LF`, `CR`, `CR-LF`, or `LF-CR`. This is useful |
| in accommodating files that are imported from other operating systems. |
| |
| .. index:: pair: End of source file; Source file, end |
| |
| .. index:: SUB (control character) |
| |
| The end of a source file is normally represented by the physical end of |
| file. However, the control character `16#1A#` (:kbd:`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. |
| |
| .. index:: spec (definition), compilation (definition) |
| |
| 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: |
| |
| Foreign Language Representation |
| =============================== |
| |
| GNAT supports the standard character sets defined in Ada as well as |
| several other non-standard character sets for use in localized versions |
| of the compiler (:ref:`Character_Set_Control`). |
| |
| .. _Latin-1: |
| |
| Latin-1 |
| ------- |
| |
| .. index:: 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. |
| |
| .. index:: Ada.Characters.Latin_1 |
| |
| For a complete list of Latin-1 codes and their encodings, see the source |
| file of library unit `Ada.Characters.Latin_1` in file |
| :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: |
| |
| Other 8-Bit Codes |
| ----------------- |
| |
| GNAT also supports several other 8-bit coding schemes: |
| |
| |
| .. index:: Latin-2 |
| .. index:: ISO 8859-2 |
| |
| *ISO 8859-2 (Latin-2)* |
| Latin-2 letters allowed in identifiers, with uppercase and lowercase |
| equivalence. |
| |
| .. index:: Latin-3 |
| .. index:: ISO 8859-3 |
| |
| *ISO 8859-3 (Latin-3)* |
| Latin-3 letters allowed in identifiers, with uppercase and lowercase |
| equivalence. |
| |
| |
| .. index:: Latin-4 |
| .. index:: ISO 8859-4 |
| |
| *ISO 8859-4 (Latin-4)* |
| Latin-4 letters allowed in identifiers, with uppercase and lowercase |
| equivalence. |
| |
| |
| .. index:: ISO 8859-5 |
| .. index:: Cyrillic |
| |
| *ISO 8859-5 (Cyrillic)* |
| ISO 8859-5 letters (Cyrillic) allowed in identifiers, with uppercase and |
| lowercase equivalence. |
| |
| .. index:: ISO 8859-15 |
| .. index:: Latin-9 |
| |
| *ISO 8859-15 (Latin-9)* |
| ISO 8859-15 (Latin-9) letters allowed in identifiers, with uppercase and |
| lowercase equivalence |
| |
| .. index:: code page 437 (IBM PC) |
| |
| *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. |
| |
| .. index:: code page 850 (IBM PC) |
| |
| *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 :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: |
| |
| 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* |
| .. index:: 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* |
| .. index:: 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* |
| .. index:: 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#0`xxxxxxx`# |
| 16#0080#-16#07ff#: 2#110`xxxxx`# 2#10`xxxxxx`# |
| 16#0800#-16#ffff#: 2#1110`xxxx`# 2#10`xxxxxx`# 2#10`xxxxxx`# |
| |
| where the `xxx` bits correspond to the left-padded bits of 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, and in the following section on wide wide |
| characters, the use of these sequences is documented). |
| |
| |
| *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 some standard |
| ACATS (Ada Conformity Assessment Test Suite) test suite distributions. |
| |
| .. note:: |
| |
| Some of these coding schemes do not permit the full use of the |
| Ada character set. For example, neither Shift JIS nor EUC allow the |
| use of the upper half of the Latin-1 set. |
| |
| .. _Wide_Wide_Character_Encodings: |
| |
| Wide_Wide_Character Encodings |
| ----------------------------- |
| |
| GNAT allows wide wide character codes to appear in character and string |
| literals, and also optionally in identifiers, by means of the following |
| possible encoding schemes: |
| |
| *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 |
| of character codes with values greater than 16#FFFF# is a |
| is a four, five, or six byte sequence:: |
| |
| 16#01_0000#-16#10_FFFF#: 11110xxx 10xxxxxx 10xxxxxx |
| 10xxxxxx |
| 16#0020_0000#-16#03FF_FFFF#: 111110xx 10xxxxxx 10xxxxxx |
| 10xxxxxx 10xxxxxx |
| 16#0400_0000#-16#7FFF_FFFF#: 1111110x 10xxxxxx 10xxxxxx |
| 10xxxxxx 10xxxxxx 10xxxxxx |
| |
| |
| where the `xxx` bits correspond to the left-padded bits of the |
| 32-bit character value. |
| |
| *Brackets Coding* |
| In this encoding, a wide wide character is represented by the following ten or |
| twelve byte character sequence:: |
| |
| [ " a b c d e f " ] |
| [ " a b c d e f g h " ] |
| |
| where `a-h` are the six or eight hexadecimal |
| characters (using uppercase letters) of the wide wide character code. For |
| example, ["1F4567"] is used to represent the wide wide character with code |
| `16#001F_4567#`. |
| |
| This scheme is compatible with use of the full Wide_Wide_Character set, |
| and is also the method used for wide wide character encoding in some standard |
| ACATS (Ada Conformity Assessment Test Suite) test suite distributions. |
| |
| |
| .. _File_Naming_Topics_and_Utilities: |
| |
| File Naming Topics and Utilities |
| ================================ |
| |
| GNAT has a default file naming scheme and also provides the user with |
| a high degree of control over how the names and extensions of the |
| source files correspond to the Ada compilation units that they contain. |
| |
| |
| .. _File_Naming_Rules: |
| |
| 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 :file:`.ads` for a spec and |
| :file:`.adb` for a body. The following table shows some |
| examples of these rules. |
| |
| ============================ =============================== |
| Source File Ada Compilation Unit |
| ---------------------------- ------------------------------- |
| :file:`main.ads` Main (spec) |
| :file:`main.adb` Main (body) |
| :file:`arith_functions.ads` Arith_Functions (package spec) |
| :file:`arith_functions.adb` Arith_Functions (package body) |
| :file:`func-spec.ads` Func.Spec (child package spec) |
| :file:`func-spec.adb` Func.Spec (child package body) |
| :file:`main-sub.adb` Sub (subunit of Main) |
| :file:`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. :ref:`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. |
| (For details see :ref:`Renaming_Files_with_gnatchop`.) |
| |
| Note: in the case of Windows or Mac OS operating systems, case is not |
| significant. So for example on `Windows` if the canonical name is |
| `main-sub.adb`, you can use the file name :file:`Main-Sub.adb` instead. |
| However, case is significant for other operating systems, so for example, |
| if you want to use other than canonically cased file names on a Unix system, |
| you need to follow the procedures described in the next section. |
| |
| .. _Using_Other_File_Names: |
| |
| Using Other File Names |
| ---------------------- |
| |
| .. index:: 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. |
| |
| .. index:: Source_File_Name pragma |
| |
| 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: |
| |
| .. code-block:: ada |
| |
| 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 :file:`gnat.adc` |
| file used to hold configuration |
| pragmas that apply to a complete compilation environment. |
| For more details on how the :file:`gnat.adc` file is created and used |
| see :ref:`Handling_of_Configuration_Pragmas`. |
| |
| .. index:: gnat.adc |
| |
| 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 :file:`.ads` or :file:`.adb` it is necessary 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 and the name |
| of the language, here `ada`, as in: |
| |
| .. code-block:: sh |
| |
| $ gcc -c -x ada 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. |
| |
| .. _Alternative_File_Naming_Schemes: |
| |
| Alternative File Naming Schemes |
| ------------------------------- |
| |
| .. index:: File naming schemes, alternative |
| |
| .. index:: File names |
| |
| The previous section described the use of the `Source_File_Name` |
| pragma to allow arbitrary names to be assigned to individual source files. |
| However, this approach requires one pragma for each file, and especially in |
| large systems can result in very long :file:`gnat.adc` files, and also create |
| a maintenance problem. |
| |
| .. index:: Source_File_Name pragma |
| |
| GNAT also provides a facility for specifying systematic file naming schemes |
| other than the standard default naming scheme previously described. An |
| alternative scheme for naming is specified by the use of |
| `Source_File_Name` pragmas having the following format: |
| |
| .. code-block:: ada |
| |
| pragma Source_File_Name ( |
| Spec_File_Name => FILE_NAME_PATTERN |
| [ , Casing => CASING_SPEC] |
| [ , Dot_Replacement => STRING_LITERAL ] ); |
| |
| pragma Source_File_Name ( |
| Body_File_Name => FILE_NAME_PATTERN |
| [ , Casing => CASING_SPEC ] |
| [ , Dot_Replacement => STRING_LITERAL ] ) ; |
| |
| pragma Source_File_Name ( |
| Subunit_File_Name => FILE_NAME_PATTERN |
| [ , Casing => CASING_SPEC ] |
| [ , Dot_Replacement => STRING_LITERAL ] ) ; |
| |
| FILE_NAME_PATTERN ::= STRING_LITERAL |
| CASING_SPEC ::= Lowercase | Uppercase | Mixedcase |
| |
| The `FILE_NAME_PATTERN` string shows how the file name is constructed. |
| It contains a single asterisk character, and the unit name is substituted |
| systematically for this asterisk. The optional parameter |
| `Casing` indicates |
| whether the unit name is to be all upper-case letters, all lower-case letters, |
| or mixed-case. If no |
| `Casing` parameter is used, then the default is all |
| lower-case. |
| |
| The optional `Dot_Replacement` string is used to replace any periods |
| that occur in subunit or child unit names. If no `Dot_Replacement` |
| argument is used then separating dots appear unchanged in the resulting |
| file name. |
| Although the above syntax indicates that the |
| `Casing` argument must appear |
| before the `Dot_Replacement` argument, but it |
| is also permissible to write these arguments in the opposite order. |
| |
| As indicated, it is possible to specify different naming schemes for |
| bodies, specs, and subunits. Quite often the rule for subunits is the |
| same as the rule for bodies, in which case, there is no need to give |
| a separate `Subunit_File_Name` rule, and in this case the |
| `Body_File_name` rule is used for subunits as well. |
| |
| The separate rule for subunits can also be used to implement the rather |
| unusual case of a compilation environment (e.g., a single directory) which |
| contains a subunit and a child unit with the same unit name. Although |
| both units cannot appear in the same partition, the Ada Reference Manual |
| allows (but does not require) the possibility of the two units coexisting |
| in the same environment. |
| |
| The file name translation works in the following steps: |
| |
| * If there is a specific `Source_File_Name` pragma for the given unit, |
| then this is always used, and any general pattern rules are ignored. |
| |
| * If there is a pattern type `Source_File_Name` pragma that applies to |
| the unit, then the resulting file name will be used if the file exists. If |
| more than one pattern matches, the latest one will be tried first, and the |
| first attempt resulting in a reference to a file that exists will be used. |
| |
| * If no pattern type `Source_File_Name` pragma that applies to the unit |
| for which the corresponding file exists, then the standard GNAT default |
| naming rules are used. |
| |
| As an example of the use of this mechanism, consider a commonly used scheme |
| in which file names are all lower case, with separating periods copied |
| unchanged to the resulting file name, and specs end with :file:`.1.ada`, and |
| bodies end with :file:`.2.ada`. GNAT will follow this scheme if the following |
| two pragmas appear: |
| |
| .. code-block:: ada |
| |
| pragma Source_File_Name |
| (Spec_File_Name => ".1.ada"); |
| pragma Source_File_Name |
| (Body_File_Name => ".2.ada"); |
| |
| The default GNAT scheme is actually implemented by providing the following |
| default pragmas internally: |
| |
| .. code-block:: ada |
| |
| pragma Source_File_Name |
| (Spec_File_Name => ".ads", Dot_Replacement => "-"); |
| pragma Source_File_Name |
| (Body_File_Name => ".adb", Dot_Replacement => "-"); |
| |
| Our final example implements a scheme typically used with one of the |
| Ada 83 compilers, where the separator character for subunits was '__' |
| (two underscores), specs were identified by adding :file:`_.ADA`, bodies |
| by adding :file:`.ADA`, and subunits by |
| adding :file:`.SEP`. All file names were |
| upper case. Child units were not present of course since this was an |
| Ada 83 compiler, but it seems reasonable to extend this scheme to use |
| the same double underscore separator for child units. |
| |
| .. code-block:: ada |
| |
| pragma Source_File_Name |
| (Spec_File_Name => "_.ADA", |
| Dot_Replacement => "__", |
| Casing = Uppercase); |
| pragma Source_File_Name |
| (Body_File_Name => ".ADA", |
| Dot_Replacement => "__", |
| Casing = Uppercase); |
| pragma Source_File_Name |
| (Subunit_File_Name => ".SEP", |
| Dot_Replacement => "__", |
| Casing = Uppercase); |
| |
| |
| .. index:: ! gnatname |
| |
| .. _Handling_Arbitrary_File_Naming_Conventions_with_gnatname: |
| |
| Handling Arbitrary File Naming Conventions with `gnatname` |
| ---------------------------------------------------------- |
| |
| .. index:: File Naming Conventions |
| |
| .. _Arbitrary_File_Naming_Conventions: |
| |
| Arbitrary File Naming Conventions |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| The GNAT compiler must be able to know the source file name of a compilation |
| unit. When using the standard GNAT default file naming conventions |
| (`.ads` for specs, `.adb` for bodies), the GNAT compiler |
| does not need additional information. |
| |
| When the source file names do not follow the standard GNAT default file naming |
| conventions, the GNAT compiler must be given additional information through |
| a configuration pragmas file (:ref:`Configuration_Pragmas`) |
| or a project file. |
| When the non-standard file naming conventions are well-defined, |
| a small number of pragmas `Source_File_Name` specifying a naming pattern |
| (:ref:`Alternative_File_Naming_Schemes`) may be sufficient. However, |
| if the file naming conventions are irregular or arbitrary, a number |
| of pragma `Source_File_Name` for individual compilation units |
| must be defined. |
| To help maintain the correspondence between compilation unit names and |
| source file names within the compiler, |
| GNAT provides a tool `gnatname` to generate the required pragmas for a |
| set of files. |
| |
| .. _Running_gnatname: |
| |
| Running `gnatname` |
| ^^^^^^^^^^^^^^^^^^ |
| |
| The usual form of the `gnatname` command is: |
| |
| .. code-block:: sh |
| |
| $ gnatname [`switches`] `naming_pattern` [`naming_patterns`] |
| [--and [`switches`] `naming_pattern` [`naming_patterns`]] |
| |
| |
| All of the arguments are optional. If invoked without any argument, |
| `gnatname` will display its usage. |
| |
| When used with at least one naming pattern, `gnatname` will attempt to |
| find all the compilation units in files that follow at least one of the |
| naming patterns. To find these compilation units, |
| `gnatname` will use the GNAT compiler in syntax-check-only mode on all |
| regular files. |
| |
| One or several Naming Patterns may be given as arguments to `gnatname`. |
| Each Naming Pattern is enclosed between double quotes (or single |
| quotes on Windows). |
| A Naming Pattern is a regular expression similar to the wildcard patterns |
| used in file names by the Unix shells or the DOS prompt. |
| |
| `gnatname` may be called with several sections of directories/patterns. |
| Sections are separated by switch `--and`. In each section, there must be |
| at least one pattern. If no directory is specified in a section, the current |
| directory (or the project directory is `-P` is used) is implied. |
| The options other that the directory switches and the patterns apply globally |
| even if they are in different sections. |
| |
| Examples of Naming Patterns are:: |
| |
| "*.[12].ada" |
| "*.ad[sb]*" |
| "body_*" "spec_*" |
| |
| For a more complete description of the syntax of Naming Patterns, |
| see the second kind of regular expressions described in :file:`g-regexp.ads` |
| (the 'Glob' regular expressions). |
| |
| When invoked with no switch `-P`, `gnatname` will create a |
| configuration pragmas file :file:`gnat.adc` in the current working directory, |
| with pragmas `Source_File_Name` for each file that contains a valid Ada |
| unit. |
| |
| .. _Switches_for_gnatname: |
| |
| Switches for `gnatname` |
| ^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| Switches for `gnatname` must precede any specified Naming Pattern. |
| |
| You may specify any of the following switches to `gnatname`: |
| |
| .. index:: --version (gnatname) |
| |
| :samp:`--version` |
| Display Copyright and version, then exit disregarding all other options. |
| |
| .. index:: --help (gnatname) |
| |
| :samp:`--help` |
| If *--version* was not used, display usage, then exit disregarding |
| all other options. |
| |
| :samp:`--subdirs={dir}` |
| Real object, library or exec directories are subdirectories <dir> of the |
| specified ones. |
| |
| :samp:`--no-backup` |
| Do not create a backup copy of an existing project file. |
| |
| :samp:`--and` |
| Start another section of directories/patterns. |
| |
| .. index:: -c (gnatname) |
| |
| :samp:`-c{filename}` |
| Create a configuration pragmas file :file:`filename` (instead of the default |
| :file:`gnat.adc`). |
| There may be zero, one or more space between *-c* and |
| :file:`filename`. |
| :file:`filename` may include directory information. :file:`filename` must be |
| writable. There may be only one switch *-c*. |
| When a switch *-c* is |
| specified, no switch *-P* may be specified (see below). |
| |
| .. index:: -d (gnatname) |
| |
| :samp:`-d{dir}` |
| Look for source files in directory :file:`dir`. There may be zero, one or more |
| spaces between *-d* and :file:`dir`. |
| :file:`dir` may end with `/**`, that is it may be of the form |
| `root_dir/**`. In this case, the directory `root_dir` and all of its |
| subdirectories, recursively, have to be searched for sources. |
| When a switch *-d* |
| is specified, the current working directory will not be searched for source |
| files, unless it is explicitly specified with a *-d* |
| or *-D* switch. |
| Several switches *-d* may be specified. |
| If :file:`dir` is a relative path, it is relative to the directory of |
| the configuration pragmas file specified with switch |
| *-c*, |
| or to the directory of the project file specified with switch |
| *-P* or, |
| if neither switch *-c* |
| nor switch *-P* are specified, it is relative to the |
| current working directory. The directory |
| specified with switch *-d* must exist and be readable. |
| |
| .. index:: -D (gnatname) |
| |
| :samp:`-D{filename}` |
| Look for source files in all directories listed in text file :file:`filename`. |
| There may be zero, one or more spaces between *-D* |
| and :file:`filename`. |
| :file:`filename` must be an existing, readable text file. |
| Each nonempty line in :file:`filename` must be a directory. |
| Specifying switch *-D* is equivalent to specifying as many |
| switches *-d* as there are nonempty lines in |
| :file:`file`. |
| |
| :samp:`-eL` |
| Follow symbolic links when processing project files. |
| |
| .. index:: -f (gnatname) |
| |
| :samp:`-f{pattern}` |
| Foreign patterns. Using this switch, it is possible to add sources of languages |
| other than Ada to the list of sources of a project file. |
| It is only useful if a -P switch is used. |
| For example, |
| |
| .. code-block:: sh |
| |
| gnatname -Pprj -f"*.c" "*.ada" |
| |
| will look for Ada units in all files with the :file:`.ada` extension, |
| and will add to the list of file for project :file:`prj.gpr` the C files |
| with extension :file:`.c`. |
| |
| .. index:: -h (gnatname) |
| |
| :samp:`-h` |
| Output usage (help) information. The output is written to :file:`stdout`. |
| |
| .. index:: -P (gnatname) |
| |
| :samp:`-P{proj}` |
| Create or update project file :file:`proj`. There may be zero, one or more space |
| between *-P* and :file:`proj`. :file:`proj` may include directory |
| information. :file:`proj` must be writable. |
| There may be only one switch *-P*. |
| When a switch *-P* is specified, |
| no switch *-c* may be specified. |
| On all platforms, except on VMS, when `gnatname` is invoked for an |
| existing project file <proj>.gpr, a backup copy of the project file is created |
| in the project directory with file name <proj>.gpr.saved_x. 'x' is the first |
| non negative number that makes this backup copy a new file. |
| |
| .. index:: -v (gnatname) |
| |
| :samp:`-v` |
| Verbose mode. Output detailed explanation of behavior to :file:`stdout`. |
| This includes name of the file written, the name of the directories to search |
| and, for each file in those directories whose name matches at least one of |
| the Naming Patterns, an indication of whether the file contains a unit, |
| and if so the name of the unit. |
| |
| .. index:: -v -v (gnatname) |
| |
| :samp:`-v -v` |
| Very Verbose mode. In addition to the output produced in verbose mode, |
| for each file in the searched directories whose name matches none of |
| the Naming Patterns, an indication is given that there is no match. |
| |
| .. index:: -x (gnatname) |
| |
| :samp:`-x{pattern}` |
| Excluded patterns. Using this switch, it is possible to exclude some files |
| that would match the name patterns. For example, |
| |
| .. code-block:: sh |
| |
| gnatname -x "*_nt.ada" "*.ada" |
| |
| will look for Ada units in all files with the :file:`.ada` extension, |
| except those whose names end with :file:`_nt.ada`. |
| |
| |
| .. _Examples_of_gnatname_Usage: |
| |
| Examples of `gnatname` Usage |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| .. code-block:: sh |
| |
| $ gnatname -c /home/me/names.adc -d sources "[a-z]*.ada*" |
| |
| In this example, the directory :file:`/home/me` must already exist |
| and be writable. In addition, the directory |
| :file:`/home/me/sources` (specified by |
| *-d sources*) must exist and be readable. |
| |
| Note the optional spaces after *-c* and *-d*. |
| |
| .. code-block:: sh |
| |
| $ gnatname -P/home/me/proj -x "*_nt_body.ada" |
| -dsources -dsources/plus -Dcommon_dirs.txt "body_*" "spec_*" |
| |
| Note that several switches *-d* may be used, |
| even in conjunction with one or several switches |
| *-D*. Several Naming Patterns and one excluded pattern |
| are used in this example. |
| |
| |
| .. _File_Name_Krunching_with_gnatkr: |
| |
| File Name Krunching with `gnatkr` |
| --------------------------------- |
| |
| .. index:: ! gnatkr |
| |
| This chapter discusses the method used by the compiler to shorten |
| the default file names chosen for Ada units so that they do not |
| exceed the maximum length permitted. It also describes the |
| `gnatkr` utility that can be used to determine the result of |
| applying this shortening. |
| |
| .. _About_gnatkr: |
| |
| About `gnatkr` |
| ^^^^^^^^^^^^^^ |
| |
| The default file naming rule in GNAT |
| is that the file name must be derived from |
| the unit name. The exact default rule is as follows: |
| |
| * Take the unit name and replace all dots by hyphens. |
| |
| * If such a replacement occurs in the |
| second character position of a name, and the first character is |
| :samp:`a`, :samp:`g`, :samp:`s`, or :samp:`i`, |
| then replace the dot by the character |
| :samp:`~` (tilde) |
| instead of a minus. |
| |
| The reason for this exception is to avoid clashes |
| with the standard names for children of System, Ada, Interfaces, |
| and GNAT, which use the prefixes |
| :samp:`s-`, :samp:`a-`, :samp:`i-`, and :samp:`g-`, |
| respectively. |
| |
| The :samp:`-gnatk{nn}` |
| switch of the compiler activates a 'krunching' |
| circuit that limits file names to nn characters (where nn is a decimal |
| integer). |
| |
| The `gnatkr` utility can be used to determine the krunched name for |
| a given file, when krunched to a specified maximum length. |
| |
| .. _Using_gnatkr: |
| |
| Using `gnatkr` |
| ^^^^^^^^^^^^^^ |
| |
| The `gnatkr` command has the form: |
| |
| .. code-block:: sh |
| |
| $ gnatkr `name` [`length`] |
| |
| `name` is the uncrunched file name, derived from the name of the unit |
| in the standard manner described in the previous section (i.e., in particular |
| all dots are replaced by hyphens). The file name may or may not have an |
| extension (defined as a suffix of the form period followed by arbitrary |
| characters other than period). If an extension is present then it will |
| be preserved in the output. For example, when krunching :file:`hellofile.ads` |
| to eight characters, the result will be hellofil.ads. |
| |
| Note: for compatibility with previous versions of `gnatkr` dots may |
| appear in the name instead of hyphens, but the last dot will always be |
| taken as the start of an extension. So if `gnatkr` is given an argument |
| such as :file:`Hello.World.adb` it will be treated exactly as if the first |
| period had been a hyphen, and for example krunching to eight characters |
| gives the result :file:`hellworl.adb`. |
| |
| Note that the result is always all lower case. |
| Characters of the other case are folded as required. |
| |
| `length` represents the length of the krunched name. The default |
| when no argument is given is 8 characters. A length of zero stands for |
| unlimited, in other words do not chop except for system files where the |
| implied crunching length is always eight characters. |
| |
| The output is the krunched name. The output has an extension only if the |
| original argument was a file name with an extension. |
| |
| .. _Krunching_Method: |
| |
| Krunching Method |
| ^^^^^^^^^^^^^^^^ |
| |
| The initial 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, except that a hyphen in the second character position is |
| replaced by a tilde if the first character is |
| :samp:`a`, :samp:`i`, :samp:`g`, or :samp:`s`. |
| The extension is `.ads` for a |
| spec and `.adb` for a body. |
| Krunching does not affect the extension, but the file name is shortened to |
| the specified length by following these rules: |
| |
| * The name is divided into segments separated by hyphens, tildes or |
| underscores and all hyphens, tildes, and underscores are |
| eliminated. If this leaves the name short enough, we are done. |
| |
| * If the name is too long, the longest segment is located (left-most |
| if there are two of equal length), and shortened by dropping |
| its last character. This is repeated until the name is short enough. |
| |
| As an example, consider the krunching of :file:`our-strings-wide_fixed.adb` |
| to fit the name into 8 characters as required by some operating systems:: |
| |
| our-strings-wide_fixed 22 |
| our strings wide fixed 19 |
| our string wide fixed 18 |
| our strin wide fixed 17 |
| our stri wide fixed 16 |
| our stri wide fixe 15 |
| 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 file name: oustwifi.adb |
| |
| * The file names for all predefined units are always krunched to eight |
| characters. The krunching of these predefined units uses the following |
| special prefix replacements: |
| |
| ===================== ============== |
| Prefix Replacement |
| --------------------- -------------- |
| :file:`ada-` :file:`a-` |
| :file:`gnat-` :file:`g-` |
| :file:`interfac es-` :file:`i-` |
| :file:`system-` :file:`s-` |
| ===================== ============== |
| |
| These system files have a hyphen in the second character position. That |
| is why normal user files replace such a character with a |
| tilde, to avoid confusion with system file names. |
| |
| As an example of this special rule, consider |
| :file:`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 file name: a-stwifi.adb |
| |
| Of course no file shortening algorithm can guarantee uniqueness over all |
| possible unit names, and if file name krunching is used then it is your |
| responsibility to ensure that no name clashes occur. The utility |
| program `gnatkr` is supplied for conveniently determining the |
| krunched name of a file. |
| |
| .. _Examples_of_gnatkr_Usage: |
| |
| Examples of `gnatkr` Usage |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| :: |
| |
| $ gnatkr very_long_unit_name.ads --> velounna.ads |
| $ gnatkr grandparent-parent-child.ads --> grparchi.ads |
| $ gnatkr Grandparent.Parent.Child.ads --> grparchi.ads |
| $ gnatkr grandparent-parent-child --> grparchi |
| $ gnatkr very_long_unit_name.ads/count=6 --> vlunna.ads |
| $ gnatkr very_long_unit_name.ads/count=0 --> very_long_unit_name.ads |
| |
| |
| .. _Renaming_Files_with_gnatchop: |
| |
| Renaming Files with `gnatchop` |
| ------------------------------ |
| |
| .. index:: ! gnatchop |
| |
| This chapter discusses how to handle files with multiple units by using |
| the `gnatchop` utility. This utility is also useful in renaming |
| files to meet the standard GNAT default file naming conventions. |
| |
| .. _Handling_Files_with_Multiple_Units: |
| |
| Handling Files with Multiple Units |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| The basic compilation model of GNAT requires that a file submitted to the |
| compiler have only one unit and there 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 file names. `gnatchop` |
| reads the specified file and generates one or more output files, |
| containing one unit per file. The unit and the file name correspond, |
| 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. |
| |
| Note that if your file containing multiple units starts with a byte order |
| mark (BOM) specifying UTF-8 encoding, then the files generated by gnatchop |
| will each start with a copy of this BOM, meaning that they can be compiled |
| automatically in UTF-8 mode without needing to specify an explicit encoding. |
| |
| .. _Operating_gnatchop_in_Compilation_Mode: |
| |
| Operating gnatchop in Compilation Mode |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| The basic function of `gnatchop` is to take a file with multiple units |
| and split it into separate files. The boundary between files is reasonably |
| clear, except for the issue of comments and pragmas. In default mode, the |
| rule is that any pragmas between units belong to the previous unit, except |
| that configuration pragmas always belong to the following unit. Any comments |
| belong to the following unit. These rules |
| almost always result in the right choice of |
| the split point without needing to mark it explicitly and most users will |
| find this default to be what they want. In this default mode it is incorrect to |
| submit a file containing only configuration pragmas, or one that ends in |
| configuration pragmas, to `gnatchop`. |
| |
| However, using a special option to activate 'compilation mode', |
| `gnatchop` |
| can perform another function, which is to provide exactly the semantics |
| required by the RM for handling of configuration pragmas in a compilation. |
| In the absence of configuration pragmas (at the main file level), this |
| option has no effect, but it causes such configuration pragmas to be handled |
| in a quite different manner. |
| |
| First, in compilation mode, if `gnatchop` is given a file that consists of |
| only configuration pragmas, then this file is appended to the |
| :file:`gnat.adc` file in the current directory. This behavior provides |
| the required behavior described in the RM for the actions to be taken |
| on submitting such a file to the compiler, namely that these pragmas |
| should apply to all subsequent compilations in the same compilation |
| environment. Using GNAT, the current directory, possibly containing a |
| :file:`gnat.adc` file is the representation |
| of a compilation environment. For more information on the |
| :file:`gnat.adc` file, see :ref:`Handling_of_Configuration_Pragmas`. |
| |
| Second, in compilation mode, if `gnatchop` |
| is given a file that starts with |
| configuration pragmas, and contains one or more units, then these |
| configuration pragmas are prepended to each of the chopped files. This |
| behavior provides the required behavior described in the RM for the |
| actions to be taken on compiling such a file, namely that the pragmas |
| apply to all units in the compilation, but not to subsequently compiled |
| units. |
| |
| Finally, if configuration pragmas appear between units, they are appended |
| to the previous unit. This results in the previous unit being illegal, |
| since the compiler does not accept configuration pragmas that follow |
| a unit. This provides the required RM behavior that forbids configuration |
| pragmas other than those preceding the first compilation unit of a |
| compilation. |
| |
| For most purposes, `gnatchop` will be used in default mode. The |
| compilation mode described above is used only if you need exactly |
| accurate behavior with respect to compilations, and you have files |
| that contain multiple units and configuration pragmas. In this |
| circumstance the use of `gnatchop` with the compilation mode |
| switch provides the required behavior, and is for example the mode |
| in which GNAT processes the ACVC tests. |
| |
| |
| .. _Command_Line_for_gnatchop: |
| |
| Command Line for `gnatchop` |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| The `gnatchop` command has the form: |
| |
| .. code-block:: sh |
| |
| $ gnatchop switches file_name [file_name ...] |
| [directory] |
| |
| The only required argument is the file name of the file to be chopped. |
| There are no restrictions on the form of this file name. The file itself |
| contains one or more Ada units, in normal GNAT format, concatenated |
| together. As shown, more than one file may be presented to be chopped. |
| |
| When run in default mode, `gnatchop` generates one output file in |
| the current directory for each unit in each of the files. |
| |
| `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. |
| |
| For example, given a |
| file called :file:`hellofiles` containing |
| |
| .. code-block:: ada |
| |
| procedure Hello; |
| |
| with Ada.Text_IO; use Ada.Text_IO; |
| procedure Hello is |
| begin |
| Put_Line ("Hello"); |
| end Hello; |
| |
| the command |
| |
| .. code-block:: sh |
| |
| $ gnatchop hellofiles |
| |
| generates two files in the current directory, one called |
| :file:`hello.ads` containing the single line that is the procedure spec, |
| and the other called :file:`hello.adb` containing the remaining text. The |
| original file is not affected. The generated files can be compiled in |
| the normal manner. |
| |
| When gnatchop is invoked on a file that is empty or that contains only empty |
| lines and/or comments, gnatchop will not fail, but will not produce any |
| new sources. |
| |
| For example, given a |
| file called :file:`toto.txt` containing |
| |
| .. code-block:: ada |
| |
| -- Just a comment |
| |
| the command |
| |
| .. code-block:: sh |
| |
| $ gnatchop toto.txt |
| |
| will not produce any new file and will result in the following warnings:: |
| |
| toto.txt:1:01: warning: empty file, contains no compilation units |
| no compilation units found |
| no source files written |
| |
| |
| .. _Switches_for_gnatchop: |
| |
| Switches for `gnatchop` |
| ^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| *gnatchop* recognizes the following switches: |
| |
| |
| .. index:: --version (gnatchop) |
| |
| :samp:`--version` |
| Display Copyright and version, then exit disregarding all other options. |
| |
| .. index:: --help (gnatchop) |
| |
| :samp:`--help` |
| If *--version* was not used, display usage, then exit disregarding |
| all other options. |
| |
| .. index:: -c (gnatchop) |
| |
| :samp:`-c` |
| Causes `gnatchop` to operate in compilation mode, in which |
| configuration pragmas are handled according to strict RM rules. See |
| previous section for a full description of this mode. |
| |
| :samp:`-gnat{xxx}` |
| This passes the given *-gnat`xxx*` switch to `gnat` which is |
| used to parse the given file. Not all `xxx` options make sense, |
| but for example, the use of *-gnati2* allows `gnatchop` to |
| process a source file that uses Latin-2 coding for identifiers. |
| |
| :samp:`-h` |
| Causes `gnatchop` to generate a brief help summary to the standard |
| output file showing usage information. |
| |
| .. index:: -k (gnatchop) |
| |
| :samp:`-k{mm}` |
| Limit generated file names to the specified number `mm` |
| of characters. |
| This is useful if the |
| resulting set of files is required to be interoperable with systems |
| which limit the length of file names. |
| No space is allowed between the *-k* and the numeric value. The numeric |
| value may be omitted in which case a default of *-k8*, |
| suitable for use |
| with DOS-like file systems, is used. If no *-k* switch |
| is present then |
| there is no limit on the length of file names. |
| |
| .. index:: -p (gnatchop) |
| |
| :samp:`-p` |
| Causes the file modification time stamp of the input file to be |
| preserved and used for the time stamp of the output file(s). This may be |
| useful for preserving coherency of time stamps in an environment where |
| `gnatchop` is used as part of a standard build process. |
| |
| .. index:: -q (gnatchop) |
| |
| :samp:`-q` |
| Causes output of informational messages indicating the set of generated |
| files to be suppressed. Warnings and error messages are unaffected. |
| |
| .. index:: -r (gnatchop) |
| .. index:: Source_Reference pragmas |
| |
| :samp:`-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. This switch causes |
| `Source_Reference` pragmas to be inserted into each of the |
| generated files to refers back to the original file name 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. |
| |
| If the original file to be chopped itself contains |
| a `Source_Reference` |
| pragma referencing a third file, then gnatchop respects |
| this pragma, and the generated `Source_Reference` pragmas |
| in the chopped file refer to the original file, with appropriate |
| line numbers. This is particularly useful when `gnatchop` |
| is used in conjunction with `gnatprep` to compile files that |
| contain preprocessing statements and multiple units. |
| |
| .. index:: -v (gnatchop) |
| |
| :samp:`-v` |
| Causes `gnatchop` to operate in verbose mode. The version |
| number and copyright notice are output, as well as exact copies of |
| the gnat1 commands spawned to obtain the chop control information. |
| |
| .. index:: -w (gnatchop) |
| |
| :samp:`-w` |
| Overwrite existing file names. Normally `gnatchop` regards it as a |
| fatal error if there is already a file with the same name as a |
| file it would otherwise output, in other words if the files to be |
| chopped contain duplicated units. This switch bypasses this |
| check, and causes all but the last instance of such duplicated |
| units to be skipped. |
| |
| .. index:: --GCC= (gnatchop) |
| |
| :samp:`--GCC={xxxx}` |
| Specify the path of the GNAT parser to be used. When this switch is used, |
| no attempt is made to add the prefix to the GNAT parser executable. |
| |
| |
| .. _Examples_of_gnatchop_Usage: |
| |
| Examples of `gnatchop` Usage |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| .. code-block:: sh |
| |
| $ gnatchop -w hello_s.ada prerelease/files |
| |
| Chops the source file :file:`hello_s.ada`. The output files will be |
| placed in the directory :file:`prerelease/files`, |
| overwriting any |
| files with matching names in that directory (no files in the current |
| directory are modified). |
| |
| .. code-block:: sh |
| |
| $ gnatchop archive |
| |
| Chops the source file :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. |
| |
| .. code-block:: sh |
| |
| $ gnatchop file1 file2 file3 direc |
| |
| Chops all units in files :file:`file1`, :file:`file2`, :file:`file3`, placing |
| the resulting files in the directory :file:`direc`. Note that if any units |
| occur more than once anywhere within this set of files, an error message |
| is generated, and no files are written. To override this check, use the |
| *-w* switch, |
| in which case the last occurrence in the last file will |
| be the one that is output, and earlier duplicate occurrences for a given |
| unit will be skipped. |
| |
| .. _Configuration_Pragmas: |
| |
| Configuration Pragmas |
| ===================== |
| |
| .. index:: Configuration pragmas |
| |
| .. index:: Pragmas, configuration |
| |
| Configuration pragmas include those pragmas described as |
| such in the Ada Reference Manual, as well as |
| implementation-dependent pragmas that are configuration pragmas. |
| See the `Implementation_Defined_Pragmas` chapter in the |
| :title:`GNAT_Reference_Manual` for details on these |
| additional GNAT-specific configuration pragmas. |
| Most notably, the pragma `Source_File_Name`, which allows |
| specifying non-default names for source files, is a configuration |
| pragma. The following is a complete list of configuration pragmas |
| recognized by GNAT:: |
| |
| Ada_83 |
| Ada_95 |
| Ada_05 |
| Ada_2005 |
| Ada_12 |
| Ada_2012 |
| Allow_Integer_Address |
| Annotate |
| Assertion_Policy |
| Assume_No_Invalid_Values |
| C_Pass_By_Copy |
| Check_Name |
| Check_Policy |
| Compile_Time_Error |
| Compile_Time_Warning |
| Compiler_Unit |
| Component_Alignment |
| Convention_Identifier |
| Debug_Policy |
| Detect_Blocking |
| Default_Storage_Pool |
| Discard_Names |
| Elaboration_Checks |
| Eliminate |
| Extend_System |
| Extensions_Allowed |
| External_Name_Casing |
| Fast_Math |
| Favor_Top_Level |
| Float_Representation |
| Implicit_Packing |
| Initialize_Scalars |
| Interrupt_State |
| License |
| Locking_Policy |
| Long_Float |
| No_Run_Time |
| No_Strict_Aliasing |
| Normalize_Scalars |
| Optimize_Alignment |
| Persistent_BSS |
| Polling |
| Priority_Specific_Dispatching |
| Profile |
| Profile_Warnings |
| Propagate_Exceptions |
| Queuing_Policy |
| Ravenscar |
| Restricted_Run_Time |
| Restrictions |
| Restrictions_Warnings |
| Reviewable |
| Short_Circuit_And_Or |
| Source_File_Name |
| Source_File_Name_Project |
| SPARK_Mode |
| Style_Checks |
| Suppress |
| Suppress_Exception_Locations |
| Task_Dispatching_Policy |
| Universal_Data |
| Unsuppress |
| Use_VADS_Size |
| Validity_Checks |
| Warnings |
| Wide_Character_Encoding |
| |
| |
| .. _Handling_of_Configuration_Pragmas: |
| |
| Handling of Configuration Pragmas |
| --------------------------------- |
| |
| Configuration pragmas may either appear at the start of a compilation |
| unit, or they can appear in a configuration pragma file to apply to |
| all compilations performed in a given compilation environment. |
| |
| GNAT also provides the `gnatchop` utility to provide an automatic |
| way to handle configuration pragmas following the semantics for |
| compilations (that is, files with multiple units), described in the RM. |
| See :ref:`Operating_gnatchop_in_Compilation_Mode` for details. |
| However, for most purposes, it will be more convenient to edit the |
| :file:`gnat.adc` file that contains configuration pragmas directly, |
| as described in the following section. |
| |
| In the case of `Restrictions` pragmas appearing as configuration |
| pragmas in individual compilation units, the exact handling depends on |
| the type of restriction. |
| |
| Restrictions that require partition-wide consistency (like |
| `No_Tasking`) are |
| recognized wherever they appear |
| and can be freely inherited, e.g. from a |withed| unit to the |withing| |
| unit. This makes sense since the binder will in any case insist on seeing |
| consistent use, so any unit not conforming to any restrictions that are |
| anywhere in the partition will be rejected, and you might as well find |
| that out at compile time rather than at bind time. |
| |
| For restrictions that do not require partition-wide consistency, e.g. |
| SPARK or No_Implementation_Attributes, in general the restriction applies |
| only to the unit in which the pragma appears, and not to any other units. |
| |
| The exception is No_Elaboration_Code which always applies to the entire |
| object file from a compilation, i.e. to the body, spec, and all subunits. |
| This restriction can be specified in a configuration pragma file, or it |
| can be on the body and/or the spec (in eithe case it applies to all the |
| relevant units). It can appear on a subunit only if it has previously |
| appeared in the body of spec. |
| |
| |
| .. _The_Configuration_Pragmas_Files: |
| |
| The Configuration Pragmas Files |
| ------------------------------- |
| |
| .. index:: gnat.adc |
| |
| In GNAT a compilation environment is defined by the current |
| directory at the time that a compile command is given. This current |
| directory is searched for a file whose name is :file:`gnat.adc`. If |
| this file is present, it is expected to contain one or more |
| configuration pragmas that will be applied to the current compilation. |
| However, if the switch *-gnatA* is used, :file:`gnat.adc` is not |
| considered. When taken into account, :file:`gnat.adc` is added to the |
| dependencies, so that if :file:`gnat.adc` is modified later, an invocation of |
| *gnatmake* will recompile the source. |
| |
| Configuration pragmas may be entered into the :file:`gnat.adc` file |
| either by running `gnatchop` on a source file that consists only of |
| configuration pragmas, or more conveniently by direct editing of the |
| :file:`gnat.adc` file, which is a standard format source file. |
| |
| Besides :file:`gnat.adc`, additional files containing configuration |
| pragmas may be applied to the current compilation using the switch |
| :samp:`-gnatec={path}` where `path` must designate an existing file that |
| contains only configuration pragmas. These configuration pragmas are |
| in addition to those found in :file:`gnat.adc` (provided :file:`gnat.adc` |
| is present and switch *-gnatA* is not used). |
| |
| It is allowable to specify several switches *-gnatec=*, all of which |
| will be taken into account. |
| |
| Files containing configuration pragmas specified with switches |
| *-gnatec=* are added to the dependencies, unless they are |
| temporary files. A file is considered temporary if its name ends in |
| :file:`.tmp` or :file:`.TMP`. Certain tools follow this naming |
| convention because they pass information to *gcc* via |
| temporary files that are immediately deleted; it doesn't make sense to |
| depend on a file that no longer exists. Such tools include |
| *gprbuild*, *gnatmake*, and *gnatcheck*. |
| |
| If you are using project file, a separate mechanism is provided using |
| project attributes, see :ref:`Specifying_Configuration_Pragmas` for more |
| details. |
| |
| |
| .. _Generating_Object_Files: |
| |
| 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: |
| |
| * If a package spec has no body, compile the package spec to produce the |
| object file for the package. |
| |
| * If a package has both a spec and a body, compile the body to produce the |
| object file for the package. The source file for the package spec need |
| not be compiled in this case because there is only one object file, which |
| contains the code for both the spec and body of the package. |
| |
| * For a subprogram, compile the subprogram body to produce the object file |
| for the subprogram. The spec, if one is present, is as usual in a |
| separate file, and need not be compiled. |
| |
| .. index:: Subunits |
| |
| * In the case of subunits, only compile the parent unit. A single object |
| file is generated for the entire subunit tree, which includes all the |
| subunits. |
| |
| * Compile child units independently of their parent units |
| (though, of course, the spec of all the ancestor unit must be present in order |
| to compile a child unit). |
| |
| .. index:: Generics |
| |
| * Compile generic units in the same manner as any other units. The object |
| files in this case are small dummy files that contain at most the |
| flag used for elaboration checking. This is because GNAT always handles generic |
| instantiation by means of macro expansion. However, it is still necessary to |
| compile generic units, for dependency checking and elaboration purposes. |
| |
| 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 |
| :file:`.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: |
| |
| 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: |
| |
| * If a file being compiled |withs| a unit `X`, the object file |
| depends on the file containing the spec of unit `X`. This includes |
| files that are |withed| implicitly either because they are parents |
| of |withed| child units or they are run-time units required by the |
| language constructs used in a particular unit. |
| |
| * If a file being compiled instantiates a library level generic unit, the |
| object file depends on both the spec and body files for this generic |
| unit. |
| |
| * If a file being compiled instantiates a generic unit defined within a |
| package, the object file depends on the body file for the package as |
| well as the spec file. |
| |
| .. index:: Inline |
| .. index:: -gnatn switch |
| |
| * If a file being compiled contains a call to a subprogram for which |
| pragma `Inline` applies and inlining is activated with the |
| *-gnatn* switch, the object file depends on the file containing the |
| body of this subprogram as well as on the file containing the spec. Note |
| that for inlining to actually occur as a result of the use of this switch, |
| it is necessary to compile in optimizing mode. |
| |
| .. index:: -gnatN switch |
| |
| The use of *-gnatN* activates inlining optimization |
| that is performed by the front end of the compiler. This inlining does |
| not require that the code generation be optimized. Like *-gnatn*, |
| the use of this switch generates additional dependencies. |
| |
| When using a gcc-based back end (in practice this means using any version |
| of GNAT other than for the JVM, .NET or GNAAMP platforms), then the use of |
| *-gnatN* is deprecated, and the use of *-gnatn* is preferred. |
| Historically front end inlining was more extensive than the gcc back end |
| inlining, but that is no longer the case. |
| |
| * If an object file :file:`O` depends on the proper body of a subunit through |
| inlining or instantiation, it depends on the parent unit of the subunit. |
| This means that any modification of the parent unit or one of its subunits |
| affects the compilation of :file:`O`. |
| |
| * The object file for a parent unit depends on all its subunit body files. |
| |
| * The previous two rules meant that for purposes of computing dependencies and |
| recompilation, a body and all its subunits are treated as an indivisible whole. |
| |
| These rules are applied transitively: if unit `A` |withs| |
| 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 :file:`c.adb`. |
| |
| The set of dependent files described by these rules includes all the |
| files on which the unit is semantically dependent, as dictated by the |
| Ada language standard. However, it is a superset of what the |
| standard 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: |
| |
| The Ada Library Information Files |
| ================================= |
| |
| .. index:: Ada Library Information files |
| |
| .. index:: ALI files |
| |
| Each compilation actually generates two output files. The first of these |
| is the normal object file that has a :file:`.o` extension. The second is a |
| text file containing full dependency information. It has the same |
| name as the source file, but an :file:`.ali` extension. |
| This file is known as the Ada Library Information (:file:`ALI`) file. |
| The following information is contained in the :file:`ALI` file. |
| |
| * Version information (indicates which version of GNAT was used to compile |
| the unit(s) in question) |
| |
| * Main program information (including priority and time slice settings, |
| as well as the wide character encoding used during compilation). |
| |
| * List of arguments used in the *gcc* command for the compilation |
| |
| * Attributes of the unit, including configuration pragmas used, an indication |
| of whether the compilation was successful, exception model used etc. |
| |
| * A list of relevant restrictions applying to the unit (used for consistency) |
| checking. |
| |
| * Categorization information (e.g., use of pragma `Pure`). |
| |
| * Information on all |withed| units, including presence of |
| Elaborate` or `Elaborate_All` pragmas. |
| |
| * Information from any `Linker_Options` pragmas used in the unit |
| |
| * Information on the use of `Body_Version` or `Version` |
| attributes in the unit. |
| |
| * Dependency information. This is a list of files, together with |
| time stamp and checksum information. These are files on which |
| the unit depends in the sense that recompilation is required |
| if any of these units are modified. |
| |
| * Cross-reference data. Contains information on all entities referenced |
| in the unit. Used by tools like `gnatxref` and `gnatfind` to |
| provide cross-reference information. |
| |
| For a full detailed description of the format of the :file:`ALI` file, |
| see the source of the body of unit `Lib.Writ`, contained in file |
| :file:`lib-writ.adb` in the GNAT compiler sources. |
| |
| |
| .. _Binding_an_Ada_Program: |
| |
| 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 Ada by |
| default, that contains calls to the elaboration procedures of those |
| compilation unit that require them, followed by |
| a call to the main program. This Ada program is compiled to generate the |
| object file for the main program. The name of |
| the Ada file is :file:`b~xxx`.adb` (with the corresponding spec |
| :file:`b~xxx`.ads`) where `xxx` is the name of the |
| main program unit. |
| |
| 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. |
| |
| |
| .. _GNAT_and_Libraries: |
| |
| GNAT and Libraries |
| ================== |
| |
| .. index:: Library building and using |
| |
| This chapter describes how to build and use libraries with GNAT, and also shows |
| how to recompile the GNAT run-time library. You should be familiar with the |
| Project Manager facility (:ref:`GNAT_Project_Manager`) before reading this |
| chapter. |
| |
| .. _Introduction_to_Libraries_in_GNAT: |
| |
| Introduction to Libraries in GNAT |
| --------------------------------- |
| |
| A library is, conceptually, a collection of objects which does not have its |
| own main thread of execution, but rather provides certain services to the |
| applications that use it. A library can be either statically linked with the |
| application, in which case its code is directly included in the application, |
| or, on platforms that support it, be dynamically linked, in which case |
| its code is shared by all applications making use of this library. |
| |
| GNAT supports both types of libraries. |
| In the static case, the compiled code can be provided in different ways. The |
| simplest approach is to provide directly the set of objects resulting from |
| compilation of the library source files. Alternatively, you can group the |
| objects into an archive using whatever commands are provided by the operating |
| system. For the latter case, the objects are grouped into a shared library. |
| |
| In the GNAT environment, a library has three types of components: |
| |
| * Source files, |
| |
| * :file:`ALI` files (see :ref:`The_Ada_Library_Information_Files`), and |
| |
| * Object files, an archive or a shared library. |
| |
| A GNAT library may expose all its source files, which is useful for |
| documentation purposes. Alternatively, it may expose only the units needed by |
| an external user to make use of the library. That is to say, the specs |
| reflecting the library services along with all the units needed to compile |
| those specs, which can include generic bodies or any body implementing an |
| inlined routine. In the case of *stand-alone libraries* those exposed |
| units are called *interface units* (:ref:`Stand-alone_Ada_Libraries`). |
| |
| All compilation units comprising an application, including those in a library, |
| need to be elaborated in an order partially defined by Ada's semantics. GNAT |
| computes the elaboration order from the :file:`ALI` files and this is why they |
| constitute a mandatory part of GNAT libraries. |
| *Stand-alone libraries* are the exception to this rule because a specific |
| library elaboration routine is produced independently of the application(s) |
| using the library. |
| |
| .. _General_Ada_Libraries: |
| |
| General Ada Libraries |
| --------------------- |
| |
| |
| .. _Building_a_library: |
| |
| Building a library |
| ^^^^^^^^^^^^^^^^^^ |
| |
| The easiest way to build a library is to use the Project Manager, |
| which supports a special type of project called a *Library Project* |
| (see :ref:`Library_Projects`). |
| |
| A project is considered a library project, when two project-level attributes |
| are defined in it: `Library_Name` and `Library_Dir`. In order to |
| control different aspects of library configuration, additional optional |
| project-level attributes can be specified: |
| |
| * *Library_Kind* |
| This attribute controls whether the library is to be static or dynamic |
| |
| |
| * *Library_Version* |
| This attribute specifies the library version; this value is used |
| during dynamic linking of shared libraries to determine if the currently |
| installed versions of the binaries are compatible. |
| |
| * *Library_Options* |
| |
| * *Library_GCC* |
| These attributes specify additional low-level options to be used during |
| library generation, and redefine the actual application used to generate |
| library. |
| |
| The GNAT Project Manager takes full care of the library maintenance task, |
| including recompilation of the source files for which objects do not exist |
| or are not up to date, assembly of the library archive, and installation of |
| the library (i.e., copying associated source, object and :file:`ALI` files |
| to the specified location). |
| |
| Here is a simple library project file: |
| |
| .. code-block:: gpr |
| |
| project My_Lib is |
| for Source_Dirs use ("src1", "src2"); |
| for Object_Dir use "obj"; |
| for Library_Name use "mylib"; |
| for Library_Dir use "lib"; |
| for Library_Kind use "dynamic"; |
| end My_lib; |
| |
| and the compilation command to build and install the library: |
| |
| .. code-block:: sh |
| |
| $ gnatmake -Pmy_lib |
| |
| It is not entirely trivial to perform manually all the steps required to |
| produce a library. We recommend that you use the GNAT Project Manager |
| for this task. In special cases where this is not desired, the necessary |
| steps are discussed below. |
| |
| There are various possibilities for compiling the units that make up the |
| library: for example with a Makefile (:ref:`Using_the_GNU_make_Utility`) or |
| with a conventional script. For simple libraries, it is also possible to create |
| a dummy main program which depends upon all the packages that comprise the |
| interface of the library. This dummy main program can then be given to |
| *gnatmake*, which will ensure that all necessary objects are built. |
| |
| After this task is accomplished, you should follow the standard procedure |
| of the underlying operating system to produce the static or shared library. |
| |
| Here is an example of such a dummy program: |
| |
| .. code-block:: ada |
| |
| with My_Lib.Service1; |
| with My_Lib.Service2; |
| with My_Lib.Service3; |
| procedure My_Lib_Dummy is |
| begin |
| null; |
| end; |
| |
| Here are the generic commands that will build an archive or a shared library. |
| |
| .. code-block:: sh |
| |
| # compiling the library |
| $ gnatmake -c my_lib_dummy.adb |
| |
| # we don't need the dummy object itself |
| $ rm my_lib_dummy.o my_lib_dummy.ali |
| |
| # create an archive with the remaining objects |
| $ ar rc libmy_lib.a *.o |
| # some systems may require "ranlib" to be run as well |
| |
| # or create a shared library |
| $ gcc -shared -o libmy_lib.so *.o |
| # some systems may require the code to have been compiled with -fPIC |
| |
| # remove the object files that are now in the library |
| $ rm *.o |
| |
| # Make the ALI files read-only so that gnatmake will not try to |
| # regenerate the objects that are in the library |
| $ chmod -w *.ali |
| |
| Please note that the library must have a name of the form :file:`lib{xxx}.a` |
| or :file:`lib{xxx}.so` (or :file:`lib{xxx}.dll` on Windows) in order to |
| be accessed by the directive :samp:`-l{xxx}` at link time. |
| |
| .. _Installing_a_library: |
| |
| Installing a library |
| ^^^^^^^^^^^^^^^^^^^^ |
| |
| .. index:: ADA_PROJECT_PATH |
| .. index:: GPR_PROJECT_PATH |
| |
| If you use project files, library installation is part of the library build |
| process (:ref:`Installing_a_library_with_project_files`). |
| |
| When project files are not an option, it is also possible, but not recommended, |
| to install the library so that the sources needed to use the library are on the |
| Ada source path and the ALI files & libraries be on the Ada Object path (see |
| :ref:`Search_Paths_and_the_Run-Time_Library_RTL`. Alternatively, the system |
| administrator can place general-purpose libraries in the default compiler |
| paths, by specifying the libraries' location in the configuration files |
| :file:`ada_source_path` and :file:`ada_object_path`. These configuration files |
| must be located in the GNAT installation tree at the same place as the gcc spec |
| file. The location of the gcc spec file can be determined as follows: |
| |
| .. code-block:: sh |
| |
| $ gcc -v |
| |
| |
| The configuration files mentioned above have a simple format: each line |
| must contain one unique directory name. |
| Those names are added to the corresponding path |
| in their order of appearance in the file. The names can be either absolute |
| or relative; in the latter case, they are relative to where theses files |
| are located. |
| |
| The files :file:`ada_source_path` and :file:`ada_object_path` might not be |
| present in a |
| GNAT installation, in which case, GNAT will look for its run-time library in |
| the directories :file:`adainclude` (for the sources) and :file:`adalib` (for the |
| objects and :file:`ALI` files). When the files exist, the compiler does not |
| look in :file:`adainclude` and :file:`adalib`, and thus the |
| :file:`ada_source_path` file |
| must contain the location for the GNAT run-time sources (which can simply |
| be :file:`adainclude`). In the same way, the :file:`ada_object_path` file must |
| contain the location for the GNAT run-time objects (which can simply |
| be :file:`adalib`). |
| |
| You can also specify a new default path to the run-time library at compilation |
| time with the switch *--RTS=rts-path*. You can thus choose / change |
| the run-time library you want your program to be compiled with. This switch is |
| recognized by *gcc*, *gnatmake*, *gnatbind*, |
| *gnatls*, *gnatfind* and *gnatxref*. |
| |
| It is possible to install a library before or after the standard GNAT |
| library, by reordering the lines in the configuration files. In general, a |
| library must be installed before the GNAT library if it redefines |
| any part of it. |
| |
| .. _Using_a_library: |
| |
| Using a library |
| ^^^^^^^^^^^^^^^ |
| |
| Once again, the project facility greatly simplifies the use of |
| libraries. In this context, using a library is just a matter of adding a |
| |with| clause in the user project. For instance, to make use of the |
| library `My_Lib` shown in examples in earlier sections, you can |
| write: |
| |
| .. code-block:: gpr |
| |
| with "my_lib"; |
| project My_Proj is |
| ... |
| end My_Proj; |
| |
| Even if you have a third-party, non-Ada library, you can still use GNAT's |
| Project Manager facility to provide a wrapper for it. For example, the |
| following project, when |withed| by your main project, will link with the |
| third-party library :file:`liba.a`: |
| |
| .. code-block:: gpr |
| |
| project Liba is |
| for Externally_Built use "true"; |
| for Source_Files use (); |
| for Library_Dir use "lib"; |
| for Library_Name use "a"; |
| for Library_Kind use "static"; |
| end Liba; |
| |
| This is an alternative to the use of `pragma Linker_Options`. It is |
| especially interesting in the context of systems with several interdependent |
| static libraries where finding a proper linker order is not easy and best be |
| left to the tools having visibility over project dependence information. |
| |
| In order to use an Ada library manually, you need to make sure that this |
| library is on both your source and object path |
| (see :ref:`Search_Paths_and_the_Run-Time_Library_RTL` |
| and :ref:`Search_Paths_for_gnatbind`). Furthermore, when the objects are grouped |
| in an archive or a shared library, you need to specify the desired |
| library at link time. |
| |
| For example, you can use the library :file:`mylib` installed in |
| :file:`/dir/my_lib_src` and :file:`/dir/my_lib_obj` with the following commands: |
| |
| .. code-block:: sh |
| |
| $ gnatmake -aI/dir/my_lib_src -aO/dir/my_lib_obj my_appl \\ |
| -largs -lmy_lib |
| |
| This can be expressed more simply: |
| |
| .. code-block:: sh |
| |
| $ gnatmake my_appl |
| |
| when the following conditions are met: |
| |
| * :file:`/dir/my_lib_src` has been added by the user to the environment |
| variable :envvar:`ADA_INCLUDE_PATH`, or by the administrator to the file |
| :file:`ada_source_path` |
| |
| * :file:`/dir/my_lib_obj` has been added by the user to the environment |
| variable :envvar:`ADA_OBJECTS_PATH`, or by the administrator to the file |
| :file:`ada_object_path` |
| |
| * a pragma `Linker_Options` has been added to one of the sources. |
| For example: |
| |
| .. code-block:: ada |
| |
| pragma Linker_Options ("-lmy_lib"); |
| |
| Note that you may also load a library dynamically at |
| run time given its filename, as illustrated in the GNAT :file:`plugins` example |
| in the directory :file:`share/examples/gnat/plugins` within the GNAT |
| install area. |
| |
| .. _Stand-alone_Ada_Libraries: |
| |
| Stand-alone Ada Libraries |
| ------------------------- |
| |
| .. index:: ! Stand-alone libraries |
| |
| .. _Introduction_to_Stand-alone_Libraries: |
| |
| Introduction to Stand-alone Libraries |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| A Stand-alone Library (abbreviated 'SAL') is a library that contains the |
| necessary code to |
| elaborate the Ada units that are included in the library. In contrast with |
| an ordinary library, which consists of all sources, objects and :file:`ALI` |
| files of the |
| library, a SAL may specify a restricted subset of compilation units |
| to serve as a library interface. In this case, the fully |
| self-sufficient set of files will normally consist of an objects |
| archive, the sources of interface units' specs, and the :file:`ALI` |
| files of interface units. |
| If an interface spec contains a generic unit or an inlined subprogram, |
| the body's |
| source must also be provided; if the units that must be provided in the source |
| form depend on other units, the source and :file:`ALI` files of those must |
| also be provided. |
| |
| The main purpose of a SAL is to minimize the recompilation overhead of client |
| applications when a new version of the library is installed. Specifically, |
| if the interface sources have not changed, client applications do not need to |
| be recompiled. If, furthermore, a SAL is provided in the shared form and its |
| version, controlled by `Library_Version` attribute, is not changed, |
| then the clients do not need to be relinked. |
| |
| SALs also allow the library providers to minimize the amount of library source |
| text exposed to the clients. Such 'information hiding' might be useful or |
| necessary for various reasons. |
| |
| Stand-alone libraries are also well suited to be used in an executable whose |
| main routine is not written in Ada. |
| |
| .. _Building_a_Stand-alone_Library: |
| |
| Building a Stand-alone Library |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| GNAT's Project facility provides a simple way of building and installing |
| stand-alone libraries; see :ref:`Stand-alone_Library_Projects`. |
| To be a Stand-alone Library Project, in addition to the two attributes |
| that make a project a Library Project (`Library_Name` and |
| `Library_Dir`; see :ref:`Library_Projects`), the attribute |
| `Library_Interface` must be defined. For example: |
| |
| .. code-block:: gpr |
| |
| for Library_Dir use "lib_dir"; |
| for Library_Name use "dummy"; |
| for Library_Interface use ("int1", "int1.child"); |
| |
| Attribute `Library_Interface` has a non-empty string list value, |
| each string in the list designating a unit contained in an immediate source |
| of the project file. |
| |
| When a Stand-alone Library is built, first the binder is invoked to build |
| a package whose name depends on the library name |
| (:file:`b~dummy.ads/b` in the example above). |
| This binder-generated package includes initialization and |
| finalization procedures whose |
| names depend on the library name (`dummyinit` and `dummyfinal` |
| in the example |
| above). The object corresponding to this package is included in the library. |
| |
| You must ensure timely (e.g., prior to any use of interfaces in the SAL) |
| calling of these procedures if a static SAL is built, or if a shared SAL |
| is built |
| with the project-level attribute `Library_Auto_Init` set to |
| `"false"`. |
| |
| For a Stand-Alone Library, only the :file:`ALI` files of the Interface Units |
| (those that are listed in attribute `Library_Interface`) are copied to |
| the Library Directory. As a consequence, only the Interface Units may be |
| imported from Ada units outside of the library. If other units are imported, |
| the binding phase will fail. |
| |
| It is also possible to build an encapsulated library where not only |
| the code to elaborate and finalize the library is embedded but also |
| ensuring that the library is linked only against static |
| libraries. So an encapsulated library only depends on system |
| libraries, all other code, including the GNAT runtime, is embedded. To |
| build an encapsulated library the attribute |
| `Library_Standalone` must be set to `encapsulated`: |
| |
| .. code-block:: gpr |
| |
| for Library_Dir use "lib_dir"; |
| for Library_Name use "dummy"; |
| for Library_Kind use "dynamic"; |
| for Library_Interface use ("int1", "int1.child"); |
| for Library_Standalone use "encapsulated"; |
| |
| The default value for this attribute is `standard` in which case |
| a stand-alone library is built. |
| |
| The attribute `Library_Src_Dir` may be specified for a |
| Stand-Alone Library. `Library_Src_Dir` is a simple attribute that has a |
| single string value. Its value must be the path (absolute or relative to the |
| project directory) of an existing directory. This directory cannot be the |
| object directory or one of the source directories, but it can be the same as |
| the library directory. The sources of the Interface |
| Units of the library that are needed by an Ada client of the library will be |
| copied to the designated directory, called the Interface Copy directory. |
| These sources include the specs of the Interface Units, but they may also |
| include bodies and subunits, when pragmas `Inline` or `Inline_Always` |
| are used, or when there is a generic unit in the spec. Before the sources |
| are copied to the Interface Copy directory, an attempt is made to delete all |
| files in the Interface Copy directory. |
| |
| Building stand-alone libraries by hand is somewhat tedious, but for those |
| occasions when it is necessary here are the steps that you need to perform: |
| |
| * Compile all library sources. |
| |
| * Invoke the binder with the switch *-n* (No Ada main program), |
| with all the :file:`ALI` files of the interfaces, and |
| with the switch *-L* to give specific names to the `init` |
| and `final` procedures. For example: |
| |
| .. code-block:: sh |
| |
| $ gnatbind -n int1.ali int2.ali -Lsal1 |
| |
| * Compile the binder generated file: |
| |
| .. code-block:: sh |
| |
| $ gcc -c b~int2.adb |
| |
| * Link the dynamic library with all the necessary object files, |
| indicating to the linker the names of the `init` (and possibly |
| `final`) procedures for automatic initialization (and finalization). |
| The built library should be placed in a directory different from |
| the object directory. |
| |
| * Copy the `ALI` files of the interface to the library directory, |
| add in this copy an indication that it is an interface to a SAL |
| (i.e., add a word *SL* on the line in the :file:`ALI` file that starts |
| with letter 'P') and make the modified copy of the :file:`ALI` file |
| read-only. |
| |
| Using SALs is not different from using other libraries |
| (see :ref:`Using_a_library`). |
| |
| .. _Creating_a_Stand-alone_Library_to_be_used_in_a_non-Ada_context: |
| |
| Creating a Stand-alone Library to be used in a non-Ada context |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| It is easy to adapt the SAL build procedure discussed above for use of a SAL in |
| a non-Ada context. |
| |
| The only extra step required is to ensure that library interface subprograms |
| are compatible with the main program, by means of `pragma Export` |
| or `pragma Convention`. |
| |
| Here is an example of simple library interface for use with C main program: |
| |
| .. code-block:: ada |
| |
| package My_Package is |
| |
| procedure Do_Something; |
| pragma Export (C, Do_Something, "do_something"); |
| |
| procedure Do_Something_Else; |
| pragma Export (C, Do_Something_Else, "do_something_else"); |
| |
| end My_Package; |
| |
| On the foreign language side, you must provide a 'foreign' view of the |
| library interface; remember that it should contain elaboration routines in |
| addition to interface subprograms. |
| |
| The example below shows the content of `mylib_interface.h` (note |
| that there is no rule for the naming of this file, any name can be used) |
| |
| .. code-block:: c |
| |
| /* the library elaboration procedure */ |
| extern void mylibinit (void); |
| |
| /* the library finalization procedure */ |
| extern void mylibfinal (void); |
| |
| /* the interface exported by the library */ |
| extern void do_something (void); |
| extern void do_something_else (void); |
| |
| Libraries built as explained above can be used from any program, provided |
| that the elaboration procedures (named `mylibinit` in the previous |
| example) are called before the library services are used. Any number of |
| libraries can be used simultaneously, as long as the elaboration |
| procedure of each library is called. |
| |
| Below is an example of a C program that uses the `mylib` library. |
| |
| .. code-block:: c |
| |
| #include "mylib_interface.h" |
| |
| int |
| main (void) |
| { |
| /* First, elaborate the library before using it */ |
| mylibinit (); |
| |
| /* Main program, using the library exported entities */ |
| do_something (); |
| do_something_else (); |
| |
| /* Library finalization at the end of the program */ |
| mylibfinal (); |
| return 0; |
| } |
| |
| Note that invoking any library finalization procedure generated by |
| `gnatbind` shuts down the Ada run-time environment. |
| Consequently, the |
| finalization of all Ada libraries must be performed at the end of the program. |
| No call to these libraries or to the Ada run-time library should be made |
| after the finalization phase. |
| |
| Note also that special care must be taken with multi-tasks |
| applications. The initialization and finalization routines are not |
| protected against concurrent access. If such requirement is needed it |
| must be ensured at the application level using a specific operating |
| system services like a mutex or a critical-section. |
| |
| .. _Restrictions_in_Stand-alone_Libraries: |
| |
| Restrictions in Stand-alone Libraries |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| The pragmas listed below should be used with caution inside libraries, |
| as they can create incompatibilities with other Ada libraries: |
| |
| * pragma `Locking_Policy` |
| * pragma `Partition_Elaboration_Policy` |
| * pragma `Queuing_Policy` |
| * pragma `Task_Dispatching_Policy` |
| * pragma `Unreserve_All_Interrupts` |
| |
| When using a library that contains such pragmas, the user must make sure |
| that all libraries use the same pragmas with the same values. Otherwise, |
| `Program_Error` will |
| be raised during the elaboration of the conflicting |
| libraries. The usage of these pragmas and its consequences for the user |
| should therefore be well documented. |
| |
| Similarly, the traceback in the exception occurrence mechanism should be |
| enabled or disabled in a consistent manner across all libraries. |
| Otherwise, Program_Error will be raised during the elaboration of the |
| conflicting libraries. |
| |
| If the `Version` or `Body_Version` |
| attributes are used inside a library, then you need to |
| perform a `gnatbind` step that specifies all :file:`ALI` files in all |
| libraries, so that version identifiers can be properly computed. |
| In practice these attributes are rarely used, so this is unlikely |
| to be a consideration. |
| |
| .. _Rebuilding_the_GNAT_Run-Time_Library: |
| |
| Rebuilding the GNAT Run-Time Library |
| ------------------------------------ |
| |
| .. index:: GNAT Run-Time Library, rebuilding |
| .. index:: Building the GNAT Run-Time Library |
| .. index:: Rebuilding the GNAT Run-Time Library |
| .. index:: Run-Time Library, rebuilding |
| |
| It may be useful to recompile the GNAT library in various contexts, the |
| most important one being the use of partition-wide configuration pragmas |
| such as `Normalize_Scalars`. A special Makefile called |
| `Makefile.adalib` is provided to that effect and can be found in |
| the directory containing the GNAT library. The location of this |
| directory depends on the way the GNAT environment has been installed and can |
| be determined by means of the command: |
| |
| .. code-block:: sh |
| |
| $ gnatls -v |
| |
| The last entry in the object search path usually contains the |
| gnat library. This Makefile contains its own documentation and in |
| particular the set of instructions needed to rebuild a new library and |
| to use it. |
| |
| |
| .. index:: ! Conditional compilation |
| |
| .. _Conditional_Compilation: |
| |
| Conditional Compilation |
| ======================= |
| |
| This section presents some guidelines for modeling conditional compilation in Ada and describes the |
| gnatprep preprocessor utility. |
| |
| .. index:: ! Conditional compilation |
| |
| .. _Modeling_Conditional_Compilation_in_Ada: |
| |
| Modeling Conditional Compilation in Ada |
| --------------------------------------- |
| |
| It is often necessary to arrange for a single source program |
| to serve multiple purposes, where it is compiled in different |
| ways to achieve these different goals. Some examples of the |
| need for this feature are |
| |
| * Adapting a program to a different hardware environment |
| * Adapting a program to a different target architecture |
| * Turning debugging features on and off |
| * Arranging for a program to compile with different compilers |
| |
| In C, or C++, the typical approach would be to use the preprocessor |
| that is defined as part of the language. The Ada language does not |
| contain such a feature. This is not an oversight, but rather a very |
| deliberate design decision, based on the experience that overuse of |
| the preprocessing features in C and C++ can result in programs that |
| are extremely difficult to maintain. For example, if we have ten |
| switches that can be on or off, this means that there are a thousand |
| separate programs, any one of which might not even be syntactically |
| correct, and even if syntactically correct, the resulting program |
| might not work correctly. Testing all combinations can quickly become |
| impossible. |
| |
| Nevertheless, the need to tailor programs certainly exists, and in |
| this section we will discuss how this can |
| be achieved using Ada in general, and GNAT in particular. |
| |
| .. _Use_of_Boolean_Constants: |
| |
| Use of Boolean Constants |
| ^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| In the case where the difference is simply which code |
| sequence is executed, the cleanest solution is to use Boolean |
| constants to control which code is executed. |
| |
| .. code-block:: ada |
| |
| FP_Initialize_Required : constant Boolean := True; |
| ... |
| if FP_Initialize_Required then |
| ... |
| end if; |
| |
| Not only will the code inside the `if` statement not be executed if |
| the constant Boolean is `False`, but it will also be completely |
| deleted from the program. |
| However, the code is only deleted after the `if` statement |
| has been checked for syntactic and semantic correctness. |
| (In contrast, with preprocessors the code is deleted before the |
| compiler ever gets to see it, so it is not checked until the switch |
| is turned on.) |
| |
| .. index:: Preprocessors (contrasted with conditional compilation) |
| |
| Typically the Boolean constants will be in a separate package, |
| something like: |
| |
| .. code-block:: ada |
| |
| package Config is |
| FP_Initialize_Required : constant Boolean := True; |
| Reset_Available : constant Boolean := False; |
| ... |
| end Config; |
| |
| The `Config` package exists in multiple forms for the various targets, |
| with an appropriate script selecting the version of `Config` needed. |
| Then any other unit requiring conditional compilation can do a |with| |
| of `Config` to make the constants visible. |
| |
| .. _Debugging_-_A_Special_Case: |
| |
| Debugging - A Special Case |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| A common use of conditional code is to execute statements (for example |
| dynamic checks, or output of intermediate results) under control of a |
| debug switch, so that the debugging behavior can be turned on and off. |
| This can be done using a Boolean constant to control whether the code |
| is active: |
| |
| .. code-block:: ada |
| |
| if Debugging then |
| Put_Line ("got to the first stage!"); |
| end if; |
| |
| or |
| |
| .. code-block:: ada |
| |
| if Debugging and then Temperature > 999.0 then |
| raise Temperature_Crazy; |
| end if; |
| |
| .. index:: pragma Assert |
| |
| Since this is a common case, there are special features to deal with |
| this in a convenient manner. For the case of tests, Ada 2005 has added |
| a pragma `Assert` that can be used for such tests. This pragma is modeled |
| on the `Assert` pragma that has always been available in GNAT, so this |
| feature may be used with GNAT even if you are not using Ada 2005 features. |
| The use of pragma `Assert` is described in the |
| :title:`GNAT_Reference_Manual`, but as an |
| example, the last test could be written: |
| |
| .. code-block:: ada |
| |
| pragma Assert (Temperature <= 999.0, "Temperature Crazy"); |
| |
| or simply |
| |
| .. code-block:: ada |
| |
| pragma Assert (Temperature <= 999.0); |
| |
| In both cases, if assertions are active and the temperature is excessive, |
| the exception `Assert_Failure` will be raised, with the given string in |
| the first case or a string indicating the location of the pragma in the second |
| case used as the exception message. |
| |
| .. index:: pragma Assertion_Policy |
| |
| You can turn assertions on and off by using the `Assertion_Policy` |
| pragma. |
| |
| .. index:: -gnata switch |
| |
| This is an Ada 2005 pragma which is implemented in all modes by |
| GNAT. Alternatively, you can use the *-gnata* switch |
| to enable assertions from the command line, which applies to |
| all versions of Ada. |
| |
| .. index:: pragma Debug |
| |
| For the example above with the `Put_Line`, the GNAT-specific pragma |
| `Debug` can be used: |
| |
| .. code-block:: ada |
| |
| pragma Debug (Put_Line ("got to the first stage!")); |
| |
| If debug pragmas are enabled, the argument, which must be of the form of |
| a procedure call, is executed (in this case, `Put_Line` will be called). |
| Only one call can be present, but of course a special debugging procedure |
| containing any code you like can be included in the program and then |
| called in a pragma `Debug` argument as needed. |
| |
| One advantage of pragma `Debug` over the `if Debugging then` |
| construct is that pragma `Debug` can appear in declarative contexts, |
| such as at the very beginning of a procedure, before local declarations have |
| been elaborated. |
| |
| .. index:: pragma Debug_Policy |
| |
| Debug pragmas are enabled using either the *-gnata* switch that also |
| controls assertions, or with a separate Debug_Policy pragma. |
| |
| The latter pragma is new in the Ada 2005 versions of GNAT (but it can be used |
| in Ada 95 and Ada 83 programs as well), and is analogous to |
| pragma `Assertion_Policy` to control assertions. |
| |
| `Assertion_Policy` and `Debug_Policy` are configuration pragmas, |
| and thus they can appear in :file:`gnat.adc` if you are not using a |
| project file, or in the file designated to contain configuration pragmas |
| in a project file. |
| They then apply to all subsequent compilations. In practice the use of |
| the *-gnata* switch is often the most convenient method of controlling |
| the status of these pragmas. |
| |
| Note that a pragma is not a statement, so in contexts where a statement |
| sequence is required, you can't just write a pragma on its own. You have |
| to add a `null` statement. |
| |
| .. code-block:: ada |
| |
| if ... then |
| ... -- some statements |
| else |
| pragma Assert (Num_Cases < 10); |
| null; |
| end if; |
| |
| .. _Conditionalizing_Declarations: |
| |
| Conditionalizing Declarations |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| In some cases it may be necessary to conditionalize declarations to meet |
| different requirements. For example we might want a bit string whose length |
| is set to meet some hardware message requirement. |
| |
| This may be possible using declare blocks controlled |
| by conditional constants: |
| |
| .. code-block:: ada |
| |
| if Small_Machine then |
| declare |
| X : Bit_String (1 .. 10); |
| begin |
| ... |
| end; |
| else |
| declare |
| X : Large_Bit_String (1 .. 1000); |
| begin |
| ... |
| end; |
| end if; |
| |
| Note that in this approach, both declarations are analyzed by the |
| compiler so this can only be used where both declarations are legal, |
| even though one of them will not be used. |
| |
| Another approach is to define integer constants, e.g., `Bits_Per_Word`, |
| or Boolean constants, e.g., `Little_Endian`, and then write declarations |
| that are parameterized by these constants. For example |
| |
| .. code-block:: ada |
| |
| for Rec use |
| Field1 at 0 range Boolean'Pos (Little_Endian) * 10 .. Bits_Per_Word; |
| end record; |
| |
| If `Bits_Per_Word` is set to 32, this generates either |
| |
| .. code-block:: ada |
| |
| for Rec use |
| Field1 at 0 range 0 .. 32; |
| end record; |
| |
| for the big endian case, or |
| |
| .. code-block:: ada |
| |
| for Rec use record |
| Field1 at 0 range 10 .. 32; |
| end record; |
| |
| for the little endian case. Since a powerful subset of Ada expression |
| notation is usable for creating static constants, clever use of this |
| feature can often solve quite difficult problems in conditionalizing |
| compilation (note incidentally that in Ada 95, the little endian |
| constant was introduced as `System.Default_Bit_Order`, so you do not |
| need to define this one yourself). |
| |
| .. _Use_of_Alternative_Implementations: |
| |
| Use of Alternative Implementations |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| In some cases, none of the approaches described above are adequate. This |
| can occur for example if the set of declarations required is radically |
| different for two different configurations. |
| |
| In this situation, the official Ada way of dealing with conditionalizing |
| such code is to write separate units for the different cases. As long as |
| this does not result in excessive duplication of code, this can be done |
| without creating maintenance problems. The approach is to share common |
| code as far as possible, and then isolate the code and declarations |
| that are different. Subunits are often a convenient method for breaking |
| out a piece of a unit that is to be conditionalized, with separate files |
| for different versions of the subunit for different targets, where the |
| build script selects the right one to give to the compiler. |
| |
| .. index:: Subunits (and conditional compilation) |
| |
| As an example, consider a situation where a new feature in Ada 2005 |
| allows something to be done in a really nice way. But your code must be able |
| to compile with an Ada 95 compiler. Conceptually you want to say: |
| |
| .. code-block:: ada |
| |
| if Ada_2005 then |
| ... neat Ada 2005 code |
| else |
| ... not quite as neat Ada 95 code |
| end if; |
| |
| where `Ada_2005` is a Boolean constant. |
| |
| But this won't work when `Ada_2005` is set to `False`, |
| since the `then` clause will be illegal for an Ada 95 compiler. |
| (Recall that although such unreachable code would eventually be deleted |
| by the compiler, it still needs to be legal. If it uses features |
| introduced in Ada 2005, it will be illegal in Ada 95.) |
| |
| So instead we write |
| |
| .. code-block:: ada |
| |
| procedure Insert is separate; |
| |
| Then we have two files for the subunit `Insert`, with the two sets of |
| code. |
| If the package containing this is called `File_Queries`, then we might |
| have two files |
| |
| * :file:`file_queries-insert-2005.adb` |
| * :file:`file_queries-insert-95.adb` |
| |
| and the build script renames the appropriate file to :file:`file_queries-insert.adb` and then carries out the compilation. |
| |
| This can also be done with project files' naming schemes. For example: |
| |
| .. code-block:: gpr |
| |
| for body ("File_Queries.Insert") use "file_queries-insert-2005.ada"; |
| |
| Note also that with project files it is desirable to use a different extension |
| than :file:`ads` / :file:`adb` for alternative versions. Otherwise a naming |
| conflict may arise through another commonly used feature: to declare as part |
| of the project a set of directories containing all the sources obeying the |
| default naming scheme. |
| |
| The use of alternative units is certainly feasible in all situations, |
| and for example the Ada part of the GNAT run-time is conditionalized |
| based on the target architecture using this approach. As a specific example, |
| consider the implementation of the AST feature in VMS. There is one |
| spec: :file:`s-asthan.ads` which is the same for all architectures, and three |
| bodies: |
| |
| * :file:`s-asthan.adb` |
| used for all non-VMS operating systems |
| |
| * :file:`s-asthan-vms-alpha.adb` |
| used for VMS on the Alpha |
| |
| * :file:`s-asthan-vms-ia64.adb` |
| used for VMS on the ia64 |
| |
| The dummy version :file:`s-asthan.adb` simply raises exceptions noting that |
| this operating system feature is not available, and the two remaining |
| versions interface with the corresponding versions of VMS to provide |
| VMS-compatible AST handling. The GNAT build script knows the architecture |
| and operating system, and automatically selects the right version, |
| renaming it if necessary to :file:`s-asthan.adb` before the run-time build. |
| |
| Another style for arranging alternative implementations is through Ada's |
| access-to-subprogram facility. |
| In case some functionality is to be conditionally included, |
| you can declare an access-to-procedure variable `Ref` that is initialized |
| to designate a 'do nothing' procedure, and then invoke `Ref.all` |
| when appropriate. |
| In some library package, set `Ref` to `Proc'Access` for some |
| procedure `Proc` that performs the relevant processing. |
| The initialization only occurs if the library package is included in the |
| program. |
| The same idea can also be implemented using tagged types and dispatching |
| calls. |
| |
| .. _Preprocessing: |
| |
| Preprocessing |
| ^^^^^^^^^^^^^ |
| |
| .. index:: Preprocessing |
| |
| Although it is quite possible to conditionalize code without the use of |
| C-style preprocessing, as described earlier in this section, it is |
| nevertheless convenient in some cases to use the C approach. Moreover, |
| older Ada compilers have often provided some preprocessing capability, |
| so legacy code may depend on this approach, even though it is not |
| standard. |
| |
| To accommodate such use, GNAT provides a preprocessor (modeled to a large |
| extent on the various preprocessors that have been used |
| with legacy code on other compilers, to enable easier transition). |
| |
| .. index:: gnatprep |
| |
| The preprocessor may be used in two separate modes. It can be used quite |
| separately from the compiler, to generate a separate output source file |
| that is then fed to the compiler as a separate step. This is the |
| `gnatprep` utility, whose use is fully described in |
| :ref:`Preprocessing_with_gnatprep`. |
| |
| The preprocessing language allows such constructs as |
| |
| .. code-block:: c |
| |
| #if DEBUG or else (PRIORITY > 4) then |
| bunch of declarations |
| #else |
| completely different bunch of declarations |
| #end if; |
| |
| The values of the symbols `DEBUG` and `PRIORITY` can be |
| defined either on the command line or in a separate file. |
| |
| The other way of running the preprocessor is even closer to the C style and |
| often more convenient. In this approach the preprocessing is integrated into |
| the compilation process. The compiler is fed the preprocessor input which |
| includes `#if` lines etc, and then the compiler carries out the |
| preprocessing internally and processes the resulting output. |
| For more details on this approach, see :ref:`Integrated_Preprocessing`. |
| |
| .. _Preprocessing_with_gnatprep: |
| |
| Preprocessing with `gnatprep` |
| ----------------------------- |
| |
| .. index:: ! gnatprep |
| .. index:: Preprocessing (gnatprep) |
| |
| This section discusses how to use GNAT's `gnatprep` utility for simple |
| preprocessing. |
| Although designed for use with GNAT, `gnatprep` does not depend on any |
| special GNAT features. |
| For further discussion of conditional compilation in general, see |
| :ref:`Conditional_Compilation`. |
| |
| .. _Preprocessing_Symbols: |
| |
| Preprocessing Symbols |
| ^^^^^^^^^^^^^^^^^^^^^ |
| |
| Preprocessing symbols are defined in definition files and referred to in |
| sources to be preprocessed. A Preprocessing symbol is an identifier, following |
| normal Ada (case-insensitive) rules for its syntax, with the restriction that |
| all characters need to be in the ASCII set (no accented letters). |
| |
| .. _Using_gnatprep: |
| |
| Using `gnatprep` |
| ^^^^^^^^^^^^^^^^ |
| |
| To call `gnatprep` use: |
| |
| .. code-block:: sh |
| |
| $ gnatprep [`switches`] `infile` `outfile` [`deffile`] |
| |
| where |
| |
| * *switches* |
| is an optional sequence of switches as described in the next section. |
| |
| * *infile* |
| is the full name of the input file, which is an Ada source |
| file containing preprocessor directives. |
| |
| * *outfile* |
| is the full name of the output file, which is an Ada source |
| in standard Ada form. When used with GNAT, this file name will |
| normally have an ads or adb suffix. |
| |
| * *deffile* |
| is the full name of a text file containing definitions of |
| preprocessing symbols to be referenced by the preprocessor. This argument is |
| optional, and can be replaced by the use of the *-D* switch. |
| |
| |
| .. _Switches_for_gnatprep: |
| |
| Switches for `gnatprep` |
| ^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| .. index:: -b (gnatprep) |
| |
| :samp:`-b` |
| Causes both preprocessor lines and the lines deleted by |
| preprocessing to be replaced by blank lines in the output source file, |
| preserving line numbers in the output file. |
| |
| .. index:: -c (gnatprep) |
| |
| :samp:`-c` |
| Causes both preprocessor lines and the lines deleted |
| by preprocessing to be retained in the output source as comments marked |
| with the special string `"--! "`. This option will result in line numbers |
| being preserved in the output file. |
| |
| .. index:: -C (gnatprep) |
| |
| :samp:`-C` |
| Causes comments to be scanned. Normally comments are ignored by gnatprep. |
| If this option is specified, then comments are scanned and any $symbol |
| substitutions performed as in program text. This is particularly useful |
| when structured comments are used (e.g., when writing programs in the |
| SPARK dialect of Ada). Note that this switch is not available when |
| doing integrated preprocessing (it would be useless in this context |
| since comments are ignored by the compiler in any case). |
| |
| .. index:: -D (gnatprep) |
| |
| :samp:`-D{symbol}={value}` |
| Defines a new preprocessing symbol, associated with value. If no value is given |
| on the command line, then symbol is considered to be `True`. This switch |
| can be used in place of a definition file. |
| |
| .. index:: -r (gnatprep) |
| |
| :samp:`-r` |
| Causes a `Source_Reference` pragma to be generated that |
| references the original input file, so that error messages will use |
| the file name of this original file. The use of this switch implies |
| that preprocessor lines are not to be removed from the file, so its |
| use will force *-b* mode if *-c* |
| has not been specified explicitly. |
| |
| Note that if the file to be preprocessed contains multiple units, then |
| it will be necessary to `gnatchop` the output file from |
| `gnatprep`. If a `Source_Reference` pragma is present |
| in the preprocessed file, it will be respected by |
| `gnatchop -r` |
| so that the final chopped files will correctly refer to the original |
| input source file for `gnatprep`. |
| |
| .. index:: -s (gnatprep) |
| |
| :samp:`-s` |
| Causes a sorted list of symbol names and values to be |
| listed on the standard output file. |
| |
| .. index:: -u (gnatprep) |
| |
| :samp:`-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. |
| |
| |
| Note: if neither *-b* nor *-c* is present, |
| then preprocessor lines and |
| deleted lines are completely removed from the output, unless -r is |
| specified, in which case -b is assumed. |
| |
| |
| .. _Form_of_Definitions_File: |
| |
| Form of Definitions File |
| ^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| The definitions file contains lines of the form:: |
| |
| symbol := value |
| |
| where `symbol` is a preprocessing symbol, and `value` is one of the following: |
| |
| * Empty, corresponding to a null substitution, |
| * A string literal using normal Ada syntax, or |
| * Any sequence of characters from the set {letters, digits, period, underline}. |
| |
| Comment lines may also appear in the definitions file, starting with |
| the usual ``--``, |
| and comments may be added to the definitions lines. |
| |
| |
| .. _Form_of_Input_Text_for_gnatprep: |
| |
| Form of Input Text for `gnatprep` |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| The input text may contain preprocessor conditional inclusion lines, |
| as well as general symbol substitution sequences. |
| |
| The preprocessor conditional inclusion commands have the form: |
| |
| .. code-block:: c |
| |
| #if <expression> [then] |
| lines |
| #elsif <expression> [then] |
| lines |
| #elsif <expression> [then] |
| lines |
| ... |
| #else |
| lines |
| #end if; |
| |
| In this example, <expression> is defined by the following grammar:: |
| |
| <expression> ::= <symbol> |
| <expression> ::= <symbol> = "<value>" |
| <expression> ::= <symbol> = <symbol> |
| <expression> ::= <symbol> = <integer> |
| <expression> ::= <symbol> > <integer> |
| <expression> ::= <symbol> >= <integer> |
| <expression> ::= <symbol> < <integer> |
| <expression> ::= <symbol> <= <integer> |
| <expression> ::= <symbol> 'Defined |
| <expression> ::= not <expression> |
| <expression> ::= <expression> and <expression> |
| <expression> ::= <expression> or <expression> |
| <expression> ::= <expression> and then <expression> |
| <expression> ::= <expression> or else <expression> |
| <expression> ::= ( <expression> ) |
| |
| Note the following restriction: it is not allowed to have "and" or "or" |
| following "not" in the same expression without parentheses. For example, this |
| is not allowed: |
| |
| .. code-block:: ada |
| |
| not X or Y |
| |
| This can be expressed instead as one of the following forms: |
| |
| .. code-block:: ada |
| |
| (not X) or Y |
| not (X or Y) |
| |
| For the first test (<expression> ::= <symbol>) the symbol must have |
| either the value true or false, that is to say the right-hand of the |
| symbol definition must be one of the (case-insensitive) literals |
| `True` or `False`. If the value is true, then the |
| corresponding lines are included, and if the value is false, they are |
| excluded. |
| |
| When comparing a symbol to an integer, the integer is any non negative |
| literal integer as defined in the Ada Reference Manual, such as 3, 16#FF# or |
| 2#11#. The symbol value must also be a non negative integer. Integer values |
| in the range 0 .. 2**31-1 are supported. |
| |
| The test (<expression> ::= <symbol>'Defined) is true only if |
| the symbol has been defined in the definition file or by a *-D* |
| switch on the command line. Otherwise, the test is false. |
| |
| The equality tests are case insensitive, as are all the preprocessor lines. |
| |
| If the symbol referenced is not defined in the symbol definitions file, |
| then the effect depends on whether or not switch *-u* |
| is specified. If so, then the symbol is treated as if it had the value |
| false and the test fails. If this switch is not specified, then |
| it is an error to reference an undefined symbol. It is also an error to |
| reference a symbol that is defined with a value other than `True` |
| or `False`. |
| |
| The use of the `not` operator inverts the sense of this logical test. |
| The `not` operator cannot be combined with the `or` or `and` |
| operators, without parentheses. For example, "if not X or Y then" is not |
| allowed, but "if (not X) or Y then" and "if not (X or Y) then" are. |
| |
| The `then` keyword is optional as shown |
| |
| The `#` must be the first non-blank character on a line, but |
| otherwise the format is free form. Spaces or tabs may appear between |
| the `#` and the keyword. The keywords and the symbols are case |
| insensitive as in normal Ada code. Comments may be used on a |
| preprocessor line, but other than that, no other tokens may appear on a |
| preprocessor line. Any number of `elsif` clauses can be present, |
| including none at all. The `else` is optional, as in Ada. |
| |
| The `#` marking the start of a preprocessor line must be the first |
| non-blank character on the line, i.e., it must be preceded only by |
| spaces or horizontal tabs. |
| |
| Symbol substitution outside of preprocessor lines is obtained by using |
| the sequence:: |
| |
| $symbol |
| |
| anywhere within a source line, except in a comment or within a |
| string literal. The identifier |
| following the `$` must match one of the symbols defined in the symbol |
| definition file, and the result is to substitute the value of the |
| symbol in place of `$symbol` in the output file. |
| |
| Note that although the substitution of strings within a string literal |
| is not possible, it is possible to have a symbol whose defined value is |
| a string literal. So instead of setting XYZ to `hello` and writing: |
| |
| .. code-block:: c |
| |
| Header : String := "$XYZ"; |
| |
| you should set XYZ to `"hello"` and write: |
| |
| .. code-block:: c |
| |
| Header : String := $XYZ; |
| |
| and then the substitution will occur as desired. |
| |
| |
| .. _Integrated_Preprocessing: |
| |
| Integrated Preprocessing |
| ------------------------ |
| |
| GNAT sources may be preprocessed immediately before compilation. |
| In this case, the actual |
| text of the source is not the text of the source file, but is derived from it |
| through a process called preprocessing. Integrated preprocessing is specified |
| through switches *-gnatep* and/or *-gnateD*. *-gnatep* |
| indicates, through a text file, the preprocessing data to be used. |
| :samp:`-gnateD` specifies or modifies the values of preprocessing symbol. |
| Note that integrated preprocessing applies only to Ada source files, it is |
| not available for configuration pragma files. |
| |
| Note that when integrated preprocessing is used, the output from the |
| preprocessor is not written to any external file. Instead it is passed |
| internally to the compiler. If you need to preserve the result of |
| preprocessing in a file, then you should use *gnatprep* |
| to perform the desired preprocessing in stand-alone mode. |
| |
| It is recommended that *gnatmake* switch -s should be |
| used when Integrated Preprocessing is used. The reason is that preprocessing |
| with another Preprocessing Data file without changing the sources will |
| not trigger recompilation without this switch. |
| |
| Note that *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 section |
| :ref:`Preprocessing_with_gnatprep`. This section only describes how integrated |
| preprocessing is triggered and parameterized. |
| |
| |
| .. index:: -gnatep (gcc) |
| |
| :samp:`-gnatep={file}` |
| This switch indicates to the compiler the file name (without directory |
| information) of the preprocessor data file to use. The preprocessor data file |
| should be found in the source directories. Note that when the compiler is |
| called by a builder such as (*gnatmake* with a project |
| file, if the object directory is not also a source directory, the builder needs |
| to be called with *-x*. |
| |
| A preprocessing data file is a text file with significant lines indicating |
| how should be preprocessed either a specific source or all sources not |
| mentioned in other lines. A significant line is a nonempty, non-comment line. |
| Comments are similar to Ada comments. |
| |
| Each significant line starts with either a literal string or the character '*'. |
| A literal string is the file name (without directory information) of the source |
| to preprocess. A character '*' indicates the preprocessing for all the sources |
| that are not specified explicitly on other lines (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 the character '*', another optional literal string |
| indicating the file name of the definition file to be used for preprocessing |
| (:ref:`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 switch -I., otherwise |
| the compiler would not find the definition file. |
| |
| Then, optionally, switches similar to those of `gnatprep` may |
| be found. Those switches are: |
| |
| :samp:`-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*. |
| |
| |
| :samp:`-c` |
| Causes both preprocessor lines and the lines deleted |
| by preprocessing to be retained as comments marked |
| with the special string '`--!`'. |
| |
| |
| :samp:`-Dsymbol={value}` |
| Define or redefine a symbol, associated with value. A symbol is an Ada |
| identifier, or an Ada reserved word, with the exception of `if`, |
| `else`, `elsif`, `end`, `and`, `or` and `then`. |
| `value` is either 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. |
| |
| |
| :samp:`-s` |
| Causes a sorted list of symbol names and values to be |
| listed on the standard output file. |
| |
| |
| :samp:`-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. |
| |
| |
| Examples of valid lines in a preprocessor data file: |
| |
| .. code-block:: ada |
| |
| "toto.adb" "prep.def" -u |
| -- preprocess "toto.adb", using definition file "prep.def", |
| -- undefined symbol are False. |
| |
| * -c -DVERSION=V101 |
| -- preprocess all other sources without a definition file; |
| -- suppressed lined are commented; symbol VERSION has the value V101. |
| |
| "titi.adb" "prep2.def" -s |
| -- preprocess "titi.adb", using definition file "prep2.def"; |
| -- list all symbols with their values. |
| |
| .. index:: -gnateD (gcc) |
| |
| :samp:`-gnateDsymbol[=value]` |
| Define or redefine a preprocessing symbol, associated with value. If no value |
| is given on the command line, then the value of the symbol is `True`. |
| A symbol is an identifier, following normal Ada (case-insensitive) |
| rules for its syntax, and 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=Titi |
| -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`. |
| |
| |
| :samp:`-gnateG` |
| When integrated preprocessing is performed and the preprocessor modifies |
| the source text, write the result of this preprocessing into a file |
| <source>.prep. |
| |
| |
| .. _Mixed_Language_Programming: |
| |
| Mixed Language Programming |
| ========================== |
| |
| .. index:: Mixed Language Programming |
| |
| This section describes how to develop a mixed-language program, |
| with a focus on combining Ada with C or C++. |
| |
| .. _Interfacing_to_C: |
| |
| Interfacing to C |
| ---------------- |
| |
| Interfacing Ada with a foreign language such as C involves using |
| compiler directives to import and/or export entity definitions in each |
| language -- using `extern` statements in C, for instance, and the |
| `Import`, `Export`, and `Convention` pragmas in Ada. |
| A full treatment of these topics is provided in Appendix B, section 1 |
| of the Ada Reference Manual. |
| |
| There are two ways to build a program using GNAT that contains some Ada |
| sources and some foreign language sources, depending on whether or not |
| the main subprogram is written in Ada. Here is a source example with |
| the main subprogram in Ada: |
| |
| .. code-block:: c |
| |
| /* file1.c */ |
| #include <stdio.h> |
| |
| void print_num (int num) |
| { |
| printf ("num is %d.\\n", num); |
| return; |
| } |
| |
| .. code-block:: c |
| |
| /* file2.c */ |
| |
| /* num_from_Ada is declared in my_main.adb */ |
| extern int num_from_Ada; |
| |
| int get_num (void) |
| { |
| return num_from_Ada; |
| } |
| |
| .. code-block:: ada |
| |
| -- my_main.adb |
| procedure My_Main is |
| |
| -- Declare then export an Integer entity called num_from_Ada |
| My_Num : Integer := 10; |
| pragma Export (C, My_Num, "num_from_Ada"); |
| |
| -- Declare an Ada function spec for Get_Num, then use |
| -- C function get_num for the implementation. |
| function Get_Num return Integer; |
| pragma Import (C, Get_Num, "get_num"); |
| |
| -- Declare an Ada procedure spec for Print_Num, then use |
| -- C function print_num for the implementation. |
| procedure Print_Num (Num : Integer); |
| pragma Import (C, Print_Num, "print_num"; |
| |
| begin |
| Print_Num (Get_Num); |
| end My_Main; |
| |
| To build this example: |
| |
| * First compile the foreign language files to |
| generate object files: |
| |
| .. code-block:: sh |
| |
| $ gcc -c file1.c |
| $ gcc -c file2.c |
| |
| * Then, compile the Ada units to produce a set of object files and ALI |
| files: |
| |
| .. code-block:: sh |
| |
| $ gnatmake -c my_main.adb |
| |
| * Run the Ada binder on the Ada main program: |
| |
| .. code-block:: sh |
| |
| $ gnatbind my_main.ali |
| |
| * Link the Ada main program, the Ada objects and the other language |
| objects: |
| |
| .. code-block:: sh |
| |
| $ gnatlink my_main.ali file1.o file2.o |
| |
| The last three steps can be grouped in a single command: |
| |
| .. code-block:: sh |
| |
| $ gnatmake my_main.adb -largs file1.o file2.o |
| |
| |
| .. index:: Binder output file |
| |
| If the main program is in a language other than Ada, then you may have |
| more than one entry point into the Ada subsystem. You must use a special |
| binder option to generate callable routines that initialize and |
| finalize the Ada units (:ref:`Binding_with_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. The binder will place the |
| initialization and finalization subprograms into the |
| :file:`b~xxx.adb` file where they can be accessed by your C |
| sources. To illustrate, we have the following example: |
| |
| .. code-block:: c |
| |
| /* main.c */ |
| extern void adainit (void); |
| extern void adafinal (void); |
| extern int add (int, int); |
| extern int sub (int, int); |
| |
| int main (int argc, char *argv[]) |
| { |
| int a = 21, b = 7; |
| |
| adainit(); |
| |
| /* Should print "21 + 7 = 28" */ |
| printf ("%d + %d = %d\\n", a, b, add (a, b)); |
| |
| /* Should print "21 - 7 = 14" */ |
| printf ("%d - %d = %d\\n", a, b, sub (a, b)); |
| |
| adafinal(); |
| } |
| |
| .. code-block:: ada |
| |
| -- unit1.ads |
| package Unit1 is |
| function Add (A, B : Integer) return Integer; |
| pragma Export (C, Add, "add"); |
| end Unit1; |
| |
| .. code-block:: ada |
| |
| -- unit1.adb |
| package body Unit1 is |
| function Add (A, B : Integer) return Integer is |
| begin |
| return A + B; |
| end Add; |
| end Unit1; |
| |
| .. code-block:: ada |
| |
| -- unit2.ads |
| package Unit2 is |
| function Sub (A, B : Integer) return Integer; |
| pragma Export (C, Sub, "sub"); |
| end Unit2; |
| |
| .. code-block:: ada |
| |
| -- unit2.adb |
| package body Unit2 is |
| function Sub (A, B : Integer) return Integer is |
| begin |
| return A - B; |
| end Sub; |
| end Unit2; |
| |
| The build procedure for this application is similar to the last |
| example's: |
| |
| * First, compile the foreign language files to generate object files: |
| |
| .. code-block:: sh |
| |
| $ gcc -c main.c |
| |
| |
| * Next, compile the Ada units to produce a set of object files and ALI |
| files: |
| |
| .. code-block:: sh |
| |
| $ gnatmake -c unit1.adb |
| $ gnatmake -c unit2.adb |
| |
| * Run the Ada binder on every generated ALI file. Make sure to use the |
| :option:`-n` option to specify a foreign main program: |
| |
| .. code-block:: sh |
| |
| $ gnatbind -n unit1.ali unit2.ali |
| |
| * Link the Ada main program, the Ada objects and the foreign language |
| objects. You need only list the last ALI file here: |
| |
| .. code-block:: sh |
| |
| $ gnatlink unit2.ali main.o -o exec_file |
| |
| This procedure yields a binary executable called :file:`exec_file`. |
| |
| Depending on the circumstances (for example when your non-Ada main object |
| does not provide symbol `main`), you may also need to instruct the |
| GNAT linker not to include the standard startup objects by passing the |
| :option:`-nostartfiles` switch to `gnatlink`. |
| |
| .. _Calling_Conventions: |
| |
| Calling Conventions |
| ------------------- |
| |
| .. index:: Foreign Languages |
| |
| .. index:: Calling Conventions |
| |
| 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: |
| |
| |
| .. index:: Interfacing to Ada |
| |
| .. index:: Other Ada compilers |
| |
| .. index:: Convention Ada |
| |
| *Ada* |
| This indicates that the standard Ada calling sequence will be |
| used and all Ada data items may be passed without any limitations in the |
| case where GNAT is used to generate both the caller and callee. It is also |
| possible to mix GNAT generated code and code generated by another Ada |
| compiler. In this case, the data types should be restricted to simple |
| cases, including primitive types. Whether complex data types can be passed |
| depends on the situation. Probably it is safe to pass simple arrays, such |
| as arrays of integers or floats. Records may or may not work, depending |
| on whether both compilers lay them out identically. Complex structures |
| involving variant records, access parameters, tasks, or protected types, |
| are unlikely to be able to be passed. |
| |
| Note that in the case of GNAT running |
| on a platform that supports HP Ada 83, a higher degree of compatibility |
| can be guaranteed, and in particular records are laid out in an identical |
| manner in the two compilers. Note also that if output from two different |
| compilers is mixed, the program is responsible for dealing with elaboration |
| issues. Probably the safest approach is to write the main program in the |
| version of Ada other than GNAT, so that it takes care of its own elaboration |
| requirements, and then call the GNAT-generated adainit procedure to ensure |
| elaboration of the GNAT components. Consult the documentation of the other |
| Ada compiler for further details on elaboration. |
| |
| However, it is not possible to mix the tasking run time of GNAT and |
| HP Ada 83, All the tasking operations must either be entirely within |
| GNAT compiled sections of the program, or entirely within HP Ada 83 |
| compiled sections of the program. |
| |
| .. index:: Interfacing to Assembly |
| |
| .. index:: Convention Assembler |
| |
| |
| *Assembler* |
| Specifies assembler as the convention. In practice this has the |
| same effect as convention Ada (but is not equivalent in the sense of being |
| considered the same convention). |
| |
| .. index:: Convention Asm |
| |
| .. index:: Asm |
| |
| *Asm* |
| Equivalent to Assembler. |
| |
| .. index:: Interfacing to COBOL |
| |
| .. index:: Convention COBOL |
| |
| .. index:: COBOL |
| |
| *COBOL* |
| Data will be passed according to the conventions described |
| in section B.4 of the Ada Reference Manual. |
| |
| .. index:: C |
| .. index:: Interfacing to C |
| |
| .. index:: Convention C |
| |
| |
| *C* |
| Data will be passed according to the conventions described |
| in section B.3 of the Ada Reference Manual. |
| |
| A note on interfacing to a C 'varargs' function: |
| |
| .. index:: C varargs function |
| .. index:: Interfacing to C varargs function |
| .. index:: varargs function interfaces |
| |
| In C, `varargs` allows a function to take a variable number of |
| arguments. There is no direct equivalent in this to Ada. One |
| approach that can be used is to create a C wrapper for each |
| different profile and then interface to this C wrapper. For |
| example, to print an `int` value using `printf`, |
| create a C function `printfi` that takes two arguments, a |
| pointer to a string and an int, and calls `printf`. |
| Then in the Ada program, use pragma `Import` to |
| interface to `printfi`. |
| |
| It may work on some platforms to directly interface to |
| a `varargs` function by providing a specific Ada profile |
| for a particular call. However, this does not work on |
| all platforms, since there is no guarantee that the |
| calling sequence for a two argument normal C function |
| is the same as for calling a `varargs` C function with |
| the same two arguments. |
| |
| .. index:: Convention Default |
| |
| .. index:: Default |
| |
| *Default* |
| Equivalent to C. |
| |
| .. index:: Convention External |
| |
| .. index:: External |
| |
| *External* |
| Equivalent to C. |
| |
| .. index:: C++ |
| .. index:: Interfacing to C++ |
| |
| .. index:: Convention C++ |
| |
| |
| *C_Plus_Plus (or CPP)* |
| This stands for C++. For most purposes this is identical to C. |
| See the separate description of the specialized GNAT pragmas relating to |
| C++ interfacing for further details. |
| |
| .. index:: Fortran |
| .. index:: Interfacing to Fortran |
| .. index:: Convention Fortran |
| |
| |
| *Fortran* |
| Data will be passed according to the conventions described |
| in section B.5 of the Ada Reference Manual. |
| |
| |
| *Intrinsic* |
| This applies to an intrinsic operation, as defined in the Ada |
| Reference Manual. If a pragma Import (Intrinsic) applies to a subprogram, |
| this means that the body of the subprogram is provided by the compiler itself, |
| usually by means of an efficient code sequence, and that the user does not |
| supply an explicit body for it. In an application program, the pragma may |
| be applied to the following sets of names: |
| |
| |
| * Rotate_Left, Rotate_Right, Shift_Left, Shift_Right, Shift_Right_Arithmetic. |
| The corresponding subprogram declaration must have |
| two formal parameters. The |
| first one must be a signed integer type or a modular type with a binary |
| modulus, and the second parameter must be of type Natural. |
| The return type must be the same as the type of the first argument. The size |
| of this type can only be 8, 16, 32, or 64. |
| |
| |
| * Binary arithmetic operators: '+', '-', '*', '/'. |
| The corresponding operator declaration must have parameters and result type |
| that have the same root numeric type (for example, all three are long_float |
| types). This simplifies the definition of operations that use type checking |
| to perform dimensional checks: |
| |
| |
| .. code-block: ada |
| |
| type Distance is new Long_Float; |
| type Time is new Long_Float; |
| type Velocity is new Long_Float; |
| function "/" (D : Distance; T : Time) |
| return Velocity; |
| pragma Import (Intrinsic, "/"); |
| |
| This common idiom is often programmed with a generic definition and an |
| explicit body. The pragma makes it simpler to introduce such declarations. |
| It incurs no overhead in compilation time or code size, because it is |
| implemented as a single machine instruction. |
| |
| |
| * General subprogram entities. This is used to bind an Ada subprogram |
| declaration to |
| a compiler builtin by name with back-ends where such interfaces are |
| available. A typical example is the set of `__builtin` functions |
| exposed by the GCC back-end, as in the following example: |
| |
| |
| .. code-block:: ada |
| |
| function builtin_sqrt (F : Float) return Float; |
| pragma Import (Intrinsic, builtin_sqrt, "__builtin_sqrtf"); |
| |
| Most of the GCC builtins are accessible this way, and as for other |
| import conventions (e.g. C), it is the user's responsibility to ensure |
| that the Ada subprogram profile matches the underlying builtin |
| expectations. |
| |
| .. index:: Stdcall |
| .. index:: Convention Stdcall |
| |
| *Stdcall* |
| This is relevant only to Windows XP/2000/NT implementations of GNAT, |
| and specifies that the `Stdcall` calling sequence will be used, |
| as defined by the NT API. Nevertheless, to ease building |
| cross-platform bindings this convention will be handled as a `C` calling |
| convention on non-Windows platforms. |
| |
| .. index:: DLL |
| .. index:: Convention DLL |
| |
| |
| *DLL* |
| This is equivalent to `Stdcall`. |
| |
| .. index:: Win32 |
| .. index:: Convention Win32 |
| |
| |
| *Win32* |
| This is equivalent to `Stdcall`. |
| |
| .. index:: Stubbed |
| .. index:: Convention Stubbed |
| |
| |
| *Stubbed* |
| This is a special convention that indicates that the compiler |
| should provide a stub body that raises `Program_Error`. |
| |
| GNAT additionally provides a useful pragma `Convention_Identifier` |
| that can be used to parameterize conventions and allow additional synonyms |
| to be specified. For example if you have legacy code in which the convention |
| identifier Fortran77 was used for Fortran, you can use the configuration |
| pragma: |
| |
| .. code-block:: ada |
| |
| pragma Convention_Identifier (Fortran77, Fortran); |
| |
| And from now on the identifier Fortran77 may be used as a convention |
| identifier (for example in an `Import` pragma) with the same |
| meaning as Fortran. |
| |
| |
| .. _Building_Mixed_Ada_and_C++_Programs: |
| |
| Building Mixed Ada and C++ Programs |
| ----------------------------------- |
| |
| A programmer inexperienced with mixed-language development may find that |
| building an application containing both Ada and C++ code can be a |
| challenge. This section gives a few hints that should make this task easier. |
| |
| .. _Interfacing_to_C++: |
| |
| Interfacing to C++ |
| ^^^^^^^^^^^^^^^^^^ |
| |
| GNAT supports interfacing with the G++ compiler (or any C++ compiler |
| generating code that is compatible with the G++ Application Binary |
| Interface ---see http://www.codesourcery.com/archives/cxx-abi). |
| |
| Interfacing can be done at 3 levels: simple data, subprograms, and |
| classes. In the first two cases, GNAT offers a specific `Convention C_Plus_Plus` |
| (or `CPP`) that behaves exactly like `Convention C`. |
| Usually, C++ mangles the names of subprograms. To generate proper mangled |
| names automatically, see :ref:`Generating_Ada_Bindings_for_C_and_C++_headers`). |
| This problem can also be addressed manually in two ways: |
| |
| * by modifying the C++ code in order to force a C convention using |
| the `extern "C"` syntax. |
| |
| * by figuring out the mangled name (using e.g. *nm*) and using it as the |
| Link_Name argument of the pragma import. |
| |
| Interfacing at the class level can be achieved by using the GNAT specific |
| pragmas such as `CPP_Constructor`. See the :title:`GNAT_Reference_Manual` for additional information. |
| |
| .. _Linking_a_Mixed_C++_and_Ada_Program: |
| |
| Linking a Mixed C++ & Ada Program |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| Usually the linker of the C++ development system must be used to link |
| mixed applications because most C++ systems will resolve elaboration |
| issues (such as calling constructors on global class instances) |
| transparently during the link phase. GNAT has been adapted to ease the |
| use of a foreign linker for the last phase. Three cases can be |
| considered: |
| |
| |
| * Using GNAT and G++ (GNU C++ compiler) from the same GCC installation: |
| The C++ linker can simply be called by using the C++ specific driver |
| called `g++`. |
| |
| Note that if the C++ code uses inline functions, you will need to |
| compile your C++ code with the `-fkeep-inline-functions` switch in |
| order to provide an existing function implementation that the Ada code can |
| link with. |
| |
| .. code-block:: sh |
| |
| $ g++ -c -fkeep-inline-functions file1.C |
| $ g++ -c -fkeep-inline-functions file2.C |
| $ gnatmake ada_unit -largs file1.o file2.o --LINK=g++ |
| |
| |
| * Using GNAT and G++ from two different GCC installations: If both |
| compilers are on the :envvar`PATH`, the previous method may be used. It is |
| important to note that environment variables such as |
| :envvar:`C_INCLUDE_PATH`, :envvar:`GCC_EXEC_PREFIX`, |
| :envvar:`BINUTILS_ROOT`, and |
| :envvar:`GCC_ROOT` will affect both compilers |
| at the same time and may make one of the two compilers operate |
| improperly if set during invocation of the wrong compiler. It is also |
| very important that the linker uses the proper :file:`libgcc.a` GCC |
| library -- that is, the one from the C++ compiler installation. The |
| implicit link command as suggested in the `gnatmake` command |
| from the former example can be replaced by an explicit link command with |
| the full-verbosity option in order to verify which library is used: |
| |
| .. code-block:: sh |
| |
| $ gnatbind ada_unit |
| $ gnatlink -v -v ada_unit file1.o file2.o --LINK=c++ |
| |
| If there is a problem due to interfering environment variables, it can |
| be worked around by using an intermediate script. The following example |
| shows the proper script to use when GNAT has not been installed at its |
| default location and g++ has been installed at its default location: |
| |
| .. code-block:: sh |
| |
| $ cat ./my_script |
| #!/bin/sh |
| unset BINUTILS_ROOT |
| unset GCC_ROOT |
| c++ $* |
| $ gnatlink -v -v ada_unit file1.o file2.o --LINK=./my_script |
| |
| |
| * Using a non-GNU C++ compiler: The commands previously described can be |
| used to insure that the C++ linker is used. Nonetheless, you need to add |
| a few more parameters to the link command line, depending on the exception |
| mechanism used. |
| |
| If the `setjmp/longjmp` exception mechanism is used, only the paths |
| to the libgcc libraries are required: |
| |
| .. code-block:: sh |
| |
| $ cat ./my_script |
| #!/bin/sh |
| CC $* `gcc -print-file-name=libgcc.a` `gcc -print-file-name=libgcc_eh.a` |
| $ gnatlink ada_unit file1.o file2.o --LINK=./my_script |
| |
| |
| where CC is the name of the non-GNU C++ compiler. |
| |
| If the `zero cost` exception mechanism is used, and the platform |
| supports automatic registration of exception tables (e.g., Solaris), |
| paths to more objects are required: |
| |
| .. code-block:: sh |
| |
| $ cat ./my_script |
| #!/bin/sh |
| CC `gcc -print-file-name=crtbegin.o` $* \\ |
| `gcc -print-file-name=libgcc.a` `gcc -print-file-name=libgcc_eh.a` \\ |
| `gcc -print-file-name=crtend.o` |
| $ gnatlink ada_unit file1.o file2.o --LINK=./my_script |
| |
| |
| If the "zero cost exception" mechanism is used, and the platform |
| doesn't support automatic registration of exception tables (e.g., HP-UX |
| or AIX), the simple approach described above will not work and |
| a pre-linking phase using GNAT will be necessary. |
| |
| |
| Another alternative is to use the :command:`gprbuild` multi-language builder |
| which has a large knowledge base and knows how to link Ada and C++ code |
| together automatically in most cases. |
| |
| .. _A_Simple_Example: |
| |
| A Simple Example |
| ^^^^^^^^^^^^^^^^ |
| |
| The following example, provided as part of the GNAT examples, shows how |
| to achieve procedural interfacing between Ada and C++ in both |
| directions. The C++ class A has two methods. The first method is exported |
| to Ada by the means of an extern C wrapper function. The second method |
| calls an Ada subprogram. On the Ada side, The C++ calls are modelled by |
| a limited record with a layout comparable to the C++ class. The Ada |
| subprogram, in turn, calls the C++ method. So, starting from the C++ |
| main program, the process passes back and forth between the two |
| languages. |
| |
| Here are the compilation commands: |
| |
| .. code-block:: sh |
| |
| $ gnatmake -c simple_cpp_interface |
| $ g++ -c cpp_main.C |
| $ g++ -c ex7.C |
| $ gnatbind -n simple_cpp_interface |
| $ gnatlink simple_cpp_interface -o cpp_main --LINK=g++ -lstdc++ ex7.o cpp_main.o |
| |
| Here are the corresponding sources: |
| |
| .. code-block:: cpp |
| |
| //cpp_main.C |
| |
| #include "ex7.h" |
| |
| extern "C" { |
| void adainit (void); |
| void adafinal (void); |
| void method1 (A *t); |
| } |
| |
| void method1 (A *t) |
| { |
| t->method1 (); |
| } |
| |
| int main () |
| { |
| A obj; |
| adainit (); |
| obj.method2 (3030); |
| adafinal (); |
| } |
| |
| .. code-block:: cpp |
| |
| //ex7.h |
| |
| class Origin { |
| public: |
| int o_value; |
| }; |
| class A : public Origin { |
| public: |
| void method1 (void); |
| void method2 (int v); |
| A(); |
| int a_value; |
| }; |
| |
| .. code-block:: cpp |
| |
| //ex7.C |
| |
| #include "ex7.h" |
| #include <stdio.h> |
| |
| extern "C" { void ada_method2 (A *t, int v);} |
| |
| void A::method1 (void) |
| { |
| a_value = 2020; |
| printf ("in A::method1, a_value = %d \\n",a_value); |
| } |
| |
| void A::method2 (int v) |
| { |
| ada_method2 (this, v); |
| printf ("in A::method2, a_value = %d \\n",a_value); |
| } |
| |
| A::A(void) |
| { |
| a_value = 1010; |
| printf ("in A::A, a_value = %d \\n",a_value); |
| } |
| |
| .. code-block:: ada |
| |
| -- simple_cpp_interface.ads |
| with System; |
| package Simple_Cpp_Interface is |
| type A is limited |
| record |
| Vptr : System.Address; |
| O_Value : Integer; |
| A_Value : Integer; |
| end record; |
| pragma Convention (C, A); |
| |
| procedure Method1 (This : in out A); |
| pragma Import (C, Method1); |
| |
| procedure Ada_Method2 (This : in out A; V : Integer); |
| pragma Export (C, Ada_Method2); |
| |
| end Simple_Cpp_Interface; |
| |
| .. code-block:: ada |
| |
| -- simple_cpp_interface.adb |
| package body Simple_Cpp_Interface is |
| |
| procedure Ada_Method2 (This : in out A; V : Integer) is |
| begin |
| Method1 (This); |
| This.A_Value := V; |
| end Ada_Method2; |
| |
| end Simple_Cpp_Interface; |
| |
| |
| .. _Interfacing_with_C++_constructors: |
| |
| Interfacing with C++ constructors |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| In order to interface with C++ constructors GNAT provides the |
| `pragma CPP_Constructor` (see the :title:`GNAT_Reference_Manual` |
| for additional information). |
| In this section we present some common uses of C++ constructors |
| in mixed-languages programs in GNAT. |
| |
| Let us assume that we need to interface with the following |
| C++ class: |
| |
| .. code-block:: cpp |
| |
| class Root { |
| public: |
| int a_value; |
| int b_value; |
| virtual int Get_Value (); |
| Root(); // Default constructor |
| Root(int v); // 1st non-default constructor |
| Root(int v, int w); // 2nd non-default constructor |
| }; |
| |
| For this purpose we can write the following package spec (further |
| information on how to build this spec is available in |
| :ref:`Interfacing_with_C++_at_the_Class_Level` and |
| :ref:`Generating_Ada_Bindings_for_C_and_C++_headers`). |
| |
| .. code-block:: ada |
| |
| with Interfaces.C; use Interfaces.C; |
| package Pkg_Root is |
| type Root is tagged limited record |
| A_Value : int; |
| B_Value : int; |
| end record; |
| pragma Import (CPP, Root); |
| |
| function Get_Value (Obj : Root) return int; |
| pragma Import (CPP, Get_Value); |
| |
| function Constructor return Root; |
| pragma Cpp_Constructor (Constructor, "_ZN4RootC1Ev"); |
| |
| function Constructor (v : Integer) return Root; |
| pragma Cpp_Constructor (Constructor, "_ZN4RootC1Ei"); |
| |
| function Constructor (v, w : Integer) return Root; |
| pragma Cpp_Constructor (Constructor, "_ZN4RootC1Eii"); |
| end Pkg_Root; |
| |
| On the Ada side the constructor is represented by a function (whose |
| name is arbitrary) that returns the classwide type corresponding to |
| the imported C++ class. Although the constructor is described as a |
| function, it is typically a procedure with an extra implicit argument |
| (the object being initialized) at the implementation level. GNAT |
| issues the appropriate call, whatever it is, to get the object |
| properly initialized. |
| |
| Constructors can only appear in the following contexts: |
| |
| * On the right side of an initialization of an object of type `T`. |
| * On the right side of an initialization of a record component of type `T`. |
| * In an Ada 2005 limited aggregate. |
| * In an Ada 2005 nested limited aggregate. |
| * In an Ada 2005 limited aggregate that initializes an object built in |
| place by an extended return statement. |
| |
| In a declaration of an object whose type is a class imported from C++, |
| either the default C++ constructor is implicitly called by GNAT, or |
| else the required C++ constructor must be explicitly called in the |
| expression that initializes the object. For example: |
| |
| .. code-block:: ada |
| |
| Obj1 : Root; |
| Obj2 : Root := Constructor; |
| Obj3 : Root := Constructor (v => 10); |
| Obj4 : Root := Constructor (30, 40); |
| |
| The first two declarations are equivalent: in both cases the default C++ |
| constructor is invoked (in the former case the call to the constructor is |
| implicit, and in the latter case the call is explicit in the object |
| declaration). `Obj3` is initialized by the C++ non-default constructor |
| that takes an integer argument, and `Obj4` is initialized by the |
| non-default C++ constructor that takes two integers. |
| |
| Let us derive the imported C++ class in the Ada side. For example: |
| |
| .. code-block:: ada |
| |
| type DT is new Root with record |
| C_Value : Natural := 2009; |
| end record; |
| |
| In this case the components DT inherited from the C++ side must be |
| initialized by a C++ constructor, and the additional Ada components |
| of type DT are initialized by GNAT. The initialization of such an |
| object is done either by default, or by means of a function returning |
| an aggregate of type DT, or by means of an extension aggregate. |
| |
| .. code-block:: ada |
| |
| Obj5 : DT; |
| Obj6 : DT := Function_Returning_DT (50); |
| Obj7 : DT := (Constructor (30,40) with C_Value => 50); |
| |
| The declaration of `Obj5` invokes the default constructors: the |
| C++ default constructor of the parent type takes care of the initialization |
| of the components inherited from Root, and GNAT takes care of the default |
| initialization of the additional Ada components of type DT (that is, |
| `C_Value` is initialized to value 2009). The order of invocation of |
| the constructors is consistent with the order of elaboration required by |
| Ada and C++. That is, the constructor of the parent type is always called |
| before the constructor of the derived type. |
| |
| Let us now consider a record that has components whose type is imported |
| from C++. For example: |
| |
| .. code-block:: ada |
| |
| type Rec1 is limited record |
| Data1 : Root := Constructor (10); |
| Value : Natural := 1000; |
| end record; |
| |
| type Rec2 (D : Integer := 20) is limited record |
| Rec : Rec1; |
| Data2 : Root := Constructor (D, 30); |
| end record; |
| |
| The initialization of an object of type `Rec2` will call the |
| non-default C++ constructors specified for the imported components. |
| For example: |
| |
| .. code-block:: ada |
| |
| Obj8 : Rec2 (40); |
| |
| Using Ada 2005 we can use limited aggregates to initialize an object |
| invoking C++ constructors that differ from those specified in the type |
| declarations. For example: |
| |
| .. code-block:: ada |
| |
| Obj9 : Rec2 := (Rec => (Data1 => Constructor (15, 16), |
| others => <>), |
| others => <>); |
| |
| The above declaration uses an Ada 2005 limited aggregate to |
| initialize `Obj9`, and the C++ constructor that has two integer |
| arguments is invoked to initialize the `Data1` component instead |
| of the constructor specified in the declaration of type `Rec1`. In |
| Ada 2005 the box in the aggregate indicates that unspecified components |
| are initialized using the expression (if any) available in the component |
| declaration. That is, in this case discriminant `D` is initialized |
| to value `20`, `Value` is initialized to value 1000, and the |
| non-default C++ constructor that handles two integers takes care of |
| initializing component `Data2` with values `20,30`. |
| |
| In Ada 2005 we can use the extended return statement to build the Ada |
| equivalent to C++ non-default constructors. For example: |
| |
| .. code-block:: ada |
| |
| function Constructor (V : Integer) return Rec2 is |
| begin |
| return Obj : Rec2 := (Rec => (Data1 => Constructor (V, 20), |
| others => <>), |
| others => <>) do |
| -- Further actions required for construction of |
| -- objects of type Rec2 |
| ... |
| end record; |
| end Constructor; |
| |
| In this example the extended return statement construct is used to |
| build in place the returned object whose components are initialized |
| by means of a limited aggregate. Any further action associated with |
| the constructor can be placed inside the construct. |
| |
| .. _Interfacing_with_C++_at_the_Class_Level: |
| |
| Interfacing with C++ at the Class Level |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| In this section we demonstrate the GNAT features for interfacing with |
| C++ by means of an example making use of Ada 2005 abstract interface |
| types. This example consists of a classification of animals; classes |
| have been used to model our main classification of animals, and |
| interfaces provide support for the management of secondary |
| classifications. We first demonstrate a case in which the types and |
| constructors are defined on the C++ side and imported from the Ada |
| side, and latter the reverse case. |
| |
| The root of our derivation will be the `Animal` class, with a |
| single private attribute (the `Age` of the animal), a constructor, |
| and two public primitives to set and get the value of this attribute. |
| |
| .. code-block:: cpp |
| |
| class Animal { |
| public: |
| virtual void Set_Age (int New_Age); |
| virtual int Age (); |
| Animal() {Age_Count = 0;}; |
| private: |
| int Age_Count; |
| }; |
| |
| Abstract interface types are defined in C++ by means of classes with pure |
| virtual functions and no data members. In our example we will use two |
| interfaces that provide support for the common management of `Carnivore` |
| and `Domestic` animals: |
| |
| .. code-block:: cpp |
| |
| class Carnivore { |
| public: |
| virtual int Number_Of_Teeth () = 0; |
| }; |
| |
| class Domestic { |
| public: |
| virtual void Set_Owner (char* Name) = 0; |
| }; |
| |
| Using these declarations, we can now say that a `Dog` is an animal that is |
| both Carnivore and Domestic, that is: |
| |
| .. code-block:: cpp |
| |
| class Dog : Animal, Carnivore, Domestic { |
| public: |
| virtual int Number_Of_Teeth (); |
| virtual void Set_Owner (char* Name); |
| |
| Dog(); // Constructor |
| private: |
| int Tooth_Count; |
| char *Owner; |
| }; |
| |
| In the following examples we will assume that the previous declarations are |
| located in a file named `animals.h`. The following package demonstrates |
| how to import these C++ declarations from the Ada side: |
| |
| .. code-block:: ada |
| |
| with Interfaces.C.Strings; use Interfaces.C.Strings; |
| package Animals is |
| type Carnivore is limited interface; |
| pragma Convention (C_Plus_Plus, Carnivore); |
| function Number_Of_Teeth (X : Carnivore) |
| return Natural is abstract; |
| |
| type Domestic is limited interface; |
| pragma Convention (C_Plus_Plus, Domestic); |
| procedure Set_Owner |
| (X : in out Domestic; |
| Name : Chars_Ptr) is abstract; |
| |
| type Animal is tagged limited record |
| Age : Natural; |
| end record; |
| pragma Import (C_Plus_Plus, Animal); |
| |
| procedure Set_Age (X : in out Animal; Age : Integer); |
| pragma Import (C_Plus_Plus, Set_Age); |
| |
| function Age (X : Animal) return Integer; |
| pragma Import (C_Plus_Plus, Age); |
| |
| function New_Animal return Animal; |
| pragma CPP_Constructor (New_Animal); |
| pragma Import (CPP, New_Animal, "_ZN6AnimalC1Ev"); |
| |
| type Dog is new Animal and Carnivore and Domestic with record |
| Tooth_Count : Natural; |
| Owner : String (1 .. 30); |
| end record; |
| pragma Import (C_Plus_Plus, Dog); |
| |
| function Number_Of_Teeth (A : Dog) return Natural; |
| pragma Import (C_Plus_Plus, Number_Of_Teeth); |
| |
| procedure Set_Owner (A : in out Dog; Name : Chars_Ptr); |
| pragma Import (C_Plus_Plus, Set_Owner); |
| |
| function New_Dog return Dog; |
| pragma CPP_Constructor (New_Dog); |
| pragma Import (CPP, New_Dog, "_ZN3DogC2Ev"); |
| end Animals; |
| |
| Thanks to the compatibility between GNAT run-time structures and the C++ ABI, |
| interfacing with these C++ classes is easy. The only requirement is that all |
| the primitives and components must be declared exactly in the same order in |
| the two languages. |
| |
| Regarding the abstract interfaces, we must indicate to the GNAT compiler by |
| means of a `pragma Convention (C_Plus_Plus)`, the convention used to pass |
| the arguments to the called primitives will be the same as for C++. For the |
| imported classes we use `pragma Import` with convention `C_Plus_Plus` |
| to indicate that they have been defined on the C++ side; this is required |
| because the dispatch table associated with these tagged types will be built |
| in the C++ side and therefore will not contain the predefined Ada primitives |
| which Ada would otherwise expect. |
| |
| As the reader can see there is no need to indicate the C++ mangled names |
| associated with each subprogram because it is assumed that all the calls to |
| these primitives will be dispatching calls. The only exception is the |
| constructor, which must be registered with the compiler by means of |
| `pragma CPP_Constructor` and needs to provide its associated C++ |
| mangled name because the Ada compiler generates direct calls to it. |
| |
| With the above packages we can now declare objects of type Dog on the Ada side |
| and dispatch calls to the corresponding subprograms on the C++ side. We can |
| also extend the tagged type Dog with further fields and primitives, and |
| override some of its C++ primitives on the Ada side. For example, here we have |
| a type derivation defined on the Ada side that inherits all the dispatching |
| primitives of the ancestor from the C++ side. |
| |
| .. code-block:: ada |
| |
|