[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This chapter describes GNAT's Project Manager, a facility that allows you to manage complex builds involving a number of source files, directories, and compilation options for different system configurations. In particular, project files allow you to specify:
gnatmake
, compiler, binder, linker, gnatls
, gnatxref
,
gnatfind
); you can apply these settings either globally or to individual
compilation units.
11.1.1 Project Files
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Project files are written in a syntax close to that of Ada, using familiar notions such as packages, context clauses, declarations, default values, assignments, and inheritance. Finally, project files can be built hierarchically from other project files, simplifying complex system integration and project reuse.
A project is a specific set of values for various compilation properties. The settings for a given project are described by means of a project file, which is a text file written in an Ada-like syntax. Property values in project files are either strings or lists of strings. Properties that are not explicitly set receive default values. A project file may interrogate the values of external variables (user-defined command-line switches or environment variables), and it may specify property settings conditionally, based on the value of such variables.
In simple cases, a project's source files depend only on other source files
in the same project, or on the predefined libraries. (Dependence is
used in
the Ada technical sense; as in one Ada unit with
ing another.) However,
the Project Manager also allows more sophisticated arrangements,
where the source files in one project depend on source files in other
projects:
More generally, the Project Manager lets you structure large development efforts into hierarchical subsystems, where build decisions are delegated to the subsystem level, and thus different compilation environments (switch settings) used for different subsystems.
The Project Manager is invoked through the
`-Pprojectfile'
switch to gnatmake
or to the gnat
front driver.
There may be zero, one or more spaces between `-P' and
`projectfile'.
If you want to define (on the command line) an external variable that is
queried by the project file, you must use the
`-Xvbl=value' switch.
The Project Manager parses and interprets the project file, and drives the
invoked tool based on the project settings.
The Project Manager supports a wide range of development strategies, for systems of all sizes. Here are some typical practices that are easily handled:
The destination of an executable can be controlled inside a project file
using the `-o'
switch.
In the absence of such a switch either inside
the project file or on the command line, any executable files generated by
gnatmake
are placed in the directory Exec_Dir
specified
in the project file. If no Exec_Dir
is specified, they will be placed
in the object directory of the project.
You can use project files to achieve some of the effects of a source versioning system (for example, defining separate projects for the different sets of sources that comprise different releases) but the Project Manager is independent of any source configuration management tools that might be used by the developers.
The next section introduces the main features of GNAT's project facility through a sequence of examples; subsequent sections will present the syntax and semantics in more detail. A more formal description of the project facility appears in the GNAT Reference Manual.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
11.2.1 Common Sources with Different Switches and Directories 11.2.2 Using External Variables 11.2.3 Importing Other Projects 11.2.4 Extending a Project
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Suppose that the Ada source files `pack.ads', `pack.adb', and
`proc.adb' are in the `/common' directory. The file
`proc.adb' contains an Ada main subprogram Proc
that with
s
package Pack
. We want to compile these source files under two sets
of switches:
gnatmake
,
and the `-gnata',
`-gnato',
and `-gnatE' switches to the
compiler; the compiler's output is to appear in `/common/debug'
The GNAT project files shown below, respectively `debug.gpr' and `release.gpr' in the `/common' directory, achieve these effects.
Schematically:
/common debug.gpr release.gpr pack.ads pack.adb proc.adb /common/debug proc.ali, proc.o pack.ali, pack.o /common/release proc.ali, proc.o pack.ali, pack.o |
project Debug is for Object_Dir use "debug"; for Main use ("proc"); package Builder is for Default_Switches ("Ada") use ("-g"); for Executable ("proc.adb") use "proc1"; end Builder; package Compiler is for Default_Switches ("Ada") use ("-fstack-check", "-gnata", "-gnato", "-gnatE"); end Compiler; end Debug; |
project Release is for Object_Dir use "release"; for Exec_Dir use "."; for Main use ("proc"); package Compiler is for Default_Switches ("Ada") use ("-O2"); end Compiler; end Release; |
The name of the project defined by `debug.gpr' is "Debug"
(case
insensitive), and analogously the project defined by `release.gpr' is
"Release"
. For consistency the file should have the same name as the
project, and the project file's extension should be "gpr"
. These
conventions are not required, but a warning is issued if they are not followed.
If the current directory is `/temp', then the command
gnatmake -P/common/debug.gpr |
generates object and ALI files in `/common/debug',
as well as the proc1
executable,
using the switch settings defined in the project file.
Likewise, the command
gnatmake -P/common/release.gpr |
generates object and ALI files in `/common/release',
and the proc
executable in `/common',
using the switch settings from the project file.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
If a project file does not explicitly specify a set of source directories or a set of source files, then by default the project's source files are the Ada source files in the project file directory. Thus `pack.ads', `pack.adb', and `proc.adb' are the source files for both projects.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Several project properties are modeled by Ada-style attributes;
a property is defined by supplying the equivalent of an Ada attribute
definition clause in the project file.
A project's object directory is another such a property; the corresponding
attribute is Object_Dir
, and its value is also a string expression,
specified either as absolute or relative. In the later case,
it is relative to the project file directory. Thus the compiler's
output is directed to `/common/debug'
(for the Debug
project)
and to `/common/release'
(for the Release
project).
If Object_Dir
is not specified, then the default is the project file
directory itself.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A project's exec directory is another property; the corresponding
attribute is Exec_Dir
, and its value is also a string expression,
either specified as relative or absolute. If Exec_Dir
is not specified,
then the default is the object directory (which may also be the project file
directory if attribute Object_Dir
is not specified). Thus the executable
is placed in `/common/debug'
for the Debug
project (attribute Exec_Dir
not specified)
and in `/common' for the Release
project.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A GNAT tool that is integrated with the Project Manager is modeled by a
corresponding package in the project file. In the example above,
The Debug
project defines the packages Builder
(for gnatmake
) and Compiler
;
the Release
project defines only the Compiler
package.
The Ada-like package syntax is not to be taken literally. Although packages in project files bear a surface resemblance to packages in Ada source code, the notation is simply a way to convey a grouping of properties for a named entity. Indeed, the package names permitted in project files are restricted to a predefined set, corresponding to the project-aware tools, and the contents of packages are limited to a small set of constructs. The packages in the example above contain attribute definitions.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Switch settings for a project-aware tool can be specified through
attributes in the package that corresponds to the tool.
The example above illustrates one of the relevant attributes,
Default_Switches
, which is defined in packages
in both project files.
Unlike simple attributes like Source_Dirs
,
Default_Switches
is
known as an associative array. When you define this attribute, you must
supply an "index" (a literal string), and the effect of the attribute
definition is to set the value of the array at the specified index.
For the Default_Switches
attribute,
the index is a programming language (in our case, Ada),
and the value specified (after use
) must be a list
of string expressions.
The attributes permitted in project files are restricted to a predefined set. Some may appear at project level, others in packages. For any attribute that is an associative array, the index must always be a literal string, but the restrictions on this string (e.g., a file name or a language name) depend on the individual attribute. Also depending on the attribute, its specified value will need to be either a string or a string list.
In the Debug
project, we set the switches for two tools,
gnatmake
and the compiler, and thus we include the two corresponding
packages; each package defines the Default_Switches
attribute with index "Ada"
.
Note that the package corresponding to
gnatmake
is named Builder
. The Release
project is
similar, but only includes the Compiler
package.
In project Debug
above, the switches starting with
`-gnat' that are specified in package Compiler
could have been placed in package Builder
, since gnatmake
transmits all such switches to the compiler.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
One of the specifiable properties of a project is a list of files that contain
main subprograms. This property is captured in the Main
attribute,
whose value is a list of strings. If a project defines the Main
attribute, it is not necessary to identify the main subprogram(s) when
invoking gnatmake
(see section 11.15.1 gnatmake and Project Files).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
By default, the executable file name corresponding to a main source is
deduced from the main source file name. Through the attributes
Executable
and Executable_Suffix
of package Builder
,
it is possible to change this default.
In project Debug
above, the executable file name
for main source `proc.adb' is
`proc1'.
Attribute Executable_Suffix
, when specified, may change the suffix
of the the executable files, when no attribute Executable
applies:
its value replace the platform-specific executable suffix.
Attributes Executable
and Executable_Suffix
are the only ways to
specify a non default executable file name when several mains are built at once
in a single gnatmake
command.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Since the project files above do not specify any source file naming
conventions, the GNAT defaults are used. The mechanism for defining source
file naming conventions -- a package named Naming
--
is described below (see section 11.11 Naming Schemes).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Since the project files do not specify a Languages
attribute, by
default the GNAT tools assume that the language of the project file is Ada.
More generally, a project can comprise source files
in Ada, C, and/or other languages.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Instead of supplying different project files for debug and release, we can
define a single project file that queries an external variable (set either
on the command line or via an environment variable) in order to
conditionally define the appropriate settings. Again, assume that the
source files `pack.ads', `pack.adb', and `proc.adb' are
located in directory `/common'. The following project file,
`build.gpr', queries the external variable named STYLE
and
defines an object directory and switch settings based on whether
the value is "deb"
(debug) or "rel"
(release), and where
the default is "deb"
.
project Build is for Main use ("proc"); type Style_Type is ("deb", "rel"); Style : Style_Type := external ("STYLE", "deb"); case Style is when "deb" => for Object_Dir use "debug"; when "rel" => for Object_Dir use "release"; for Exec_Dir use "."; end case; package Builder is case Style is when "deb" => for Default_Switches ("Ada") use ("-g"); for Executable ("proc") use "proc1"; when others => null; end case; end Builder; package Compiler is case Style is when "deb" => for Default_Switches ("Ada") use ("-gnata", "-gnato", "-gnatE"); when "rel" => for Default_Switches ("Ada") use ("-O2"); end case; end Compiler; end Build; |
Style_Type
is an example of a string type, which is the project
file analog of an Ada enumeration type but whose components are string literals
rather than identifiers. Style
is declared as a variable of this type.
The form external("STYLE", "deb")
is known as an
external reference; its first argument is the name of an
external variable, and the second argument is a default value to be
used if the external variable doesn't exist. You can define an external
variable on the command line via the `-X' switch,
or you can use an environment variable
as an external variable.
Each case
construct is expanded by the Project Manager based on the
value of Style
. Thus the command
gnatmake -P/common/build.gpr -XSTYLE=deb |
is equivalent to the gnatmake
invocation using the project file
`debug.gpr' in the earlier example. So is the command
gnatmake -P/common/build.gpr |
since "deb"
is the default for STYLE
.
Analogously,
gnatmake -P/common/build.gpr -XSTYLE=rel |
is equivalent to the gnatmake
invocation using the project file
`release.gpr' in the earlier example.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A compilation unit in a source file in one project may depend on compilation
units in source files in other projects. To compile this unit under
control of a project file, the
dependent project must import the projects containing the needed source
files.
This effect is obtained using syntax similar to an Ada with
clause,
but where with
ed entities are strings that denote project files.
As an example, suppose that the two projects GUI_Proj
and
Comm_Proj
are defined in the project files `gui_proj.gpr' and
`comm_proj.gpr' in directories `/gui'
and `/comm', respectively.
Suppose that the source files for GUI_Proj
are
`gui.ads' and `gui.adb', and that the source files for
Comm_Proj
are `comm.ads' and `comm.adb', where each set of
files is located in its respective project file directory. Schematically:
/gui gui_proj.gpr gui.ads gui.adb /comm comm_proj.gpr comm.ads comm.adb |
We want to develop an application in directory `/app' that
with
the packages GUI
and Comm
, using the properties of
the corresponding project files (e.g. the switch settings
and object directory).
Skeletal code for a main procedure might be something like the following:
with GUI, Comm; procedure App_Main is ... begin ... end App_Main; |
Here is a project file, `app_proj.gpr', that achieves the desired effect:
with "/gui/gui_proj", "/comm/comm_proj"; project App_Proj is for Main use ("app_main"); end App_Proj; |
Building an executable is achieved through the command:
gnatmake -P/app/app_proj |
app_main
executable
in the directory where `app_proj.gpr' resides.
If an imported project file uses the standard extension (gpr
) then
(as illustrated above) the with
clause can omit the extension.
Our example specified an absolute path for each imported project file. Alternatively, the directory name of an imported object can be omitted if either
ADA_PROJECT_PATH
is the same as
the syntax of ADA_INCLUDE_PATH
and ADA_OBJECTS_PATH
: a list of
directory names separated by colons (semicolons on Windows).
Thus, if we define ADA_PROJECT_PATH
to include `/gui' and
`/comm', then our project file `app_proj.gpr' can be written
as follows:
with "gui_proj", "comm_proj"; project App_Proj is for Main use ("app_main"); end App_Proj; |
Importing other projects can create ambiguities. For example, the same unit might be present in different imported projects, or it might be present in both the importing project and in an imported project. Both of these conditions are errors. Note that in the current version of the Project Manager, it is illegal to have an ambiguous unit even if the unit is never referenced by the importing project. This restriction may be relaxed in a future release.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In large software systems it is common to have multiple implementations of a common interface; in Ada terms, multiple versions of a package body for the same specification. For example, one implementation might be safe for use in tasking programs, while another might only be used in sequential applications. This can be modeled in GNAT using the concept of project extension. If one project (the "child") extends another project (the "parent") then by default all source files of the parent project are inherited by the child, but the child project can override any of the parent's source files with new versions, and can also add new files. This facility is the project analog of a type extension in Object-Oriented Programming. Project hierarchies are permitted (a child project may be the parent of yet another project), and a project that inherits one project can also import other projects.
As an example, suppose that directory `/seq' contains the project file `seq_proj.gpr' as well as the source files `pack.ads', `pack.adb', and `proc.adb':
/seq pack.ads pack.adb proc.adb seq_proj.gpr |
Note that the project file can simply be empty (that is, no attribute or package is defined):
project Seq_Proj is end Seq_Proj; |
implying that its source files are all the Ada source files in the project directory.
Suppose we want to supply an alternate version of `pack.adb', in
directory `/tasking', but use the existing versions of
`pack.ads' and `proc.adb'. We can define a project
Tasking_Proj
that inherits Seq_Proj
:
/tasking pack.adb tasking_proj.gpr project Tasking_Proj extends "/seq/seq_proj" is end Tasking_Proj; |
The version of `pack.adb' used in a build depends on which project file is specified.
Note that we could have obtained the desired behavior using project import
rather than project inheritance; a base
project would contain the
sources for `pack.ads' and `proc.adb', a sequential project would
import base
and add `pack.adb', and likewise a tasking project
would import base
and add a different version of `pack.adb'. The
choice depends on whether other sources in the original project need to be
overridden. If they do, then project extension is necessary, otherwise,
importing is sufficient.
In a project file that extends another project file, it is possible to indicate that an inherited source is not part of the sources of the extending project. This is necessary sometimes when a package spec has been overloaded and no longer requires a body: in this case, it is necessary to indicate that the inherited body is not part of the sources of the project, otherwise there will be a compilation error when compiling the spec.
For that purpose, the attribute Locally_Removed_Files
is used.
Its value is a string list: a list of file names.
project B extends "a" is for Source_Files use ("pkg.ads"); -- New spec of Pkg does not need a completion for Locally_Removed_Files use ("pkg.adb"); end B; |
Attribute Locally_Removed_Files
may also be used to check if a source
is still needed: if it is possible to build using gnatmake
when such
a source is put in attribute Locally_Removed_Files
of a project P, then
it is possible to remove the source completely from a system that includes
project P.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
11.3.1 Basic Syntax 11.3.2 Packages 11.3.3 Expressions 11.3.4 String Types 11.3.5 Variables 11.3.6 Attributes 11.3.7 Associative Array Attributes 11.3.8 case
Constructions
This section describes the structure of project files.
A project may be an independent project, entirely defined by a single project file. Any Ada source file in an independent project depends only on the predefined library and other Ada source files in the same project.
A project may also depend on other projects, in either or both of the following ways:
The dependence relation is a directed acyclic graph (the subgraph reflecting the "extends" relation is a tree).
A project's immediate sources are the source files directly defined by that project, either implicitly by residing in the project file's directory, or explicitly through any of the source-related attributes described below. More generally, a project proj's sources are the immediate sources of proj together with the immediate sources (unless overridden) of any project on which proj depends (either directly or indirectly).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
As seen in the earlier examples, project files have an Ada-like syntax. The minimal project file is:
project Empty is end Empty; |
The identifier Empty
is the name of the project.
This project name must be present after the reserved
word end
at the end of the project file, followed by a semi-colon.
Any name in a project file, such as the project name or a variable name, has the same syntax as an Ada identifier.
The reserved words of project files are the Ada reserved words plus
extends
, external
, and project
. Note that the only Ada
reserved words currently used in project file syntax are:
case
end
for
is
others
package
renames
type
use
when
with
Comments in project files have the same syntax as in Ada, two consecutives hyphens through the end of the line.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A project file may contain packages. The name of a package must be one of the identifiers from the following list. A package with a given name may only appear once in a project file. Package names are case insensitive. The following package names are legal:
Naming
Builder
Compiler
Binder
Linker
Finder
Cross_Reference
Eliminate
Pretty_Printer
Metrics
gnatls
gnatstub
IDE
Language_Processing
In its simplest form, a package may be empty:
project Simple is package Builder is end Builder; end Simple; |
A package may contain attribute declarations, variable declarations and case constructions, as will be described below.
When there is ambiguity between a project name and a package name,
the name always designates the project. To avoid possible confusion, it is
always a good idea to avoid naming a project with one of the
names allowed for packages or any name that starts with gnat
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An expression is either a string expression or a string list expression.
A string expression is either a simple string expression or a compound string expression.
A simple string expression is one of the following:
"comm/my_proj.gpr"
A compound string expression is a concatenation of string expressions,
using the operator "&"
Path & "/" & File_Name & ".ads" |
A string list expression is either a simple string list expression or a compound string list expression.
A simple string list expression is one of the following:
File_Names := (File_Name, "gnat.adc", File_Name & ".orig"); Empty_List := (); |
A compound string list expression is the concatenation (using
"&"
) of a simple string list expression and an expression. Note that
each term in a compound string list expression, except the first, may be
either a string expression or a string list expression.
File_Name_List := () & File_Name; -- One string in this list Extended_File_Name_List := File_Name_List & (File_Name & ".orig"); -- Two strings Big_List := File_Name_List & Extended_File_Name_List; -- Concatenation of two string lists: three strings Illegal_List := "gnat.adc" & Extended_File_Name_List; -- Illegal: must start with a string list |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A string type declaration introduces a discrete set of string literals. If a string variable is declared to have this type, its value is restricted to the given set of literals.
Here is an example of a string type declaration:
type OS is ("NT", "nt", "Unix", "GNU/Linux", "other OS"); |
Variables of a string type are called typed variables; all other
variables are called untyped variables. Typed variables are
particularly useful in case
constructions, to support conditional
attribute declarations.
(see section 11.3.8 case
Constructions).
The string literals in the list are case sensitive and must all be different. They may include any graphic characters allowed in Ada, including spaces.
A string type may only be declared at the project level, not inside a package.
A string type may be referenced by its name if it has been declared in the same project file, or by an expanded name whose prefix is the name of the project in which it is declared.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A variable may be declared at the project file level, or within a package. Here are some examples of variable declarations:
This_OS : OS := external ("OS"); -- a typed variable declaration That_OS := "GNU/Linux"; -- an untyped variable declaration |
The syntax of a typed variable declaration is identical to the Ada syntax for an object declaration. By contrast, the syntax of an untyped variable declaration is identical to an Ada assignment statement. In fact, variable declarations in project files have some of the characteristics of an assignment, in that successive declarations for the same variable are allowed. Untyped variable declarations do establish the expected kind of the variable (string or string list), and successive declarations for it must respect the initial kind.
A string variable declaration (typed or untyped) declares a variable whose value is a string. This variable may be used as a string expression.
File_Name := "readme.txt"; Saved_File_Name := File_Name & ".saved"; |
A string list variable declaration declares a variable whose value is a list of strings. The list may contain any number (zero or more) of strings.
Empty_List := (); List_With_One_Element := ("-gnaty"); List_With_Two_Elements := List_With_One_Element & "-gnatg"; Long_List := ("main.ada", "pack1_.ada", "pack1.ada", "pack2_.ada" "pack2.ada", "util_.ada", "util.ada"); |
The same typed variable may not be declared more than once at project level, and it may not be declared more than once in any package; it is in effect a constant.
The same untyped variable may be declared several times. Declarations are elaborated in the order in which they appear, so the new value replaces the old one, and any subsequent reference to the variable uses the new value. However, as noted above, if a variable has been declared as a string, all subsequent declarations must give it a string value. Similarly, if a variable has been declared as a string list, all subsequent declarations must give it a string list value.
A variable reference may take several forms:
A context may be one of the following:
A variable reference may be used in an expression.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A project (and its packages) may have attributes that define the project's properties. Some attributes have values that are strings; others have values that are string lists.
There are two categories of attributes: simple attributes and associative arrays (see section 11.3.7 Associative Array Attributes).
Legal project attribute names, and attribute names for each legal package are listed below. Attributes names are case-insensitive.
The following attributes are defined on projects (all are simple attributes):
Attribute Name | Value |
Source_Files |
string list |
Source_Dirs |
string list |
Source_List_File |
string |
Object_Dir |
string |
Exec_Dir |
string |
Locally_Removed_Files |
string list |
Main |
string list |
Languages |
string list |
Main_Language |
string |
Library_Dir |
string |
Library_Name |
string |
Library_Kind |
string |
Library_Version |
string |
Library_Interface |
string |
Library_Auto_Init |
string |
Library_Options |
string list |
Library_GCC |
string |
The following attributes are defined for package Naming
(see section 11.11 Naming Schemes):
Attribute Name | Category | Index | Value |
Spec_Suffix |
associative array | language name | string |
Body_Suffix |
associative array | language name | string |
Separate_Suffix |
simple attribute | n/a | string |
Casing |
simple attribute | n/a | string |
Dot_Replacement |
simple attribute | n/a | string |
Spec |
associative array | Ada unit name | string |
Body |
associative array | Ada unit name | string |
Specification_Exceptions |
associative array | language name | string list |
Implementation_Exceptions |
associative array | language name | string list |
The following attributes are defined for packages Builder
,
Compiler
, Binder
,
Linker
, Cross_Reference
, and Finder
(see section 11.15.1.1 Switches and Project Files).
Attribute Name | Category | Index | Value |
Default_Switches |
associative array | language name | string list |
Switches |
associative array | file name | string list |
In addition, package Compiler
has a single string attribute
Local_Configuration_Pragmas
and package Builder
has a single
string attribute Global_Configuration_Pragmas
.
Each simple attribute has a default value: the empty string (for string-valued attributes) and the empty list (for string list-valued attributes).
An attribute declaration defines a new value for an attribute.
Examples of simple attribute declarations:
for Object_Dir use "objects"; for Source_Dirs use ("units", "test/drivers"); |
The syntax of a simple attribute declaration is similar to that of an attribute definition clause in Ada.
Attributes references may be appear in expressions.
The general form for such a reference is <entity>'<attribute>
:
Associative array attributes are functions. Associative
array attribute references must have an argument that is a string literal.
Examples are:
project'Object_Dir Naming'Dot_Replacement Imported_Project'Source_Dirs Imported_Project.Naming'Casing Builder'Default_Switches("Ada") |
The prefix of an attribute may be:
project
for an attribute of the current project
Example:
project Prj is for Source_Dirs use project'Source_Dirs & "units"; for Source_Dirs use project'Source_Dirs & "test/drivers" end Prj; |
In the first attribute declaration, initially the attribute Source_Dirs
has the default value: an empty string list. After this declaration,
Source_Dirs
is a string list of one element: "units"
.
After the second attribute declaration Source_Dirs
is a string list of
two elements: "units"
and "test/drivers"
.
Note: this example is for illustration only. In practice, the project file would contain only one attribute declaration:
for Source_Dirs use ("units", "test/drivers"); |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Some attributes are defined as associative arrays. An associative array may be regarded as a function that takes a string as a parameter and delivers a string or string list value as its result.
Here are some examples of single associative array attribute associations:
for Body ("main") use "Main.ada"; for Switches ("main.ada") use ("-v", "-gnatv"); for Switches ("main.ada") use Builder'Switches ("main.ada") & "-g"; |
Like untyped variables and simple attributes, associative array attributes may be declared several times. Each declaration supplies a new value for the attribute, and replaces the previous setting.
An associative array attribute may be declared as a full associative array declaration, with the value of the same attribute in an imported or extended project.
package Builder is for Default_Switches use Default.Builder'Default_Switches; end Builder; |
In this example, Default
must be either an project imported by the
current project, or the project that the current project extends. If the
attribute is in a package (in this case, in package Builder
), the same
package needs to be specified.
A full associative array declaration replaces any other declaration for the attribute, including other full associative array declaration. Single associative array associations may be declare after a full associative declaration, modifying the value for a single association of the attribute.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
case
Constructions
A case
construction is used in a project file to effect conditional
behavior.
Here is a typical example:
project MyProj is type OS_Type is ("GNU/Linux", "Unix", "NT", "VMS"); OS : OS_Type := external ("OS", "GNU/Linux"); package Compiler is case OS is when "GNU/Linux" | "Unix" => for Default_Switches ("Ada") use ("-gnath"); when "NT" => for Default_Switches ("Ada") use ("-gnatP"); when others => end case; end Compiler; end MyProj; |
The syntax of a case
construction is based on the Ada case statement
(although there is no null
construction for empty alternatives).
The case expression must a typed string variable.
Each alternative comprises the reserved word when
, either a list of
literal strings separated by the "|"
character or the reserved word
others
, and the "=>"
token.
Each literal string must belong to the string type that is the type of the
case variable.
An others
alternative, if present, must occur last.
After each =>
, there are zero or more constructions. The only
constructions allowed in a case construction are other case constructions and
attribute declarations. String type declarations, variable declarations and
package declarations are not allowed.
The value of the case variable is often given by an external reference (see section 11.8 External References in Project Files).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
11.4.1 Object Directory 11.4.2 Exec Directory 11.4.3 Source Directories 11.4.4 Source File Names
Each project has exactly one object directory and one or more source directories. The source directories must contain at least one source file, unless the project file explicitly specifies that no source files are present (see section 11.4.4 Source File Names).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The object directory for a project is the directory containing the compiler's output (such as `ALI' files and object files) for the project's immediate sources.
The object directory is given by the value of the attribute Object_Dir
in the project file.
for Object_Dir use "objects"; |
The attribute Object_Dir has a string value, the path name of the object directory. The path name may be absolute or relative to the directory of the project file. This directory must already exist, and be readable and writable.
By default, when the attribute Object_Dir
is not given an explicit value
or when its value is the empty string, the object directory is the same as the
directory containing the project file.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The exec directory for a project is the directory containing the executables for the project's main subprograms.
The exec directory is given by the value of the attribute Exec_Dir
in the project file.
for Exec_Dir use "executables"; |
The attribute Exec_Dir has a string value, the path name of the exec directory. The path name may be absolute or relative to the directory of the project file. This directory must already exist, and be writable.
By default, when the attribute Exec_Dir
is not given an explicit value
or when its value is the empty string, the exec directory is the same as the
object directory of the project file.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The source directories of a project are specified by the project file
attribute Source_Dirs
.
This attribute's value is a string list. If the attribute is not given an explicit value, then there is only one source directory, the one where the project file resides.
A Source_Dirs
attribute that is explicitly defined to be the empty list,
as in
for Source_Dirs use (); |
indicates that the project contains no source files.
Otherwise, each string in the string list designates one or more source directories.
for Source_Dirs use ("sources", "test/drivers"); |
If a string in the list ends with "/**"
, then the directory whose path
name precedes the two asterisks, as well as all its subdirectories
(recursively), are source directories.
for Source_Dirs use ("/system/sources/**"); |
Here the directory /system/sources
and all of its subdirectories
(recursively) are source directories.
To specify that the source directories are the directory of the project file
and all of its subdirectories, you can declare Source_Dirs
as follows:
for Source_Dirs use ("./**"); |
Each of the source directories must exist and be readable.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In a project that contains source files, their names may be specified by the
attributes Source_Files
(a string list) or Source_List_File
(a string). Source file names never include any directory information.
If the attribute Source_Files
is given an explicit value, then each
element of the list is a source file name.
for Source_Files use ("main.adb"); for Source_Files use ("main.adb", "pack1.ads", "pack2.adb"); |
If the attribute Source_Files
is not given an explicit value,
but the attribute Source_List_File
is given a string value,
then the source file names are contained in the text file whose path name
(absolute or relative to the directory of the project file) is the
value of the attribute Source_List_File
.
Each line in the file that is not empty or is not a comment contains a source file name.
for Source_List_File use "source_list.txt"; |
By default, if neither the attribute Source_Files
nor the attribute
Source_List_File
is given an explicit value, then each file in the
source directories that conforms to the project's naming scheme
(see section 11.11 Naming Schemes) is an immediate source of the project.
A warning is issued if both attributes Source_Files
and
Source_List_File
are given explicit values. In this case, the attribute
Source_Files
prevails.
Each source file name must be the name of one existing source file in one of the source directories.
A Source_Files
attribute whose value is an empty list
indicates that there are no source files in the project.
If the order of the source directories is known statically, that is if
"/**"
is not used in the string list Source_Dirs
, then there may
be several files with the same source file name. In this case, only the file
in the first directory is considered as an immediate source of the project
file. If the order of the source directories is not known statically, it is
an error to have several files with the same source file name.
Projects can be specified to have no Ada source
files: the value of (Source_Dirs
or Source_Files
may be an empty
list, or the "Ada"
may be absent from Languages
:
for Source_Dirs use (); for Source_Files use (); for Languages use ("C", "C++"); |
Otherwise, a project must contain at least one immediate source.
Projects with no source files are useful as template packages
(see section 11.9 Packages in Project Files) for other projects; in particular to
define a package Naming
(see section 11.11 Naming Schemes).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An immediate source of a project P may depend on source files that are neither immediate sources of P nor in the predefined library. To get this effect, P must import the projects that contain the needed source files.
with "project1", "utilities.gpr"; with "/namings/apex.gpr"; project Main is ... |
As can be seen in this example, the syntax for importing projects is similar
to the syntax for importing compilation units in Ada. However, project files
use literal strings instead of names, and the with
clause identifies
project files rather than packages.
Each literal string is the file name or path name (absolute or relative) of a project file. If a string is simply a file name, with no path, then its location is determined by the project path:
ADA_PROJECT_PATH
exists,
then the project path includes all the directories in this
environment variable, plus the directory of the project file.
ADA_PROJECT_PATH
does not
exist, then the project path contains only one directory, namely the one where
the project file is located.
If a relative pathname is used, as in
with "tests/proj"; |
then the path is relative to the directory where the importing project file is located. Any symbolic link will be fully resolved in the directory of the importing project file before the imported project file is examined.
If the with
'ed project file name does not have an extension,
the default is `.gpr'. If a file with this extension is not found,
then the file name as specified in the with
clause (no extension) will
be used. In the above example, if a file project1.gpr
is found, then it
will be used; otherwise, if a file project1
exists
then it will be used; if neither file exists, this is an error.
A warning is issued if the name of the project file does not match the name of the project; this check is case insensitive.
Any source file that is an immediate source of the imported project can be
used by the immediate sources of the importing project, transitively. Thus
if A
imports B
, and B
imports C
, the immediate
sources of A
may depend on the immediate sources of C
, even if
A
does not import C
explicitly. However, this is not recommended,
because if and when B
ceases to import C
, some sources in
A
will no longer compile.
A side effect of this capability is that normally cyclic dependencies are not
permitted: if A
imports B
(directly or indirectly) then B
is not allowed to import A
. However, there are cases when cyclic
dependencies would be beneficial. For these cases, another form of import
between projects exists, the limited with
: a project A
that
imports a project B
with a straigh with
may also be imported,
directly or indirectly, by B
on the condition that imports from B
to A
include at least one limited with
.
with "../b/b.gpr"; with "../c/c.gpr"; project A is end A; limited with "../a/a.gpr"; project B is end B; with "../d/d.gpr"; project C is end C; limited with "../a/a.gpr"; project D is end D; |
In the above legal example, there are two project cycles:
In each of these cycle there is one limited with
: import of A
from B
and import of A
from D
.
The difference between straight with
and limited with
is that
the name of a project imported with a limited with
cannot be used in the
project that imports it. In particular, its packages cannot be renamed and
its variables cannot be referred to.
An exception to the above rules for limited with
is that for the main
project specified to gnatmake
or to the GNAT
driver a
limited with
is equivalent to a straight with
. For example,
in the example above, projects B
and D
could not be main
projects for gnatmake
or to the GNAT
driver, because they
each have a limited with
that is the only one in a cycle of importing
projects.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
During development of a large system, it is sometimes necessary to use modified versions of some of the source files, without changing the original sources. This can be achieved through the project extension facility.
project Modified_Utilities extends "/baseline/utilities.gpr" is ... |
A project extension declaration introduces an extending project (the child) and a project being extended (the parent).
By default, a child project inherits all the sources of its parent. However, inherited sources can be overridden: a unit in a parent is hidden by a unit of the same name in the child.
Inherited sources are considered to be sources (but not immediate sources) of the child project; see 11.3 Project File Syntax.
An inherited source file retains any switches specified in the parent project.
For example if the project Utilities
contains the specification and the
body of an Ada package Util_IO
, then the project
Modified_Utilities
can contain a new body for package Util_IO
.
The original body of Util_IO
will not be considered in program builds.
However, the package specification will still be found in the project
Utilities
.
A child project can have only one parent but it may import any number of other projects.
A project is not allowed to import directly or indirectly at the same time a child project and any of its ancestors.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When extending a large system spanning multiple projects, it is often
inconvenient to extend every project in the hierarchy that is impacted by a
small change introduced. In such cases, it is possible to create a virtual
extension of entire hierarchy using extends all
relationship.
When the project is extended using extends all
inheritance, all projects
that are imported by it, both directly and indirectly, are considered virtually
extended. That is, the Project Manager creates "virtual projects"
that extend every project in the hierarchy; all these virtual projects have
no sources of their own and have as object directory the object directory of
the root of "extending all" project.
It is possible to explicitly extend one or more projects in the hierarchy in order to modify the sources. These extending projects must be imported by the "extending all" project, which will replace the corresponding virtual projects with the explicit ones.
When building such a project hierarchy extension, the Project Manager will ensure that both modified sources and sources in virtual extending projects that depend on them, are recompiled.
By means of example, consider the following hierarchy of projects.
We want to modify packages P1 and P3.
This project hierarchy will need to be extended as follows:
project A1 extends "(...)/A" is end A1; |
with "(...)/A1"; project C1 extends all "(...)/C" is end C1; |
When you build project C1, your entire modified project space will be recompiled, including the virtual project B1 that has been impacted by the "extending all" inheritance of project C.
Note that if a Library Project in the hierarchy is virtually extended, the virtual project that extends the Library Project is not a Library Project.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A project file may contain references to external variables; such references are called external references.
An external variable is either defined as part of the environment (an environment variable in Unix, for example) or else specified on the command line via the `-Xvbl=value' switch. If both, then the command line value is used.
The value of an external reference is obtained by means of the built-in
function external
, which returns a string value.
This function has two forms:
external (external_variable_name)
external (external_variable_name, default_value)
Each parameter must be a string literal. For example:
external ("USER") external ("OS", "GNU/Linux") |
In the form with one parameter, the function returns the value of the external variable given as parameter. If this name is not present in the environment, the function returns an empty string.
In the form with two string parameters, the second argument is
the value returned when the variable given as the first argument is not
present in the environment. In the example above, if "OS"
is not
the name of an environment variable and is not passed on
the command line, then the returned value is "GNU/Linux"
.
An external reference may be part of a string expression or of a string list expression, and can therefore appear in a variable declaration or an attribute declaration.
type Mode_Type is ("Debug", "Release"); Mode : Mode_Type := external ("MODE"); case Mode is when "Debug" => ... |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A package defines the settings for project-aware tools within a project. For each such tool one can declare a package; the names for these packages are preset (see section 11.3.2 Packages). A package may contain variable declarations, attribute declarations, and case constructions.
project Proj is package Builder is -- used by gnatmake for Default_Switches ("Ada") use ("-v", "-g"); end Builder; end Proj; |
The syntax of package declarations mimics that of package in Ada.
Most of the packages have an attribute
Default_Switches
.
This attribute is an associative array, and its value is a string list.
The index of the associative array is the name of a programming language (case
insensitive). This attribute indicates the switch
or switches to be used
with the corresponding tool.
Some packages also have another attribute, Switches
,
an associative array whose value is a string list.
The index is the name of a source file.
This attribute indicates the switch
or switches to be used by the corresponding
tool when dealing with this specific file.
Further information on these switch-related attributes is found in 11.15.1.1 Switches and Project Files.
A package may be declared as a renaming of another package; e.g., from the project file for an imported project.
with "/global/apex.gpr"; project Example is package Naming renames Apex.Naming; ... end Example; |
Packages that are renamed in other project files often come from project files that have no sources: they are just used as templates. Any modification in the template will be reflected automatically in all the project files that rename a package from the template.
In addition to the tool-oriented packages, you can also declare a package
named Naming
to establish specialized source file naming conventions
(see section 11.11 Naming Schemes).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An attribute or variable defined in an imported or parent project can be used in expressions in the importing / extending project. Such an attribute or variable is denoted by an expanded name whose prefix is either the name of the project or the expanded name of a package within a project.
with "imported"; project Main extends "base" is Var1 := Imported.Var; Var2 := Base.Var & ".new"; package Builder is for Default_Switches ("Ada") use Imported.Builder.Ada_Switches & "-gnatg" & "-v"; end Builder; package Compiler is for Default_Switches ("Ada") use Base.Compiler.Ada_Switches; end Compiler; end Main; |
In this example:
Var1
is a copy of the variable Var
defined
in the project file `"imported.gpr"'
Var2
is a copy of the value of variable Var
defined in the project file `base.gpr', concatenated with ".new"
Default_Switches ("Ada")
in package
Builder
is a string list that includes in its value a copy of the value
of Ada_Switches
defined in the Builder
package
in project file `imported.gpr' plus two new elements:
`"-gnatg"'
and `"-v"';
Default_Switches ("Ada")
in package
Compiler
is a copy of the variable Ada_Switches
defined in the Compiler
package in project file `base.gpr',
the project being extended.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Sometimes an Ada software system is ported from a foreign compilation
environment to GNAT, and the file names do not use the default GNAT
conventions. Instead of changing all the file names (which for a variety
of reasons might not be possible), you can define the relevant file
naming scheme in the Naming
package in your project file.
Note that the use of pragmas described in 2.5 Alternative File Naming Schemes by mean of a configuration pragmas file is not supported when using project files. You must use the features described in this paragraph. You can however use specify other configuration pragmas (see section 11.15.1.2 Specifying Configuration Pragmas).
For example, the following package models the Apex file naming rules:
package Naming is for Casing use "lowercase"; for Dot_Replacement use "."; for Spec_Suffix ("Ada") use ".1.ada"; for Body_Suffix ("Ada") use ".2.ada"; end Naming; |
You can define the following attributes in package Naming
:
Casing
"lowercase"
,
"uppercase"
or "mixedcase"
; these strings are case insensitive.
If Casing is not specified, then the default is "lowercase"
.
Dot_Replacement
'.'
except if the entire string
is "."
If Dot_Replacement
is not specified, then the default is "-"
.
Spec_Suffix
Spec_Suffix ("Ada")
is not specified, then the default is
".ads"
.
Body_Suffix
Spec_Suffix ("Ada")
Body_Suffix ("Ada")
is not specified, then the default is
".adb"
.
Separate_Suffix
Body_Suffix
.
If Separate_Suffix ("Ada")
is not specified, then it defaults to same
value as Body_Suffix ("Ada")
.
Spec
Spec
to define
the source file name for an individual Ada compilation unit's spec. The array
index must be a string literal that identifies the Ada unit (case insensitive).
The value of this attribute must be a string that identifies the file that
contains this unit's spec (case sensitive or insensitive depending on the
operating system).
for Spec ("MyPack.MyChild") use "mypack.mychild.spec"; |
Body
You can use the associative array attribute Body
to
define the source file name for an individual Ada compilation unit's body
(possibly a subunit). The array index must be a string literal that identifies
the Ada unit (case insensitive). The value of this attribute must be a string
that identifies the file that contains this unit's body or subunit (case
sensitive or insensitive depending on the operating system).
for Body ("MyPack.MyChild") use "mypack.mychild.body"; |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Library projects are projects whose object code is placed in a library. (Note that this facility is not yet supported on all platforms)
To create a library project, you need to define in its project file
two project-level attributes: Library_Name
and Library_Dir
.
Additionally, you may define the library-related attributes
Library_Kind
, Library_Version
, Library_Interface
,
Library_Auto_Init
, Library_Options
and Library_GCC
.
The Library_Name
attribute has a string value. There is no restriction
on the name of a library. It is the responsability of the developer to
choose a name that will be accepted by the platform. It is recommanded to
choose names that could be Ada identifiers; such names are almost guaranteed
to be acceptable on all platforms.
The Library_Dir
attribute has a string value that designates the path
(absolute or relative) of the directory where the library will reside.
It must designate an existing directory, and this directory must be
different from the project's object directory. It also needs to be writable.
The directory should only be used for one library; the reason is that all
files contained in this directory may be deleted by the Project Manager.
If both Library_Name
and Library_Dir
are specified and
are legal, then the project file defines a library project. The optional
library-related attributes are checked only for such project files.
The Library_Kind
attribute has a string value that must be one of the
following (case insensitive): "static"
, "dynamic"
or
"relocatable"
(which is a synonym for "dynamic"
). If this
attribute is not specified, the library is a static library, that is
an archive of object files that can be potentially linked into an
static executable. Otherwise, the library may be dynamic or
relocatable, that is a library that is loaded only at the start of execution.
If you need to build both a static and a dynamic library, you should use two different object directories, since in some cases some extra code needs to be generated for the latter. For such cases, it is recommended to either use two different project files, or a single one which uses external variables to indicate what kind of library should be build.
The Library_Version
attribute has a string value whose interpretation
is platform dependent. It has no effect on VMS and Windows. On Unix, it is
used only for dynamic/relocatable libraries as the internal name of the
library (the "soname"
). If the library file name (built from the
Library_Name
) is different from the Library_Version
, then the
library file will be a symbolic link to the actual file whose name will be
Library_Version
.
Example (on Unix):
project Plib is Version := "1"; for Library_Dir use "lib_dir"; for Library_Name use "dummy"; for Library_Kind use "relocatable"; for Library_Version use "libdummy.so." & Version; end Plib; |
Directory `lib_dir' will contain the internal library file whose name will be `libdummy.so.1', and `libdummy.so' will be a symbolic link to `libdummy.so.1'.
When gnatmake
detects that a project file
is a library project file, it will check all immediate sources of the project
and rebuild the library if any of the sources have been recompiled.
Standard project files can import library project files. In such cases, the libraries will only be rebuild if some of its sources are recompiled because they are in the closure of some other source in an importing project. Sources of the library project files that are not in such a closure will not be checked, unless the full library is checked, because one of its sources needs to be recompiled.
For instance, assume the project file A
imports the library project file
L
. The immediate sources of A are `a1.adb', `a2.ads' and
`a2.adb'. The immediate sources of L are `l1.ads', `l1.adb',
`l2.ads', `l2.adb'.
If `l1.adb' has been modified, then the library associated with L
will be rebuild when compiling all the immediate sources of A
only
if `a1.ads', `a2.ads' or `a2.adb' includes a statement
"with L1;"
.
To be sure that all the sources in the library associated with L
are
up to date, and that all the sources of parject A
are also up to date,
the following two commands needs to be used:
gnatmake -Pl.gpr gnatmake -Pa.gpr |
When a library is built or rebuilt, an attempt is made first to delete all
files in the library directory.
All `ALI' files will also be copied from the object directory to the
library directory. To build executables, gnatmake
will use the
library rather than the individual object files.
It is also possible to create library project files for third-party libraries
that are precompiled and cannot be compiled locally thanks to the
externally_built
attribute. (See 19.2.2 Installing a library).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A Stand-alone Library is a library that contains the necessary code to elaborate the Ada units that are included in the library. A Stand-alone Library is suitable to be used in an executable when the main is not in Ada. However, Stand-alone Libraries may also be used with an Ada main subprogram.
A Stand-alone Library Project is a Library Project where the library is a Stand-alone Library.
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 11.12 Library Projects), the attribute
Library_Interface
must be defined.
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 (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.
A dynamic or relocatable Stand-alone Library is automatically initialized
if automatic initialization of Stand-alone Libraries is supported on the
platform and if attribute Library_Auto_Init
is not specified or
is specified with the value "true". A static Stand-alone Library is never
automatically initialized.
Single string attribute Library_Auto_Init
may be specified with only
two possible values: "false" or "true" (case-insensitive). Specifying
"false" for attribute Library_Auto_Init
will prevent automatic
initialization of dynamic or relocatable libraries.
When a non automatically initialized Stand-alone Library is used in an executable, its initialization procedure must be called before any service of the library is used. When the main subprogram is in Ada, it may mean that the initialization procedure has to be called during elaboration of another package.
For a Stand-Alone Library, only the `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.
When a Stand-Alone Library is bound, the switches that are specified in
the attribute Default_Switches ("Ada")
in package Binder
are
used in the call to gnatbind
.
The string list attribute Library_Options
may be used to specified
additional switches to the call to gcc
to link the library.
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, necessary to an Ada client of the library, will be
copied to the designated directory, called Interface Copy directory.
These sources includes 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 units 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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The following switches are used by GNAT tools that support project files:
There must be only one `-P' switch on the command line.
Since the Project Manager parses the project file only after all the switches on the command line are checked, the order of the switches `-P', `-vPx' or `-X' is not significant.
external(name)
when parsing the project file.
If name or value includes a space, then name=value should be put between quotes.
-XOS=NT -X"user=John Doe" |
Several `-X' switches can be used simultaneously. If several `-X' switches specify the same name, only the last one is used.
An external variable specified with a `-X' switch takes precedence over the value of the same name in the environment.
`-vP0' means Default; `-vP1' means Medium; `-vP2' means High.
The default is Default: no output for syntactically correct project files. If several `-vPx' switches are present, only the last one is used.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
11.15.1 gnatmake and Project Files 11.15.2 The GNAT Driver and Project Files 11.15.3 Glide and Project Files
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This section covers several topics related to gnatmake
and
project files: defining switches for gnatmake
and for the tools that it invokes; specifying configuration pragmas;
the use of the Main
attribute; building and rebuilding library project
files.
11.15.1.1 Switches and Project Files 11.15.1.2 Specifying Configuration Pragmas 11.15.1.3 Project Files and Main Subprograms 11.15.1.4 Library Project Files
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
For each of the packages Builder
, Compiler
, Binder
, and
Linker
, you can specify a Default_Switches
attribute, a Switches
attribute, or both;
as their names imply, these switch-related
attributes affect the switches that are used for each of these GNAT
components when
gnatmake
is invoked. As will be explained below, these
component-specific switches precede
the switches provided on the gnatmake
command line.
The Default_Switches
attribute is an associative
array indexed by language name (case insensitive) whose value is a string list.
For example:
package Compiler is for Default_Switches ("Ada") use ("-gnaty", "-v"); end Compiler; |
The Switches
attribute is also an associative array,
indexed by a file name (which may or may not be case sensitive, depending
on the operating system) whose value is a string list. For example:
package Builder is for Switches ("main1.adb") use ("-O2"); for Switches ("main2.adb") use ("-g"); end Builder; |
For the Builder
package, the file names must designate source files
for main subprograms. For the Binder
and Linker
packages, the
file names must designate `ALI' or source files for main subprograms.
In each case just the file name without an explicit extension is acceptable.
For each tool used in a program build (gnatmake
, the compiler, the
binder, and the linker), the corresponding package contributes a set of
switches for each file on which the tool is invoked, based on the
switch-related attributes defined in the package.
In particular, the switches
that each of these packages contributes for a given file f comprise:
Switches (f)
,
if it is specified in the package for the given file,
Default_Switches ("Ada")
,
if it is specified in the package.
If neither of these attributes is defined in the package, then the package does not contribute any switches for the given file.
When gnatmake
is invoked on a file, the switches comprise
two sets, in the following order: those contributed for the file
by the Builder
package;
and the switches passed on the command line.
When gnatmake
invokes a tool (compiler, binder, linker) on a file,
the switches passed to the tool comprise three sets,
in the following order:
Builder
package in the project file supplied on the command line;
The term applicable switches reflects the fact that
gnatmake
switches may or may not be passed to individual
tools, depending on the individual switch.
gnatmake
may invoke the compiler on source files from different
projects. The Project Manager will use the appropriate project file to
determine the Compiler
package for each source file being compiled.
Likewise for the Binder
and Linker
packages.
As an example, consider the following package in a project file:
project Proj1 is package Compiler is for Default_Switches ("Ada") use ("-g"); for Switches ("a.adb") use ("-O1"); for Switches ("b.adb") use ("-O2", "-gnaty"); end Compiler; end Proj1; |
If gnatmake
is invoked with this project file, and it needs to
compile, say, the files `a.adb', `b.adb', and `c.adb', then
`a.adb' will be compiled with the switch
`-O1',
`b.adb' with switches
`-O2'
and `-gnaty',
and `c.adb' with `-g'.
The following example illustrates the ordering of the switches contributed by different packages:
project Proj2 is package Builder is for Switches ("main.adb") use ("-g", "-O1", "-f"); end Builder; package Compiler is for Switches ("main.adb") use ("-O2"); end Compiler; end Proj2; |
If you issue the command:
gnatmake -Pproj2 -O0 main |
then the compiler will be invoked on `main.adb' with the following sequence of switches
-g -O1 -O2 -O0 |
with the last `-O' switch having precedence over the earlier ones; several other switches (such as `-c') are added implicitly.
The switches
`-g'
and `-O1' are contributed by package
Builder
, `-O2' is contributed
by the package Compiler
and `-O0' comes from the command line.
The `-g'
switch will also be passed in the invocation of
Gnatlink.
A final example illustrates switch contributions from packages in different project files:
project Proj3 is for Source_Files use ("pack.ads", "pack.adb"); package Compiler is for Default_Switches ("Ada") use ("-gnata"); end Compiler; end Proj3; with "Proj3"; project Proj4 is for Source_Files use ("foo_main.adb", "bar_main.adb"); package Builder is for Switches ("foo_main.adb") use ("-s", "-g"); end Builder; end Proj4; -- Ada source file: with Pack; procedure Foo_Main is ... end Foo_Main; |
If the command is
gnatmake -PProj4 foo_main.adb -cargs -gnato |
then the switches passed to the compiler for `foo_main.adb' are
`-g' (contributed by the package Proj4.Builder
) and
`-gnato' (passed on the command line).
When the imported package Pack
is compiled, the switches used
are `-g' from Proj4.Builder
,
`-gnata' (contributed from package Proj3.Compiler
,
and `-gnato' from the command line.
When using gnatmake
with project files, some switches or
arguments may be expressed as relative paths. As the working directory where
compilation occurs may change, these relative paths are converted to absolute
paths. For the switches found in a project file, the relative paths
are relative to the project file directory, for the switches on the command
line, they are relative to the directory where gnatmake
is invoked.
The switches for which this occurs are:
-I,
-A,
-L,
-aO,
-aL,
-aI, as well as all arguments that are not switches (arguments to
switch
-o, object files specified in package Linker
or after
-largs on the command line). The exception to this rule is the switch
--RTS= for which a relative path argument is never converted.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When using gnatmake
with project files, if there exists a file
`gnat.adc' that contains configuration pragmas, this file will be
ignored.
Configuration pragmas can be defined by means of the following attributes in
project files: Global_Configuration_Pragmas
in package Builder
and Local_Configuration_Pragmas
in package Compiler
.
Both these attributes are single string attributes. Their values is the path name of a file containing configuration pragmas. If a path name is relative, then it is relative to the project directory of the project file where the attribute is defined.
When compiling a source, the configuration pragmas used are, in order,
those listed in the file designated by attribute
Global_Configuration_Pragmas
in package Builder
of the main
project file, if it is specified, and those listed in the file designated by
attribute Local_Configuration_Pragmas
in package Compiler
of
the project file of the source, if it exists.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When using a project file, you can invoke gnatmake
with one or several main subprograms, by specifying their source files on the
command line.
gnatmake -Pprj main1 main2 main3 |
Each of these needs to be a source file of the same project, except when the switch -u is used.
When -u is not used, all the mains need to be sources of the
same project, one of the project in the tree rooted at the project specified
on the command line. The package Builder
of this common project, the
"main project" is the one that is considered by gnatmake
.
When -u is used, the specified source files may be in projects
imported directly or indirectly by the project specified on the command line.
Note that if such a source file is not part of the project specified on the
command line, the switches found in package Builder
of the
project specified on the command line, if any, that are transmitted
to the compiler will still be used, not those found in the project file of
the source file.
When using a project file, you can also invoke gnatmake
without
explicitly specifying any main, and the effect depends on whether you have
defined the Main
attribute. This attribute has a string list value,
where each element in the list is the name of a source file (the file
extension is optional) that contains a unit that can be a main subprogram.
If the Main
attribute is defined in a project file as a non-empty
string list and the switch `-u' is not used on the command
line, then invoking gnatmake
with this project file but without any
main on the command line is equivalent to invoking gnatmake
with all
the file names in the Main
attribute on the command line.
Example:
project Prj is for Main use ("main1", "main2", "main3"); end Prj; |
With this project file, "gnatmake -Pprj"
is equivalent to
"gnatmake -Pprj main1 main2 main3"
.
When the project attribute Main
is not specified, or is specified
as an empty string list, or when the switch `-u' is used on the command
line, then invoking gnatmake
with no main on the command line will
result in all immediate sources of the project file being checked, and
potentially recompiled. Depending on the presence of the switch `-u',
sources from other project files on which the immediate sources of the main
project file depend are also checked and potentially recompiled. In other
words, the `-u' switch is applied to all of the immediate sources of the
main project file.
When no main is specified on the command line and attribute Main
exists
and includes several mains, or when several mains are specified on the
command line, the default switches in package Builder
will
be used for all mains, even if there are specific switches
specified for one or several mains.
But the switches from package Binder
or Linker
will be
the specific switches for each main, if they are specified.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When gnatmake
is invoked with a main project file that is a library
project file, it is not allowed to specify one or more mains on the command
line.
When a library project file is specified, switches -b and -l have special meanings.
gnatmake
that gnatbind
should be invoked for the
library.
gnatmake
that the binder generated file should be compiled
(in the case of a stand-alone library) and that the library should be built.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A number of GNAT tools, other than gnatmake
are project-aware:
gnatbind
,
gnatfind
,
gnatlink
,
gnatls
,
gnatelim
,
gnatpp
,
gnatmetric
,
gnatstub
,
and gnatxref
. However, none of these tools can be invoked
directly with a project file switch (`-P').
They must be invoked through the gnat
driver.
The gnat
driver is a front-end that accepts a number of commands and
call the corresponding tool. It has been designed initially for VMS to convert
VMS style qualifiers to Unix style switches, but it is now available to all
the GNAT supported platforms.
On non VMS platforms, the gnat
driver accepts the following commands
(case insensitive):
gnatbind
gnatchop
gnatclean
gnatelim
gnatfind
gnatkr
gnatlink
gnatls
gnatmake
gnatname
gnatprep
gnatpp
gnatmetric
gnatstub
gnatxref
(note that the compiler is invoked using the command
gnatmake -f -u -c
).
On non VMS platforms, between gnat
and the command, two
special switches may be used:
-v
to display the invocation of the tool.
-dn
to prevent the gnat
driver from removing
the temporary files it has created. These temporary files are
configuration files and temporary file list files.
The command may be followed by switches and arguments for the invoked tool.
gnat bind -C main.ali gnat ls -a main gnat chop foo.txt |
Switches may also be put in text files, one switch per line, and the text files may be specified with their path name preceded by '@'.
gnat bind @args.txt main.ali |
In addition, for commands BIND, COMP or COMPILE, FIND, ELIM, LS or LIST, LINK, METRIC, PP or PRETTY, STUB and XREF, the project file related switches (`-P', `-X' and `-vPx') may be used in addition to the switches of the invoking tool.
When GNAT PP or GNAT PRETTY is used with a project file, but with no source
specified on the command line, it invokes gnatpp
with all
the immediate sources of the specified project file.
When GNAT METRIC is used with a project file, but with no source
specified on the command line, it invokes gnatmetric
with all the immediate sources of the specified project file and with
`-d' with the parameter pointing to the object directory
of the project.
In addition, when GNAT PP, GNAT PRETTY or GNAT METRIC is used with a project file, no source is specified on the command line and switch -U is specified on the command line, then the underlying tool (gnatpp or gnatmetric) is invoked for all sources of all projects, not only for the immediate sources of the main project. (-U stands for Universal or Union of the project files of the project tree)
For each of the following commands, there is optionally a corresponding package in the main project.
Binder
for command BIND (invoking gnatbind
)
Compiler
for command COMP or COMPILE (invoking the compiler)
Finder
for command FIND (invoking gnatfind
)
Eliminate
for command ELIM (invoking
gnatelim
)
Gnatls
for command LS or LIST (invoking gnatls
)
Linker
for command LINK (invoking gnatlink
)
Metrics
for command METRIC
(invoking gnatmetric
)
Pretty_Printer
for command PP or PRETTY
(invoking gnatpp
)
Gnatstub
for command STUB
(invoking gnatstub
)
Cross_Reference
for command XREF (invoking
gnatxref
)
Package Gnatls
has a unique attribute Switches
,
a simple variable with a string list value. It contains switches
for the invocation of gnatls
.
project Proj1 is package gnatls is for Switches use ("-a", "-v"); end gnatls; end Proj1; |
All other packages have two attribute Switches
and
Default_Switches
.
Switches
is an associated array attribute, indexed by the
source file name, that has a string list value: the switches to be
used when the tool corresponding to the package is invoked for the specific
source file.
Default_Switches
is an associative array attribute,
indexed by the programming language that has a string list value.
Default_Switches ("Ada")
contains the
switches for the invocation of the tool corresponding
to the package, except if a specific Switches
attribute
is specified for the source file.
project Proj is for Source_Dirs use ("./**"); package gnatls is for Switches use ("-a", "-v"); end gnatls; package Compiler is for Default_Switches ("Ada") use ("-gnatv", "-gnatwa"); end Binder; package Binder is for Default_Switches ("Ada") use ("-C", "-e"); end Binder; package Linker is for Default_Switches ("Ada") use ("-C"); for Switches ("main.adb") use ("-C", "-v", "-v"); end Linker; package Finder is for Default_Switches ("Ada") use ("-a", "-f"); end Finder; package Cross_Reference is for Default_Switches ("Ada") use ("-a", "-f", "-d", "-u"); end Cross_Reference; end Proj; |
With the above project file, commands such as
gnat comp -Pproj main gnat ls -Pproj main gnat xref -Pproj main gnat bind -Pproj main.ali gnat link -Pproj main.ali |
will set up the environment properly and invoke the tool with the switches
found in the package corresponding to the tool:
Default_Switches ("Ada")
for all tools,
except Switches ("main.adb")
for gnatlink
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Glide will automatically recognize the `.gpr' extension for
project files, and will
convert them to its own internal format automatically. However, it
doesn't provide a syntax-oriented editor for modifying these
files.
The project file will be loaded as text when you select the menu item
Ada
=> Project
=> Edit
.
You can edit this text and save the `gpr' file;
when you next select this project file in Glide it
will be automatically reloaded.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Suppose that we have two programs, prog1 and prog2,
whose sources are in corresponding directories. We would like
to build them with a single gnatmake
command, and we want to place
their object files into `build' subdirectories of the source directories.
Furthermore, we want to have to have two separate subdirectories
in `build' -- `release' and `debug' -- which will contain
the object files compiled with different set of compilation flags.
In other words, we have the following structure:
main |- prog1 | |- build | | debug | | release |- prog2 |- build | debug | release |
Here are the project files that we must place in a directory `main' to maintain this structure:
Common
project with a package Compiler
that
specifies the compilation switches:
File "common.gpr": project Common is for Source_Dirs use (); -- No source files type Build_Type is ("release", "debug"); Build : Build_Type := External ("BUILD", "debug"); package Compiler is case Build is when "release" => for Default_Switches ("Ada") use ("-O2"); when "debug" => for Default_Switches ("Ada") use ("-g"); end case; end Compiler; end Common; |
File "prog1.gpr": with "common"; project Prog1 is for Source_Dirs use ("prog1"); for Object_Dir use "prog1/build/" & Common.Build; package Compiler renames Common.Compiler; end Prog1; |
File "prog2.gpr": with "common"; project Prog2 is for Source_Dirs use ("prog2"); for Object_Dir use "prog2/build/" & Common.Build; package Compiler renames Common.Compiler; end Prog2; |
Main
:
File "main.gpr": with "common"; with "prog1"; with "prog2"; project Main is package Compiler renames Common.Compiler; end Main; |
with
s (either
explicitly or implicitly) all the sources of our two programs.
Now we can build the programs using the command
gnatmake -Pmain dummy |
for the Debug mode, or
gnatmake -Pmain -XBUILD=release |
for the Release mode.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
project ::= context_clause project_declaration context_clause ::= {with_clause} with_clause ::= with path_name { , path_name } ; path_name ::= string_literal project_declaration ::= simple_project_declaration | project_extension simple_project_declaration ::= project <project_>simple_name is {declarative_item} end <project_>simple_name; project_extension ::= project <project_>simple_name extends path_name is {declarative_item} end <project_>simple_name; declarative_item ::= package_declaration | typed_string_declaration | other_declarative_item package_declaration ::= package_specification | package_renaming package_specification ::= package package_identifier is {simple_declarative_item} end package_identifier ; package_identifier ::= |
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |