Project Tree
A GPR project file rarely exists in isolation. A system is typically split across several project files, each responsible for one component. This chapter describes how multiple project files are connected into a project tree.
Project tree structure
A GPR project file rarely exists in isolation. A system is typically split across several project files, each responsible for one component. The connected graph of project files forms the project tree.
The project tree is a directed acyclic graph (DAG) rooted at the root
project - the project passed directly to the build tool (for example
gprbuild -P root.gpr). Two kinds of edges connect projects in the tree:
- Import (
withclause) The importing project depends on the imported project for compilation and for attribute visibility.
- Extension (
extendsclause) The extending project inherits sources and attributes from a base project. See Project Extension.
Aggregation (Project_Files) is a third relationship specific to aggregate
and aggregate library projects; see Aggregate Project.
Every project in the tree is loaded once and shared, regardless of how many other projects import it.
The with clause
A project declares its imports at the top of the file, before the project
declaration, using with clauses:
with "libs/utils/utils.gpr";
with "libs/crypto/crypto.gpr";
project My_App is
for Source_Dirs use ("src");
for Main use ("main.adb");
end My_App;
Multiple paths may appear in a single clause, separated by commas:
with "utils.gpr", "crypto.gpr";
A given project may appear at most once across all with clauses of the
same importing project. Duplicates are an error.
What a plain with makes visible
From within the body of the importing project, a plain with exposes all
of the following from the imported project:
- Types and variables
Typed string type definitions and variable declarations are accessible via the
Imported_Project.Namenotation.- Attributes and packages
Attribute values may be read using
Imported_Project'Attribute(orImported_Project.Package'Attribute). Packages may be renamed into the importing project with apackage P renames Imported_Project.Pdeclaration.- Source files
Sources of the imported project are compiled as needed; the resulting object files and Ada Library Information files (
*.ali) are made available to the importing project’s sources.
Example - sharing settings from an abstract project:
with "common.gpr";
project My_App is
-- Read a typed variable from Common
Mode : Common.Build_Mode_Type := Common.Build_Mode;
-- Alias the whole Compiler package from Common
package Compiler renames Common.Compiler;
-- Extend the linker switches defined in Common
package Linker is
for Switches ("Ada") use
Common.Linker'Switches ("Ada") & ("-lm");
end Linker;
end My_App;
Path resolution
The path in a with clause is a string naming a .gpr file. The
.gpr extension is optional and appended automatically if absent. The
directory separator is always /, even on Windows.
Paths are resolved in the following order:
If the path is absolute, it is used directly.
Otherwise it is resolved relative to the directory of the importing project file.
If no file is found there, each directory listed in
GPR_PROJECT_PATHis searched in order.Then the directories in
ADA_PROJECT_PATHare searched.Finally the default project paths provided by the selected toolchain(s) are searched.
The first match terminates the search. Installed libraries typically rely on steps 3-5, so they can be imported by bare name without a path:
with "gnatcoll.gpr"; -- resolved via GPR_PROJECT_PATH or toolchain paths
The limited with clause
Because attribute evaluation must be acyclic, a cycle formed entirely from
plain with edges is an error. The limited with variant relaxes this
constraint by restricting what is visible across the import:
limited with "component_b.gpr";
project Component_A is
for Source_Dirs use ("src_a");
end Component_A;
With a limited with:
- Visible
Source files of the imported project are compiled as part of the tree; their object files and ALI files are available to the importing project’s sources.
- Not visible
The imported project’s types, variables, attributes, and packages cannot be referenced inside the importing project’s body.
The limited modifier applies to the attribute-visibility graph only; it
has no effect on the source-dependency graph. Two components whose Ada units
are mutually recursive can therefore coexist in the same tree:
-- component_a.gpr
limited with "component_b.gpr";
project Component_A is
for Source_Dirs use ("src_a");
end Component_A;
-- component_b.gpr
with "component_a.gpr";
project Component_B is
for Source_Dirs use ("src_b");
end Component_B;
Here Component_B may reference attributes of Component_A, but
Component_A may not reference attributes of Component_B.
A cycle requires at least one limited with edge to break the attribute
cycle; without one the project loader reports an error.
Note
A need for limited with sometimes signals that the two components
share a common abstraction that should be factored into a third project on
which both depend. Consider restructuring before reaching for
limited with.