Subsystem Manifests¶
Each AURA subsystem can optionally include a special library unit called the manifest. This is an Ada package that is the first child of the subsystem root package itself, with a name “AURA”. For example, for a the CLI subsystem in our quick start example, the AURA manifest would be declared like this:
package CLI.AURA is
..
If included, manifests are copied to the project root as-is (spec and body), except that they are renamed as direct children of the AURA package with the subsystem name. As with the root AURA package, any AURA subsystem can then with this unit to access the configuration properties.
Note
Manifests, as well as all special nested packages described in this documentation, are completely optional.
In the example above, the CLI manifest would be converted into a unit in the project root that would be declared as follows:
package AURA.CLI is
..
Manifests should contain sufficient comments to allow the user to make their own modifications to the configuration of the subsystem once checked-out.
Note
Since the AURA package is Pure, manifest packages must also be Pure. This is by design, and limits what manifest packages can do during autoconfiguration. This is both a safety/security feature, and encouragement to create AURA packages that build more efficiently and reliably.
Role in Autoconfiguration¶
Once a subsystem manifest gets copied to the root project during the checkout of an AURA subsystem, it becomes what is known as the configuration package. Configuration packages are a powerful feature of the auto configuration process.
Note
If a subsystem does not have a manfiest, an empty configuration package is generated automatically. In other words, manifests are implicitly empty packages.
During the build process, each subsystem is configured, which involves evaluating each available subsystem configuration package, and using some of the explicitly defined components to influence the build environment with code paths, external libraries, compiler settings, and C language definitions.
Manifest Contents¶
An AURA manifest package may contain any legal Ada declarations, and may also have a body. The only restriction is that an AURA manifest cannot have any dependencies except the Ada standard library, and my not be generic.
There are three special nested packages that the AURA implementation recognizes and processes specially (Build
Codepaths
Information
), and one recommended neutral nested package (Configuration
).
All of the specially recognized nested packages can contain any number of constant String declarations (often initialized with non-static expressions). These declarations are used by the AURA implementation to affect different capabilities, features, and configuration parameters for the subsystem and build environment.
Example of a Manifest¶
The ASAP INET subsystem provides a great example of a package manifest that contains both platform-based auto configuration, as well as user-configured options. The INET manifest also uses most of the important AURA-specific configuration facilities.
Here is the complete INET manifest.
Note
Remember that the manifest will become a configuration package with the name aura.inet
after checkout. The actual manifest itself will never be directly compiled by AURA, and should not be withed directly by any unit of the subsystem.
-- INET AURA Configuration Manifest
package INET.AURA is
package Configuration is
Enable_TLS: constant Boolean := False;
end Configuration;
package Build is
package External_Libraries is
LibreSSL_libtls: constant String
:= (if Configuration.Enable_TLS then
"tls"
else
"");
-- Users should also ensure that the libressl include directory is in
-- C_INCLUDE_PATH, if not installed in the usual locations
end External_libraries;
package Ada is
package Compiler_Options is
Ignore_Unknown_Pragmas: constant String := "-gnatwG";
end Compiler_Options;
end Ada;
package C is
package Preprocessor_Definitions is
BSD: constant String
:= (if Platform_Flavor
in "freebsd" | "openbsd" | "netbsd"
then
"__INET_OS_BSD"
else
"");
Darwin: constant String
:= (if Platform_Flavor = "darwin" then
"__INET_OS_DARWIN"
else
"");
Linux: constant String
:= (if Platform_Flavor = "linux" then
"__INET_OS_LINUX"
else
"");
end Preprocessor_Definitions;
end C;
end Build;
package Codepaths is
TLS: constant String
:= (if Configuration.Enable_TLS then "tls" else "");
OS_Dependent: constant String
:= (if Platform_Family = "unix" then
"unix"
else
"");
IP_Lookup_Base: constant String := "ip_lookup/" & OS_Dependent;
IP_Lookup_Addrinfo: constant String
:= (if Platform_Flavor in "linux" | "openbsd" | "darwin" then
IP_Lookup_Base & "/addrinfo_posix"
elsif Platform_Flavor in
"freebsd" | "netbsd" | "solaris" | "illumos"
then
IP_Lookup_Base & "/addrinfo_bsd"
else
"");
end Codepaths;
end INET.AURA;
The Configuration Nested Package¶
-- INET AURA Configuration Manifest
package INET.AURA is
package Configuration is
Enable_TLS: constant Boolean := False;
end Configuration;
package Build is
-- ...
end Build;
package Codepaths is
-- ...
end Codepaths;
end INET.AURA;
The Configuration
nested package is a recommended convention, but is not specially recognized by the AURA implementation. Its recommended role is to contain all user-configurable options for the subsystem.
In this example, the Configuration
package contains the option for enabling TLS support for the INET
subsystem. The manifest should contain the default configuration.
If the user of the INET package wished to enable TLS support, they would edit the subsystem configuration package to enable that feature (in this case, aura.inet
in the project root).
By following this convention, the AURA subsystem users can more easily configure their checkouts of the subsystem.
Note
This package, if present, should be the first declaration of the manifest.
The Build Nested Package¶
The Build
nested package is used to control the building of subsystems, as well as the linking of projects that depend on the subsystem.
The Build
nested package is composed of a further number of specific, AURA-recognized nested packages.
Note
The Build
nested package, as well as all of its nested children, is optional.
The External_Libraries Package¶
-- INET AURA Configuration Manifest
package INET.AURA is
package Configuration is
-- ..
end Configuration;
package Build is
package External_Libraries is
LibreSSL_libtls: constant String
:= (if Configuration.Enable_TLS then
"tls"
else
"");
-- Users should also ensure that the libressl include directory is in
-- C_INCLUDE_PATH, if not installed in the usual locations
end External_libraries;
-- ..
end Build;
-- ..
end INET.AURA;
The Build.External_Libraries
package can contain any number of constant String declarations which declare the linker/compiler-recognized library name.
Note
The AURA implementation is advised to generally follow the UNIX convention of using the library name, not including ‘lib’. So, for example “iberty” for “libiberty”, which for the uix cc
and ld
convention would imply a command line option of -Liberty
The reference implementation follows this convention.
For an AURA subsystem that relies on libiberty, it should have a manifest with a declaration for Build.External_Libraries
that contains a constant string with the value “iberty”.
Note
The names of the constant String objects are ignored by the AURA implementation, but should typically be descriptive enough to maximize readability.
Note
Empty strings are ignored, which is useful when the requirement of an external library is conditional, depending on the configuration.
Note
In the above example that the value of LibreSSL_libtls
is declared with a conditional expression that is based on the value of Configuration.Enable_TLS
. This is the recommended application of user configuration, using the Configuration
package.
The Ada Package¶
package INET.AURA is
package Configuration is
-- ..
end Configuration;
package Build is
-- ..
package Ada is
package Compiler_Options is
Ignore_Unknown_Pragmas: constant String := "-gnatwG";
end Compiler_Options;
end Ada;
-- ..
end Build;
-- ..
end INET.AURA;
The Build.Ada
package supplies subsystem-specific configuration for the building of Ada sources.
Currently AURA only specifies a further nested package Compiler_Options
.
The Compiler_Options
nested package should contain a number of constant String declarations, where each one represents a specific option to pass to the Ada compiler.
Note
In the above example, the GNAT-specific option -gnatwG
is included. Notice how the object is given the descriptive name Ignore_Unknown_Pragmas
. This is included because the AURA specification includes a new pragma External_With
used by AURA subsystems to include non-Ada units in their codebase.
See also
See this section for more discussion on the new pragma External_With
, and how to include non-Ada sources in an AURA subsystem.
The C Package¶
package INET.AURA is
package Configuration is
-- ..
end Configuration;
package Build is
-- ..
package C is
package Preprocessor_Definitions is
BSD: constant String
:= (if Platform_Flavor
in "freebsd" | "openbsd" | "netbsd"
then
"__INET_OS_BSD"
else
"");
Darwin: constant String
:= (if Platform_Flavor = "darwin" then
"__INET_OS_DARWIN"
else
"");
Linux: constant String
:= (if Platform_Flavor = "linux" then
"__INET_OS_LINUX"
else
"");
end Preprocessor_Definitions;
end C;
end Build;
-- ..
end INET.AURA;
The Build.C
package supplies subsystem-specific configuration for the building of C sources, and is a particularly powerful tool in the integration of C sources in AURA subsystems.
Currently, AURA specifies two further nested packages: Compiler_Options
and Preprocessor_Definitions
.
Build.C.Compiler_Options
This functions identically as it does for
Build.Ada.Compiler_Options
, as discussed above, except that it applies only to the C compiler.Build.C.Preprocessor_Definitions
This package is the most interesting and powerful tool for the integration of C sources.
Like most of the other nested packages, the
Preprocessor_Definitions
package should contain a series of constant String declarations. Each String causes the content of that string to be “defined” for any C sources in the subsystem’s codepaths.For example, if the
INET
AURA subsystem is built on MacOS,AURA.Platform_Flavor
will have a value of “darwin”, which will causeBuild.C.Darwin
to evaluate to “__INET_OS_DARWIN”. This will cause all C sources that are part of theINET
subsystem to be (in effect) compiled with#define __INET_OS_DARWIN
.
Note
If any of the constant String declarations of Build.C.Preprocessor_Definitions
evaluate to a null string, AURA will ignore that declaration. Therefore (as in the above example), if a preprocessor definition should not be made in some cases, it should be set to a null string.
The Codepaths Nested Package¶
package INET.AURA is
-- ..
package Codepaths is
TLS: constant String
:= (if Configuration.Enable_TLS then "tls" else "");
OS_Dependent: constant String
:= (if Platform_Family = "unix" then
"unix"
else
"");
IP_Lookup_Base: constant String := "ip_lookup/" & OS_Dependent;
IP_Lookup_Addrinfo: constant String
:= (if Platform_Flavor in "linux" | "openbsd" | "darwin" then
IP_Lookup_Base & "/addrinfo_posix"
elsif Platform_Flavor in
"freebsd" | "netbsd" | "solaris" | "illumos"
then
IP_Lookup_Base & "/addrinfo_bsd"
else
"");
end Codepaths;
-- ..
end INET.AURA;
The Codepaths
nested package is perhaps the most powerful single feature of AURA subsystem auto configuration. Codepaths
allow the active content of the subsystem codebase to be selected through the auto configuration process. Among other things, this allows platform-specific code to be selected automatically for the target platform. In the above INET example, it is also used to include the additional TLS code when that option is enabled.
While the Codebase
mechanics are implementation-defined, the required behavior strongly hints at the typical implementation, and the recommended implementation is that of AURA CLI.
The Codepaths
package consists of any number of static String declarations. Each declaration that evaluates to a non-null string refers to some collection of library units, and/or other further collections. For AURA CLI, these declarations should evaluate to UNIX-style paths, without leading ‘/’. These paths should index subdirectories of the subsystem’s own subdirectory.
For the INET
example, we see that if TLS is enabled (Configuration.Enable_TLS = True
), the immediate source code of the tls
subdirectory should be included.
Note
Any subdirectories in a selected Codepath are not automatically included. These must be explicitly selected if they are to be included as well.
Codepaths can be of any depth. In the INET
example, we see that all platforms have a base ip_lookup
codepath (subdirectory), which further contains addrinfo_posix
and addrinfo_bsd
. These second-level subdirectories are selected based on the platform. It is important to note that the content of these second-level subdirectories would not be entered if not explicitly given as a codepath. That is to say, if only IP_Lookup_Base
was declared, the contents of addrinfo_posix
and addrinfo_bsd
would not be included.