[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

11. GNAT Project Manager

11.1 Introduction  
11.2 Examples of Project Files  
11.3 Project File Syntax  
11.4 Objects and Sources in Project Files  
11.5 Importing Projects  
11.6 Project Extension  
11.7 Project Hierarchy Extension  
11.8 External References in Project Files  
11.9 Packages in Project Files  
11.10 Variables from Imported Projects  
11.11 Naming Schemes  
11.12 Library Projects  
11.13 Stand-alone Library Projects  
11.14 Switches Related to Project Files  
11.15 Tools Supporting Project Files  
11.16 An Extended Example  
11.17 Project File Complete Syntax  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

11.1 Introduction

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:

11.1.1 Project Files  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

11.1.1 Project Files

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 withing 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 section `Project File Reference' in GNAT Reference Manual.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

11.2 Examples of Project Files

This section illustrates some of the typical uses of project files and explains their basic structure and behavior.

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] [ ? ]

11.2.1 Common Sources with Different Switches and Directories

Source Files  
Specifying the Object Directory  
Specifying the Exec Directory  
Project File Packages  
Specifying Switch Settings  
Main Subprograms  
Executable File Names  
Source File Naming Conventions  
Source Language(s)  

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 withs package Pack. We want to compile these source files under two sets of switches:

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
Here are the corresponding project files:

 
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] [ ? ]

Source Files

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] [ ? ]

Specifying the Object Directory

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] [ ? ]

Specifying the Exec Directory

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] [ ? ]

Project File Packages

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] [ ? ]

Specifying Switch Settings

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] [ ? ]

Main Subprograms

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] [ ? ]

Executable File Names

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 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] [ ? ]

Source File Naming Conventions

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] [ ? ]

Source Language(s)

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] [ ? ]

11.2.2 Using External Variables

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] [ ? ]

11.2.3 Importing Other Projects

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 withed 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
which will generate the 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

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] [ ? ]

11.2.4 Extending a Project

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 spec. 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 Excluded_Source_Files is used. Its value is a string list: a list of file names. It is also possible to use attribute Excluded_Source_List_File. Its value is a single string: the file name of a text file containing a list of file names, one per line.

 
project B extends "a" is
   for Source_Files use ("pkg.ads");
   --  New spec of Pkg does not need a completion
   for Excluded_Source_Files use ("pkg.adb");
end B;

Attribute Excluded_Source_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 Excluded_Source_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 Project File Syntax

11.3.1 Basic Syntax  
11.3.2 Qualified Projects  
11.3.3 Packages  
11.3.4 Expressions  
11.3.5 String Types  
11.3.6 Variables  
11.3.7 Attributes  
11.3.8 Associative Array Attributes  
11.3.9 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] [ ? ]

11.3.1 Basic Syntax

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 95 reserved words plus extends, external, and project. Note that the only Ada reserved words currently used in project file syntax are:

Comments in project files have the same syntax as in Ada, two consecutive hyphens through the end of the line.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

11.3.2 Qualified Projects

Before the reserved project, there may be one or two "qualifiers", that is identifiers or other reserved words, to qualify the project.

The current list of qualifiers is:


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

11.3.3 Packages

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:

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] [ ? ]

11.3.4 Expressions

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:

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:

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] [ ? ]

11.3.5 String Types

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.9 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] [ ? ]

11.3.6 Variables

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] [ ? ]

11.3.7 Attributes

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.8 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
Excluded_Source_Dirs string list
Excluded_Source_Files string list
Excluded_Source_List_File string
Languages string list
Main string list
Library_Dir string
Library_Name string
Library_Kind string
Library_Version string
Library_Interface string
Library_Auto_Init string
Library_Options string list
Library_Src_Dir string
Library_ALI_Dir string
Library_GCC string
Library_Symbol_File string
Library_Symbol_Policy string
Library_Reference_Symbol_File string
Externally_Built 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:

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] [ ? ]

11.3.8 Associative Array Attributes

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 a 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] [ ? ]

11.3.9 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 be 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, attribute declarations and variable declarations. String type declarations and package declarations are not allowed. Variable declarations are restricted to variables that have already been declared before the case construction.

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 Objects and Sources in Project Files

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] [ ? ]

11.4.1 Object Directory

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] [ ? ]

11.4.2 Exec Directory

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] [ ? ]

11.4.3 Source Directories

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] [ ? ]

11.4.4 Source File Names

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] [ ? ]

11.5 Importing Projects

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 corresponds to a file name, with no path or a relative path, then its location is determined by the project path. The latter can be queried using gnatls -v. It contains:

If a relative pathname is used, as in

 
  with "tests/proj";

then the full path for the project is constructed by concatenating this relative path to those in the project path, in order, until a matching file is found. 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 straight 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] [ ? ]

11.6 Project Extension

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 spec 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 spec will still be found in the project Utilities.

A child project can have only one parent, except when it is qualified as abstract. 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] [ ? ]

11.7 Project Hierarchy Extension

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.

  1. project A, containing package P1
  2. project B importing A and containing package P2 which depends on P1
  3. project C importing B and containing package P3 which depends on P2

We want to modify packages P1 and P3.

This project hierarchy will need to be extended as follows:

  1. Create project A1 that extends A, placing modified P1 there:

     
    project A1 extends "(...)/A" is
    end A1;
    

  2. Create project C1 that "extends all" C and imports A1, placing modified P3 there:

     
    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] [ ? ]

11.8 External References in Project Files

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:

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] [ ? ]

11.9 Packages in Project Files

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.3 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] [ ? ]

11.10 Variables from Imported Projects

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:


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

11.11 Naming Schemes

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
This must be a string with one of the three values "lowercase", "uppercase" or "mixedcase"; these strings are case insensitive.

If Casing is not specified, then the default is "lowercase".

Dot_Replacement
This must be a string whose value satisfies the following conditions:

If Dot_Replacement is not specified, then the default is "-".

Spec_Suffix
This is an associative array (indexed by the programming language name, case insensitive) whose value is a string that must satisfy the following conditions:

If Spec_Suffix ("Ada") is not specified, then the default is ".ads".

Body_Suffix
This is an associative array (indexed by the programming language name, case insensitive) whose value is a string that must satisfy the following conditions:

If Body_Suffix ("Ada") and Spec_Suffix ("Ada") end with the same string, then a file name that ends with the longest of these two suffixes will be a body if the longest suffix is Body_Suffix ("Ada") or a spec if the longest suffix is Spec_Suffix ("Ada").

If Body_Suffix ("Ada") is not specified, then the default is ".adb".

Separate_Suffix
This must be a string whose value satisfies the same conditions as Body_Suffix. The same "longest suffix" rules apply.

If Separate_Suffix ("Ada") is not specified, then it defaults to same value as Body_Suffix ("Ada").

Spec
You can use the associative array attribute 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 thi