Project Extension
Project extension lets one project inherit sources and settings from another and selectively override them. A common use case is patching a third-party library: the extending project replaces only the files that need to change while reusing everything else unchanged.
Basic syntax
project Patched extends "original/original.gpr" is
-- Source files here shadow those in original.gpr.
-- All other sources and settings are inherited.
end Patched;
The path in extends is relative to the extending project file.
What is inherited
An extending project inherits:
Sources - all source files from the base are implicitly present. A source file in the extending project whose base name matches a base source shadows it.
Attribute values - project-level attributes not declared in the extending project are inherited from the base.
Packages - any package not declared in the extending project is inherited in full from the base.
Exception: Linker'Linker_Options is never inherited.
Object_Dir and Library_Dir must always be overridden in the extending
project; the two projects cannot share the same output directories.
project Patched extends "original/original.gpr" is
for Object_Dir use "obj";
for Library_Dir use "lib"; -- only for library projects
end Patched;
Overriding sources
Place a source file with the same base name in the extending project’s source directory. The extending project’s version is used and the base version is ignored entirely.
To remove an inherited source without providing a replacement, list it in
Excluded_Source_Files:
project Patched extends "original/original.gpr" is
for Object_Dir use "obj";
for Excluded_Source_Files use ("obsolete.adb");
end Patched;
Overriding attributes and packages
Attribute values are overridden by simply re-declaring them. Package declarations, however, replace the inherited package entirely - no per-attribute inheritance occurs within a package:
project Patched extends "original/original.gpr" is
for Object_Dir use "obj";
-- This replaces Original's entire Compiler package:
package Compiler is
for Switches ("Ada") use ("-O2");
end Compiler;
end Patched;
To amend a package rather than replace it, use package X extends Base.X:
project Patched extends "original/original.gpr" is
for Object_Dir use "obj";
-- Inherit Original's Compiler switches and add one more:
package Compiler extends Original.Compiler is
for Switches ("Ada") use Original.Compiler'Switches ("Ada") & ("-gnatwa");
end Compiler;
end Patched;
Abstract base projects
A common pattern is to declare common settings in an abstract base project
and extend it for each concrete build variant. The concrete project still needs
to declare its own project-specific attributes (such as Object_Dir) for its
own purposes:
-- base.gpr
abstract project Base is
type Build_Type is ("debug", "release");
Build : Build_Type := external ("BUILD", "debug");
package Compiler is
case Build is
when "debug" => for Switches ("Ada") use ("-g", "-gnatwa");
when "release" => for Switches ("Ada") use ("-O2");
end case;
end Compiler;
end Base;
-- my_app.gpr
project My_App extends "base.gpr" is
for Source_Dirs use ("src");
for Object_Dir use "obj/" & Base.Build;
for Exec_Dir use "bin/" & Base.Build;
for Main use ("main.adb");
end My_App;
Import redirection
When a project D extends A, and D also imports C which extends B, and A imports B - then within D’s project tree, A’s import of B is automatically redirected to C. The build system connects these automatically when both extensions are present in the tree.
For example, suppose B defines a variable that A references:
-- b.gpr
library project B is
Build_Suffix : constant String := "debug";
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Library_Name use "b";
for Library_Dir use "lib";
end B;
-- a.gpr
with "b.gpr";
project A is
for Source_Dirs use ("src");
for Object_Dir use "obj-" & B.Build_Suffix; -- "obj-debug"
end A;
C extends B and overrides the variable:
-- c.gpr
library project C extends "b.gpr" is
Build_Suffix : constant String := "release";
for Object_Dir use "obj";
for Library_Dir use "lib";
end C;
D extends A and imports C. When D is loaded, A’s import of B is
redirected to C, so A’s Object_Dir becomes "obj-release":
-- d.gpr
with "c.gpr";
project D extends "a.gpr" is
for Object_Dir use "obj";
end D;
Since a project tree may not depend on both an extending and an extended
project, this mechanism can only be used in simple cases. That is where
extends all solves the issue for more complex structures.
extends all
extends all implicitly creates an extending project for every project in
the import closure of the named base and applies import redirection throughout
the entire subtree in one step. This makes it practical to amend any
constituent of a large project hierarchy without manually extending every
project along the import path.
project Full_Override extends all "original/original.gpr" is
for Object_Dir use "obj";
end Full_Override;
The same inheritance rules apply as with a plain extends: each constituent
inherits its base’s sources, attributes, and packages with the same semantics
described above. A source file placed in Full_Override’s source directory
shadows the matching file wherever it originates in the tree.
To replace a specific constituent - for example to substitute instrumented
sources for one particular library - import an explicit extending project for
that constituent from within the extends all project. The explicit
extension takes the place of the corresponding implicit one, and import
redirection propagates it consistently across the whole subtree:
with "instrumented_lib.gpr"; -- extends "libs/my_lib/my_lib.gpr"
project Full_Override extends all "original/original.gpr" is
for Object_Dir use "obj";
end Full_Override;