Attributes
Attributes are the primary mechanism for storing project configuration in a
.gpr file. Each attribute has a name, an optional index, and a value that
is either a single string or a list of strings.
The attribute API is spread across four packages:
GPR2.Project.Registry.Pack- registers packages (built-in and custom).GPR2.Project.Registry.Attribute- registers attribute definitions and provides constants for every standard attribute.GPR2.Project.Attribute_Index- index values used to look up indexed attributes.GPR2.Project.Attribute- the attribute object returned by view queries.
Attribute registry
Every attribute that GPR2 recognizes must be registered before the project tree is loaded. Registration records the attribute’s metadata: whether it takes an index, what kind of value it holds, and which project kinds it is allowed in.
GPR2 pre-registers all standard GPR attributes (Compiler'Switches,
Object_Dir, Main, etc.) at library elaboration time. Tools that
define their own GPR packages must register those packages and their
attributes before calling Tree.Load.
Registering a custom package
Use GPR2.Project.Registry.Pack.Add to introduce a new package:
with GPR2.Project.Registry.Pack;
-- Register a custom package allowed in all project kinds
if not GPR2.Project.Registry.Pack.Exists (+"MyTool") then
GPR2.Project.Registry.Pack.Add
(Name => +"MyTool",
Projects => GPR2.Project.Registry.Pack.Everywhere);
end if;
Projects restricts which project kinds may contain the package.
Everywhere allows it in all project kinds; No_Aggregates excludes
aggregate projects.
Once registered, packages with this name will be recognized in .gpr files:
package MyTool is
for Switches use ("-O2");
end MyTool;
Registering custom attributes
Attributes are registered with GPR2.Project.Registry.Attribute.Add.
The package the attribute belongs to must already be registered.
with GPR2.Project.Registry.Attribute;
with GPR2.Project.Registry.Pack;
My_Package : constant Package_Id := +"MyTool";
My_Switches : constant Q_Attribute_Id := (My_Package, +"Switches");
if not GPR2.Project.Registry.Attribute.Exists (My_Switches) then
GPR2.Project.Registry.Attribute.Add
(Name => My_Switches,
Index_Type => GPR2.Project.Registry.Attribute.Language_Index,
Value => GPR2.Project.Registry.Attribute.List,
Value_Case_Sensitive => True,
Is_Allowed_In => GPR2.Project.Registry.Attribute.Everywhere);
end if;
Key parameters of Add:
Index_TypeKind of index the attribute accepts.
No_Indexfor unindexed attributes;Language_Indexfor language names;FileGlob_Or_Language_Indexfor source globs or languages;File_Index/FileGlob_Indexfor source filenames or patterns.ValueSinglefor a scalar value,Listfor a list of strings.Value_Case_SensitiveWhether the value strings are case-sensitive.
Is_Allowed_InArray of
Project_Kindbooleans; useEverywhereto allow the attribute in all project kinds.Index_OptionalIf
True, the index may be omitted.Empty_ValueHow empty values are treated:
Allow,Ignore(warning), orError.Inherit_From_ExtendedWhether and how the attribute value is inherited from an extended project:
Inherited,Concatenated, orNot_Inherited.Config_ConcatenableIf
True, the value is concatenated with any value found in the configuration project rather than overriding it.
Standard attribute constants
GPR2.Project.Registry.Attribute exposes a constant of type
Q_Attribute_Id for every standard GPR attribute. Top-level attributes use
a simple name; package attributes are nested under a child package:
GPR2.Project.Registry.Attribute.Object_DirObject_DirGPR2.Project.Registry.Attribute.Exec_DirExec_DirGPR2.Project.Registry.Attribute.Source_FilesSource_FilesGPR2.Project.Registry.Attribute.Source_List_FileSource_List_FileGPR2.Project.Registry.Attribute.MainMainGPR2.Project.Registry.Attribute.Library_NameLibrary_NameGPR2.Project.Registry.Attribute.Compiler.SwitchesCompiler'SwitchesGPR2.Project.Registry.Attribute.Compiler.Default_SwitchesCompiler'Default_SwitchesGPR2.Project.Registry.Attribute.Compiler.DriverCompiler'DriverGPR2.Project.Registry.Attribute.Binder.SwitchesBinder'SwitchesGPR2.Project.Registry.Attribute.Linker.SwitchesLinker'SwitchesGPR2.Project.Registry.Attribute.Naming.Body_SuffixNaming'Body_SuffixGPR2.Project.Registry.Attribute.Builder.Default_SwitchesBuilder'Default_Switches
Reading attributes from a view
Use View.Has_Attribute before accessing an attribute that may be absent:
with GPR2.Project.Registry.Attribute;
if View.Has_Attribute (GPR2.Project.Registry.Attribute.Object_Dir) then
Attr : constant GPR2.Project.Attribute.Object :=
View.Attribute (GPR2.Project.Registry.Attribute.Object_Dir);
Put_Line (Attr.Value.Text);
end if;
View.Attribute returns Attribute.Undefined when the attribute is
absent and has no default, so the Has_Attribute guard is necessary for
optional attributes.
Single vs. list attributes
An attribute’s Kind is either Single or List:
Attr : constant GPR2.Project.Attribute.Object :=
View.Attribute (GPR2.Project.Registry.Attribute.Main);
case Attr.Kind is
when Single =>
Put_Line (Attr.Value.Text);
when List =>
for V of Attr.Values loop
Put_Line (V.Text);
end loop;
end case;
In practice the kind of each attribute is fixed by its registration, so you
rarely need to check Kind at runtime - just call Value for single
attributes and Values for list attributes.
Indexed attributes
Many attributes are indexed (e.g. Compiler'Switches is indexed by
language or source filename). Pass an Attribute_Index to select one entry:
with GPR2.Project.Attribute_Index;
with GPR2.Project.Registry.Attribute;
-- Look up Compiler'Switches for the Ada language
Attr := View.Attribute
(GPR2.Project.Registry.Attribute.Compiler.Switches,
GPR2.Project.Attribute_Index.Create (Ada_Language));
-- Look up Compiler'Switches for a specific source file.
-- The index passed is a concrete filename. The project may define the
-- attribute with a glob-pattern index such as Compiler'Switches ("autogen-*");
-- the library resolves the lookup by pattern matching against defined
-- indexes, or by falling back to the language of the source file.
Attr := View.Attribute
(GPR2.Project.Registry.Attribute.Compiler.Switches,
GPR2.Project.Attribute_Index.Create_Source ("autogen-blah.adb"));
Creating an Attribute_Index:
Attribute_Index.Create (Value_Type)String index (case-insensitive by default)
Attribute_Index.Create_Source (Simple_Name)Source filename (respects filesystem case sensitivity)
Attribute_Index.Create (Language_Id)Language identifier
Attribute_Index.I_OthersThe special
othersindex
Enumeration vs. lookup
View.Attributes returns all entries as they are written in the project
file - glob patterns appear as-is (e.g. the index value is "autogen-*"
rather than any resolved filename). Use it to inspect or iterate raw
definitions.
View.Attribute with a concrete index performs resolution: the library
tries to match the given value against each defined index pattern
(FileGlob matching), and for source-file indexes also falls back to the
language of that source file. This is the right call when you want the
effective switches that apply to a particular source.
-- Enumerate raw definitions (patterns as written in the project)
for Attr of View.Attributes
(GPR2.Project.Registry.Attribute.Compiler.Switches)
loop
Put_Line (Attr.Index.Value & " => " & Attr.Value.Text);
-- Index.Value may be "autogen-*", "Ada", "others", etc.
end loop;
-- Resolve the effective switches for one specific source file
Attr := View.Attribute
(GPR2.Project.Registry.Attribute.Compiler.Switches,
GPR2.Project.Attribute_Index.Create_Source ("autogen-blah.adb"));
Attribute metadata
Beyond the value, an Attribute.Object carries useful metadata:
Attr.KindSingleorList.Attr.ValueThe single value (
Source_Reference.Value.Object). Call.Textto obtain theValue_Typestring.Attr.ValuesThe list of values. Each element has a
.Textaccessor.Attr.IndexThe
Attribute_Indexfor this entry; call.Valueor.Is_Otherson the result.Attr.Has_IndexTrueif this attribute entry has an index.Attr.Is_DefaultTrueif the value was synthesised from a GPR default rule rather than written explicitly in the project file.Attr.Is_From_ConfigTrueif the value originates from the configuration project (.cgpr) rather than from the user project.