Alire
is a source-based package manager for the Ada and SPARK programming
languages.
It is a way for developers to easily build upon projects (libraries or programs) shared by the community, but also to easily share their projects for others to build upon.
In the Alire vocabulary, sources of projects/libraries/programs are provided by
what is called a crate
. A crate can depend on crates, and other crates can
depend on it. For instance, the libgpr
crate depends on the xmlada
crate.
Crates can have multiple dependencies, themselves having multiple dependencies. This forms a dependency graph. Alire’s main task is to automatically fetch, build and upgrade the crates of the dependency graph so you don’t have to do it by hand.
The main interface into the Alire
ecosystem is a command line tool called
alr
.
You can download the last release of Alire at the GitHub repository.
alr
on LinuxOn Linux, Alire
is simply provided in an archive.
Once the archive is extracted you have to add alr
in the environment PATH
:
$ export PATH=<PATH_TO_EXTRACTED>/bin/:$PATH
Alire provides GNAT toolchains hosted on x86-64 for Linux. If those toolchains do not work for you, or if you are on another host architecture like ARM, you have the option to look at the GNAT toolchains from the Linux distribution.
alr
on WindowsOn Windows an installer is provided. The installer will create a shortcut to
start PowerShell
with Alire
in the environment PATH
.
The first time you run alr
the program will ask if you want to install
msys2. This is recommended as alr
will use msys2
to automatically install required tools such as git
or make
that you would
otherwise have to install manually. msys2
will also provide external
libraries required by some projects in the Alire index, allowing you to build
more projects out of the box.
Alire provides GNAT toolchains hosted on x86-64 for Windows. Those toolchains should work for all cases, if not, let us know.
alr
on macOSOn macOS, Alire
is simply provided in an archive.
Once the archive is extracted you have to add alr
in the environment PATH
:
$ export PATH=<PATH_TO_EXTRACTED>/bin/:$PATH
If you try to run it on recent versions of macOS, you will get a popup saying
“alr” cannot be opened because the developer cannot be verified.
and inviting
you to move it to the bin. The way round this is to remove the quarantine attribute,
$ xattr -d com.apple.quarantine bin/alr
Alire provides GNAT toolchains hosted on x86-64 for macOS. If those toolchains do not work for you, or if you are on another host architecture like the Apple M1, you have the option to look at the GNAT toolchains from the community.
alr
for other platformsIf alr
is not available on your platform, you can try to build it from
sources. Go to the GitHub repository
for more information.
The following miniguide shows how to obtain and build already packaged
projects, and create your own. First, create or enter into some folder where
you don’t mind that new project folders are created by the alr
tool
Run alr
without arguments to get a summary of available commands.
Run alr --help
for global options about verbosity.
Run alr help <command>
for more details about a command.
Obtaining an executable project already cataloged in Alire is straightforward.
We’ll demonstrate it with the hello
project which is a plain “Hello, world!”
application (or you can use the hangman
or eagle_lander
projects as funnier
alternatives).
Follow these steps:
alr get hello
cd hello*
Build and run the project with alr run
. This will build and then launch
the resulting executable.
The first time you run this command, the toolchain selection assistant
will ask you to select your preferred default toolchains (GNAT compiler and
GPRbuild). For this getting started example, we recommend to just press
enter twice to select the defaults.
As a shorthand, you can use alr get --build hello
to get and build the
program in one step.
Alire allows you to initialize an empty binary or library crate with ease:
Issue alr init --bin myproj
(you can use --lib
for a library project)
The first time you run this command, alr
will ask a couple of questions to
automatically fill-in information about the crate:
GitHub login
: is used to identify the maintainer of the crate when
contributed to the community index.Full name
: Name of the author of the crateEmail address
: Point of contact to author of the crateAll the questions are optional for now, you can just press enter to use the default values.
The alr init
command will create a basic crate
structure in the myproj
directory.
cd myproj
alr build
alr run
We can now edit the sources of this executable in the src/
directory.
For instance, add a “Hello world” to src/myproj.adb
:
with Ada.Text_IO;
procedure Myproj is
begin
Ada.Text_IO.Put_Line ("Hello, world!");
end Myproj;
Use alr run
to build and run the program again:
$ alr run
# Building myproj/myproj.gpr...
Compile
[Ada] myproj.adb
Bind
[gprbind] myproj.bexch
[Ada] myproj.ali
Link
[link] myproj.adb
Build finished successfully in 0.35 seconds.
Hello, world!
Besides the alr
command, the main interface with Alire is the manifest
.
The manifest is a text file named alire.toml
in the root directory of the
crate. It contains all sorts of information about the crate, some mandatory
such as the name
and version
, others optional like the licenses
. Alire
manifests are written in TOML format.
You can have a look at the manifest to get a idea of its content, but nothing has to be edited by hand so far.
Alire keeps track of dependencies in the manifest (alire.toml
) of your crate.
Adding dependencies can be done with the alr with
command:
alr with crate_name
adds a dependency. You can immediately ‘with’ its
packages in your code.alr with --del crate_name
removes a dependency.Alternatively you can edit the file to add dependencies and then issue:
alr update
, which will fetch any modified dependencies in your project.Using alr with
without arguments will show the current dependencies of your
project. Using one of --solve
, --tree
, --versions
, --graph
will show
different details about the complete solution needed to fulfill dependencies.
Let’s add a dependency to the libhello
crate.
$ alr with libhello
Requested changes:
# libhello ^1.0.0 (add)
Changes to dependency solution:
+ libhello 1.0.0 (new)
Do you want to proceed?
[Y] Yes [N] No (default is Yes)
alr
is showing the new dependency solution, i.e. all the crates in the
dependency graph and their version.
Press enter to accept the new solution.
alr
will then download the sources of the libhello
crate.
You can now edit the src/myproj.adb
source file again, and write this piece
of code to call a function from the libhello
crate:
with Libhello;
procedure Myproj is
begin
libhello.Hello_World;
end Myproj;
Run alr run
to build and run the new executable:
$ alr run
# Building myproj/myproj.gpr...
Setup
[mkdir] object directory for project Libhello
[mkdir] library directory for project Libhello
Compile
[Ada] myproj.adb
[Ada] libhello.adb
Build Libraries
[gprlib] hello.lexch
[archive] libhello.a
[index] libhello.a
Bind
[gprbind] myproj.bexch
[Ada] myproj.ali
Link
[link] myproj.adb
Build finished successfully in 0.34 seconds.
Hello, world!
As you can see, the libhello
library sources are automatically built and
linked in your program.
For quick listing of crates and their descriptions you can use the search
command with the --crates
switch:
alr search --crates [substring]
Otherwise, search
will look into releases, providing more details about specific
releases:
alr search <substring>
will look for substring
in crate names.alr search --list
will list the latest release of every crate.alr search --list --full
will list all releases in the catalog.Even more details are obtained with:
alr show <crate>
This last command will show generic information. To see the one that specifically applies to your platform:
alr show --system <crate>
The list of projects and their descriptions are also available on the Alire website:
To create a build environment, alr
sets environment variables such as
GPR_PROJECT_PATH
before running gprbuild
. If you want to run gprbuild
yourself or inside an editor (GNAT Studio), you can use the printenv
command
to print the build environment:
alr printenv
By default alr
is quite terse and will hide the output of subprocesses,
mostly reporting in case of failure. If you hit any problem, increasing
verbosity (-v
or even -vv
) is usually enough to get an idea of the root of
the problem. Additionally, -d
will show tracebacks of exceptions.
alr
comes with a test suite for self-checks. See the instructions in the
README
of the testsuite
folder.
Additionally, you can test in batch the building of crates in your platform
with the alr test
command. (See alr test --help
output for instructions.)
First you have to decide on a crate name for your project, this name will have to follow the naming rules of Alire. You can find those rules using the command:
$ alr help identifiers
Avoid using ada
as a prefix for your crate name, this will make the project
harder to find in a list. ada
suffix is ok when the project is a binding for
an existing library (e.g. sdlada
, gtkada
).
We will use the name my_crate
as an example, and consider that the repository
uses the same name.
Clone your project repository and enter the directory:
$ git clone https://github.com/github_login/my_crate.git
$ cd my_crate
At this point you have a choice:
Let Alire generate a new GPR project file for you. This is recommended for most projects, and in particular if your project has simple code organization and GPR project file. One of the advantages is that Alire will create a GPR project file “standardized” for best integration in the ecosystem.
Keep your existing GPR project file. This is recommended for projects with complex GPR project file(s).
If you want Alire to generate a project you first have to delete the existing GPR project file:
$ rm *.gpr
And then use alr init
command to create a skeleton for your crate:
For a library:
$ alr init --in-place --lib my_crate
For an application:
$ alr init --in-place --bin my_crate
If this is your first time using alr init
, you will have to provide some
information like your name and GitHub login.
You can ignore the warnings such as Cannot create
'[...]/my_crate/src/my_crate.ads'
, Alire is trying to create a root package
for your crate but you probably already have one.
From this point you can edit the GPR project file to change the source dir or compilation flags, if needed. And then try to compile your crate with:
$ alr build
If you want to keep the existing GPR project file, use alr init
with the
--no-skel
option to skip the project skeleton creation:
For a library:
$ alr init --in-place --no-skel --lib my_crate
For an application:
$ alr init --in-place --no-skel --bin my_crate
If this is your first time using alr init
, you will have to provide some
information like your name and GitHub login.
If your GPR project file does not match the crate name (i.e. my_crate.gpr
),
you have to add a
project-files
field in your alire.toml
manifest. For instance:
project-files = ["project_file.gpr"]
Although this is not recommended (see Best practices), you can have multiple GPR project files:
project-files = ["project_file_1.gpr", "project_file_2.gpr"]
You can now compile your crate with:
$ alr build
Toolchains are comprised by a GNAT compiler and a gprbuild
project file
processor. Alire strives to simplify the availability of GNAT releases, which
are packaged to be retrieved and used with ease.
The user can now select a preferred compiler via alr toolchain --select
.
Releases may still override this selection (for example to use a
cross-compiler).
There are two kind of dependencies on GNAT compilers: generic dependencies on
the gnat
crate, which apply to every compiler, and dependencies on a precise
native or cross-compiler.
The native compiler for each platform is always gnat_native
, whereas
cross-compilers follow the naming convention gnat_<target>
(e.g.,
gnat_riscv_elf
). Alire will only offer to install valid cross-compilers for
the host platform.
Compilers available for download can be listed with alr search --full
--external-detect gnat_
. They will also be shown by the selection assistant,
alr toolchain --select
.
Running alr toolchain
without arguments will show the installed compilers and
the preferred compiler, if any.
Besides selecting a default compiler with alr toolchain --select
, the user
may install other compilers via alr toolchain --install
. Installed but
unselected compilers will not be used, though, unless a crate explicitly
requests them via dependencies.
Compilers can be removed with alr toolchain --uninstall
.
If a crate requires a target-specific compiler via its dependencies, alr
will
attempt to use first a matching installed compiler. Otherwise, a matching
compiler will be automatically downloaded.
Generic dependencies on gnat
will never cause a compiler download.
When a build is launched, or alr printenv
is run to obtain a build environment,
alr
will use the available compilers as follows:
From the point of view of a user preparing a release for publication, these are the considerations to bear in mind:
gnat
to specify known compiler version restrictions.gnat_riscv_elf
)
when your crate is purposely only available for such a target.gnat_native
) as that would unnecessarily limit the availability of a
library crate that might be useful to dependent cross-target crates.gnat_native
in cases where a crate builds a
tool to be used always in the host platform, for example to be used in some
action during the build process.Independently of the compiler made available by alr
in the environment, the
crate project file still must define an appropriate Target
attribute for the
desired compiler. At the moment, Alire does not examine project file contents
to identify necessary compilers, and relies only on regular depends-on
dependencies.
Publishing a project in Alire is done with the help of the alr publish
command. The steps to take are described after some introductory concepts (jump
to these steps directly here; you can also ask for help on
the gitter channel of the project.
The community index is a collection of TOML files stored in the alire-index repository, under the index directory. Each file contains a release for a crate and is named after the crate and version it contains. A file contains the description of a release, with other metadata.
The complete specification of such TOML files is available in this document.
Publishing a new crate is achieved through a pull-request against the index repository, in which the TOML file for the release must be provided.
The community index is supported through two kinds of branches:
stable-x.x.x
branches are used by stable versions of alr
.devel-x.x.x
branches are used to introduce breaking changes in the index
format, during the development of alr
.Your alr
version knows which branch to use, so you do not need to manually
select one. When using alr publish
to assist on creating a release, you will
be provided with an upload link for the branch your alr
is using.
However, when submitting releases manually, you must decide to which branch
they will be added: selecting the latest stable branch results in the release
becoming immediately available to the latest stable alr
. Conversely, using
the latest development branch will make the releases available for testing by
unstable clients, and will become generally available with the next stable
release of alr
.
Note that, as of this writing, only development branches exist, until the first
stable release of alr
is made.
Each crate is “owned” by a list of maintainers, provided with the
maintainers-logins
property of the crate file. After the initial submission,
which will be manually approved (see the policies for details),
the maintainers of a crate are the only people allowed to submit new releases
or metadata modifications to the corresponding crate.
Other checks your submission will go through are:
available
property.Depending on how you develop your project, you can use one of the following methods to prepare your release submission:
For this common use case, you need:
alire.toml
manifest describing the release.git
.alr
will inform you if your host is not supported. Please contact us if
you think a site should be allowed. The complete list can be consulted by
running alr publish --trusted-sites
.By default, the last commit is used for the release. You can alternatively provide another commit, tag, or branch. In any case, the git revision will be used to obtain a final commit. That is, a release cannot evolve with a branch, or be updated by moving a tag.
alr publish
to use the last commit. You can, alternatively, issue:
alr publish . <commit|tag|branch>
Note the path between publish
and your non-commit revision. Likewise, you can
run this command from outside your repository, as long as you supply the proper
path to it.
At this point, alr publish
will carry out a few tests and, if everything
checks out, it will create a ${repo_root}/alire/releases/crate-version.toml
file. This file must be submitted to the community index via a PR. A link for
conveniently creating this PR will also be provided by alr
:
crate-version.toml
) to the
supplied page link on github and create a pull-request.This case is analogous to the previous one, but you don’t need the local repository. The same considerations about allowed hosts discussed in the previous scenario apply:
alire.toml
manifest describing the release.git
.alr
will inform you if your host is not supported. Please contact us if
you think a site should be allowed. The complete list can be consulted by
running alr publish --trusted-sites
.The only difference when invoking alr
is that you must supply the remote URL
and commit (not a tag or branch). The commit must exist in the repository:
alr publish <URL> <commit>
The checks will be carried out and the outcome will be the same as in the previous scenario.
This case can be used when you use another VCS other than git
, or do not work
with an online repository.
In this use case, you start from an already prepared final remote tarball/zipball:
git archive
.alire.toml
manifest must be placed at the top-level with the rest of
your sources (inside the same single directory just described), containing
all required information except for the [origin]
table, which will be created
by alr
.alire
directory generated by
alr
in working directories. The alire
directory is designed to be
put in your VCS ignore list.With the source archive already uploaded to the online host where it is going to be served (there are no restrictions on this host), you should issue
alr publish <URL>
and the publishing process will carry on as in the previous cases, performing the checks and providing you with a file to submit to the index, and an upload URL to do so.
Invoking alr publish --tar
inside an Alire workspace will result in the
creation of a source archive at ${CRATE_ROOT}/alire/archives/
. This archive
must be manually uploaded (for now) by the user to a publicly accessible
hosting service.
After the upload, the user can supply the URL to fetch this archive to the
publishing assistant (which will be waiting for this information), and the
assistant will resume as if it had been invoked with alr publish <URL>
(see #starting-with-a-remote-source-archive).
In case your project does not easily map to a single Alire crate (e.g., because you manage multiple project files with different dependencies, or there are other reasons to keep the sources together even if they generate several crates), you have several options.
The simplest one is to store each crate in a subdirectory within the
repository, with its corresponding Alire manifest, sources and project files.
With the repository up-to-date with the remote, and the local copy checked out
at the desired commit, issuing alr publish
in each subdirectory will properly
recognize that the crate is nested below the repository root. Furthermore, when
using this method, all nested crates will share the same storage when retrieved
as dependencies.
A similar alternative would be to publish each crate relying on source archives
In this case you can use alr publish --tar
normally inside each subdirectory.
Compared with the previous options, there is no disadvantage to this method if
you favor source archives.
Another possibility would be to use a bit of scripting to create temporary
subfolders with the described organization, and again using alr publish --tar
normally.
Finally, the alr publish
command provides a --manifest <file>
switch to
work in place with several crates. You can have different manifests at custom
locations (other than the expected ./alire.toml
) and provide each one in turn
with the --manifest
switch to create their respective crate. In this case,
alr
temporarily uses the given file as the root manifest, so all sources will
be packaged for each crate. This is a bit wasteful, but as long as each crate’s
project files are properly defined (no shared sources), this remains an option
to split the sources into crates. With the current support for autodetection of
crates in subdirectories, this option is not recommended for new repositories.
If your case does not fit well into any of the situations above we definitely want to hear about it, to see how it can be brought into existing or new Alire workflows.
Instead of uploading the generated index manifest file via the github upload link, you can follow the usual procedure to submit a PR to a github repository:
hub
tool).
Once the pull request is verified and merged, the new release will become available for normal use. The open source Ada ecosystem needs all the help it can get, so thank you for contributing!
If you like, you can add a nice, shiny badge to your project page which links back to the Alire website. This can even serve as a reminder to republish your project once you published a new release, because the badge shows the latest version of your project that is known to Alire.
The Alire website is updated once a day, every day. Hence, after we accepted and merged your pull request, it might take up to a day for your changes to appear there, usually less.
To add the badge, all you need to do is add the line
[](https://alire.ada.dev/crates/YOUR_CRATE.html)
to your README.md
. Of course, you need to replace the string YOUR_CRATE
with
your actual project’s crate name.
Here’s an example:
[](https://alire.ada.dev/crates/hal.html)
This will be shown as:
Each release belonging to a crate is described as a TOML file. This file has
minor differences depending on its location: a local manifest is found at the
top-level directory of the sources of a project, in which case its named
alire.toml
, whereas a manifest found in an index (e.g., the community index),
is named <name>-<version>.toml
.
Other than that, contents follow the same conventions and there are only slight differences (some fields are intended only for an index manifest, and cannot appear, or are optional, in a local manifest). These differences are highlighted in the following descriptions, where necessary.
Each TOML description file contains exactly one release, except for the special external definitions that are described in their own section.
This section describes the various encodings used in this format to encode information.
First, there are two kinds of data: atomic and composite.
Atomic data designates values that cannot be decomposed. There are only two atomic data types:
"Hello, world!"
);true
, false
);When a string denotes a relative path intended to be portable across operating
systems, it must use forward slashes as directory separator: "path/to/my/resource"
.
We can then split composite data in two kinds: lists (TOML’s arrays) and mappings (JSON’s tables). Lists are just sequences of other values, for instance a list of strings:
["A", "B"]
Mappings are the traditional sets of associations from keys (here, always strings) to other values. For instance, the following represents a set of dependencies, with version constraints:
libfoo = "^1.2"
libbar = "^2.0 & /=2.1.3" # Excluding a known bad version
In some contexts, information can be dynamic: special encodings can be used to make data vary depending on the environment (OS, architecture, …). The environment is represented as a set of specific variables which can have a specific set of values: see the Parameters section below for a comprehensive list.
All properties that support dynamic expressions follow the same structure, in which the expression (case-like) is inserted between the key and its value. For example, given a static expression:
key = "value"
one of its cases would be expressed by the following inline TOML table:
key.'case(var)'.var_value = "value"
Several expressions can be inserted between a property key and its value,
leading to a combinatorial explosion if all cases have specific values. The
equivalent to an others
Ada clause in this format is a '...'
entry.
Here is an example of a conditional boolean value.
{'case(distribution)' = {
'debian|ubuntu': true,
'...': false
}}
# Or in a more idiomatic TOML syntax
['case(distribution)']
'debian|ubuntu' = true
'...' = false
Depending on the value of the distribution
environment variable, this will
return true
(its value is debian
or ubuntu
) or false
(for other
values). Note that these and subsequent examples are not showing the
left-hand-side property to which such a value would be assigned.
A little variation allows building environment-dependent composite data. For
instance, to make the dependency on libbar
above dynamic:
{
"libfoo": "^1.2",
"case(os)": {
"linux": {"libbar": "^2.0"},
"windows": {"libwinbar": "^3.0"},
"...": {}
}
}
# Or in a more idiomatic TOML syntax
libfoo = "^1.2"
['case(os)'.linux]
libbar = "^2.0"
['case(os)'.windows]
libwinbar = "^3.0"
['case(os)'.'...']
The case(os)
part selects dependencies depending on the value of the os
environment variable.
If the os
environment variable contains linux
, this will create the
following dependencies:
libfoo = "^1.2"
libbar = "^2.0"
If the os
environment variable contains windows
, this will create the
following dependencies:
libfoo = "^1.2"
libwinbar = "^3.0"
And finally for other os
values:
libfoo = "^1.2"
This section describes the actual properties that must or can appear in a manifest file to describe a release. Unless specified, all the entries must be static, i.e. they cannot depend on the context.
name
: mandatory string. The name of the crate this release belongs to. Use
alr help identifiers
to see the rules such names must follow.
version
: mandatory string. The semantic version of the release.
description
: mandatory string. One-line description about the package. For
instance:
description = "Library to handle foobars"
long-description
: optional free-form string to provide information about
this package, in addition to description
, without length restrictions.
authors
: optional array of strings. Flat list of human-readable names for
the authors, i.e. the people that wrote the software that is packaged. For
instance:
authors = ["Alice Example",
"Bob For Instance <bob@example.com>"]
maintainers
: mandatory (for indexing) array of strings. Flat list of
human-readable names (optional) for the maintainers, with a contact email
(mandatory); i.e. the people that maintain the crate metadata in Alire. For
instance:
maintainers = ["alice@example.com",
"Bob For Instance <bob@athome.com>"]
maintainers-logins
: mandatory (for indexing) array of strings. Flat
list of github login usernames used by the maintainers of the crate. This
information is used to authorize crate modifications. For instance:
maintainers-logins = ["alicehacks", "bobcoder"]
licenses
: mandatory (for indexing) string. A valid SPDX
expression. Custom license identifiers are
accepted with the format: custom-[0-9a-zA-Z.-]+
licenses = "MIT"
For a double license:
licenses = "GPL-3.0-only OR MIT"
For a custom license:
licenses = "custom-my-license-1.2"
website
: optional string. URL to the original project’s website. For
instance:
website = "https://myproject.example.org/"
tags
: optional array of strings. Flat list of topics covered by the crate.
Tags will help users find crates related to their interests:
tags = ["spark", "security"]
available
: optional dynamic boolean expression. Determines whether the
package is available for the current platform (true) or not (false). For
instance:
[available.'case(distribution)']
'debian|ubuntu' = true
'...' = false
depends-on
: optional array of dynamic dependencies expressions. For instance:
[[depends-on]] # A static dependency
libfoo = "^1.2"
[[depends-on]] # A dynamic dependency
[depends-on.'case(os)'.linux]
libbar = "^2.0"
[depends-on.'case(os)'.windows]
libwinbar = "^3.0"
Available constraint operators are the usual Ada relationals (=
, /=
, >
, >=
,
<
, <=
) plus caret (^
, any upwards version within the same major point)
and tilde (~, any upwards version within the same minor point).
Note that caret and tilde do not have any special behavior for pre-1
versions. This means, for example, that ^0.2
will still mean any release
below 1.0
. The Semver specification does not make any promises about the
compatibility of pre-1 versions, and there are differing interpretations of
these operators out there for such versions. Bear in mind this when expressing
your restrictions; for pre-1 versions you most likely want to use ~0.x
constraints (compatibility within a minor version).
Logical operators for and (&), or (|) are accepted; see the Semantic_Versioning
project documentation on extended version
sets.
See also the section on compiler dependencies
for more details on how to use the depends-on
property for cross-compiling or
compiler version selection.
project-files
: optional list of strings. Each is a path, relative to the
root of the source directory, to a .gpr
project file to be made available.
Expressions are accepted. For instance:
project-files = ["my_project.gpr", "utils/utils_for_my_project.gpr"]
[project-files.'case(word-size)']
bits-64 = ["my_project.gpr"]
bits-32 = ["my_project32.gpr"]
gpr-externals
: optional table, giving a mapping from the name of external
variables in the .gpr
project files to sets of possible values (as array of
strings), or an empty string if this set is infinite. For instance:
[gpr-externals]
BUILD_MODE = ["debug", "profile", "release"]
TAG = ""
gpr-set-externals
: optional dynamic table, setting values of project
external variables when building the project. This should not be used to
specify default values, the default values must be specified in the .gpr
project file. Expressions are accepted before the mapping. For instance:
[gpr-set-externals]
BUILD_MODE = "release"
[gpr-set-externals.'case(os)']
linux = { OS = "gnu-linux" } # Compact table syntax is convenient in this case
windows = { OS = "ms-linux" } # to see all enumeration values, one per row.
environment
: optional dynamic table used to modify environment variables
that will apply at build time. Variables and values are specified with the
form VARIABLE.<action> = "value"
, where <action>
is one of append
,
prepend
, or set
. For instance:
[environment]
C_INCLUDE_PATH.append = "/usr/include/something"
MY_PROJECT_ASSETS.set= "${CRATE_ROOT}/assets"
PATH.append = "${DISTRIB_ROOT}/usr/bin"
Predefined variables are provided by Alire and will be replaced in the value:
${CRATE_ROOT}
absolute path to the deployment directory of the crate.${DISTRIB_ROOT}
absolute path to the root directory of the system
distribution. On UNIX systems it will be /
, on Windows msys2
it will
be the msys2
installation directory (e.g.
C:\Users\user_name\.cache\alire\msys2
).Environment entries can use dynamic expressions:
[environment.'case(distribution)']
msys2 = { C_INCLUDE_PATH.append = "${DISTRIB_ROOT}/mingw64/include/SDL2" }
executables
: optional dynamic list of strings. Each one is the simple name
of an executable provided by the package. Executables are looked for by
alr
in the build tree and must not include a path. If only one executable is
given, it is considered the default for alr run
. For instance:
executables = ["my_main"]
actions
: optional dynamic list of actions to perform when certain events
take place in a workspace. The general action syntax is:
[[actions]]
type = <kind>
command = <command>
<command>
is an array of strings for a shell command to run in the
source directory.
For events that cause a workspace-wide triggering of actions (all
pre_/post_
actions described next), the actions are invoked in a
dependency-safe order, starting at the leaves of the dependency graph
(releases with no dependencies) and moving up to the root release (the working
release, or the release being obtained with alr get
). In this context, the
root release is considered part of the dependency solution, and so its
actions are executed too, always in the last place.
<kind>
can be either:
post-fetch
: the command is to be run whenever there are new sources
deployed in the workspace, in any release in the solution. All releases
post-fetch
actions are run after the new deployment is complete. Initial
retrieval, subsequent modification of dependencies, pinning a
directory or repository is considered a deployment of new sources. A manual
alr update
, even if it results in no changes, will also trigger this
action in every release in the solution.
pre-build
: the command is to be run right before the build of the
workspace starts. This kind of action is run for all releases in the
solution.
post-build
: the command is to be run right after a build has
successfully completed. This kind of action is run for all releases in the
solution.
test
: the command is run on demand for crate testing within the Alire
ecosystem (using alr test
). This kind of action is run only for the
root crate being tested, after its build succeeds, and after any
post-build
actions.
Since actions may end being run more than once they should take this into account and allow multiple runs with the expected results intended by the packager.
Actions accept dynamic expressions. For example:
[[actions.'case(os)'.linux]]
type = "post-fetch"
command = ["make"]
[[actions.'case(os)'.windows]]
type = "post-fetch"
command = ["cmd", "build"]
[[actions.'case(os)'.'...']]
# An explicit empty case alternative, which is not mandatory
auto-gpr-with
: optional Boolean value that specifies if the project (gpr) files
of a crate can be automatically depended upon (‘withed’) directly by the root
project file. (The default is true.) This feature is meant to simplify the process
of using dependencies in Alire. However, not all project files are supposed to be
direct dependencies. Some are intended to be extended, for example, and in that
case a crate can disable the feature by setting auto-gpr-with=false
.
origin
: dynamic table. Mandatory for index manifests and forbidden in
workspace manifests. This table describes how sources are obtained, using
the following fields:
url
: mandatory string which points to a source file or repository.
hashes
: mandatory string array for source archives. An array
of “kind:digest” fields that specify a hash kind and its value. Kinds
accepted are: sha512
.
archive-name
: optional string. If url
points to a source archive,
this can specify the name of the file to download, which is needed in
order to properly extract the sources, in case the URL does not identify it.
commit
: mandatory string for VCS origins that describes the
VCS-specific revision to be checked out (a git/hg hash, a svn
revision).
subdir
: optional relative path, only valid for repository origins,
that when provided indicates that the crate is not located at the
repository root. This option enables the possibility of publishing
several crates from the same repository (sometimes referred to as a
monorepo).
Examples of origin tables:
# Clone a git repository with a crate at its root
[origin]
url = "git+https://github.com/example-user/example-project"
commit = "ec8b267bb8b777c6887059059924d823e9443439"
# Download and extract a source archive
origin = "https://example.org/0123456789"
archive-name = "archive.tar.gz"
hashes = ["sha512:bf6082573dc537836ea8506a2c9a75dc7837440c35c5b02a52add52e38293640d99e90a9706690591f8899b8b4935824b195f230b3aa1c4da10911e3caf954c04ac"]
# Clone a git repository with the crate in a subdirectory
[origin]
url = "git+https://github.com/example-user/example-project"
commit = "ec8b267bb8b777c6887059059924d823e9443439"
subdir = "examples"
available
: optional dynamic boolean expression. If it evaluates to
false
, the package is not available for the current platform.
notes
: optional string. Provides miscellaneous information about this
release. For instance:
notes = "Experimental version"
configuration
: optional table to control crate configuration code
generators:
For more information on crate configuration, see Using crate configuration.
disabled
: Completely disable configuration code generation for the
crate (default: false
)
output_dir
: Path to the directory where the configuration code will
be generated, relative to the crate root (default: config
).
generate_ada
: Enable generation of Ada configuration (default:
true
).
generate_gpr
: Enable generation of GPR file configuration (default:
true
).
generate_c
: Enable generation of C configuration (default: true
).
auto_gpr_with
: Enabled generation of list of withed project in the
GPR file configuration (default: true
).
configuration.variables
: optional table of crate configuration variable
definitions.
For more information on crate configuration, see Using crate configuration.
The keys of the table are names of the variables. Variable definitions themselves are tables with the following entries:
type
: mandatory string which defines the type of the variable, it can
be:
String
: any string
Boolean
: either True
or False
Enum
: enumeration type
Integer
: an integer value that can be encoded in 64-bit
Real
: a real value that can be encoded in IEEE 754 binary64
default
: optional default value for the variable. Will be used if no
crates explicitly set a value for this variable. Must be a valid value
for the type.
first
: (optional) for Real
and Integer
types only. Defines the
lower bound of valid values for the type (inclusive).
last
: (optional) for Real
and Integer
types only. Defines the
upper bound of valid values for the type (inclusive).
values
: mandatory for Enum
types. An array of strings containing
all the possible values for the enumeration.
Example:
[configuration.variables]
Device_Name = {type = "String", default = "no device name"}
Print_Debug = {type = "Boolean", default = false}
Debug_Level = {type = "Enum", values = ["Info", "Debug", "Warn", "Error"], default = "Warn"}
Buffer_Size = {type = "Integer", first = 0, last = 1024, default = 256}
Max_Power = {type = "Real", first = 0.0, last = 100.0, default = 50.0}
configuration.values
optional table of variables assignment:
The keys of the table are crate names, and entries are sub-tables of
variable_name
and value
. The type of the value has to match the
definition of the variable type.
Example:
[configuration.values]
crate_1.var1 = 42
crate_1.var2 = true
crate_2.var1 = "Debug"
build-profiles
: optional table of strings that sets the build profile of
crates in the solution.
For more information on build profiles and switches, see Build profiles and switches.
There are 3 build profiles available in Alire:
Development
Release
Validation
Example:
[build-profiles]
depend1 = "validation" # Set depend1 build profile to validation
depend2 = "development" # Set depend2 build profile to development
my_crate = "release" # Set my_crate build profile to release
A wildcard key can be used to set the build profile of all crates that are not otherwise specified:
[build-profiles]
"*" = "validation" # Set all build profiles to validation
build-switches
: optional table of build profile switches definitions.
For more information on build profiles and switches, see Build profiles and switches.
The keys of the table are either build profiles or the wildcard "*"
:
Development
Release
Validation
The values are profile definitions, themselves tables with switch categories as keys and switches selection as values. This list of switch categories and their corresponding selection is as follow:
Optimization
Performance
Size
Debug
Debug_Info
No
Yes
Runtime_Checks
None
Default
Overflow
Everything
Compile_Checks
None
Warnings
Errors
Contracts
No
Yes
Style_Checks
No
Yes
Ada_Version
Compiler_Default
Ada83
Ada95
Ada05
Ada12
Ada2022
GNAT_Extensions
For example, to enable all run-time checks in the release profile:
[build-switches]
release.runtime_checks = "Everything"
To disable style checks for all profiles:
[build-switches]
"*".style_checks = "No"
All switch categories also accept a custom list of switches, for instance:
[build-switches]
release.optimization = ["-O1"]
validation.style_checks = ["-gnatyg"]
provides
: specifies a list of releases of another crate for which the
current release is a drop-in replacement. I.e., the crate is either
API-compatible or call-compatible, depending on how it is to be used (as a
source library, or providing some command-line tool).
Example:
name = "foo"
provides = ["bar=1.1"]
# A crate depending on `bar^1` might find this `foo` release in its solution instead.
forbids
: an array of tables containing dependency specifications, just as
the depends-on
property. Releases matching one of the forbidden
dependencies are prevented from appearing in a solution with the release
doing the forbidding.
There are two use cases for this property:
provides
field. In this case the release must both provide and forbid
the crate for which it is a replacement.Example:
name = "bar"
version = "1.0"
provides = [ "foo=1.0" ]
[[forbids]]
baz = "*" # This crate cannot coexist with ours for some reason
foo = "*" # No other crate that provides foo is needed/allowed at the same time
It is usual to develop several interdependent crates at the same time. In this scenario, it is often impractical to rely on indexed releases which are not intended to be modified. Instead, one would prefer to use a work-in-progress version of a crate to fulfill some dependency.
Alire provides pins to support this use case. Pins override dependencies, they are intended to be used locally, and to be fulfilled by proper dependencies once a crate is ready to be published. The use of pins is based on two ideas:
depends-on
array of the manifest, even for those dependencies to be pinned. This way, once the release is ready, pins are simply removed and the actual dependencies are used in their place.[[pins]]
array of the manifest.Three kinds of pins are available, all of them with the syntax:
crate_name = { pin_attributes }
The specific pin kinds and their attributes are:
Pins to versions: used to force the use of a particular version of an indexed crate.
version
: a string containing a single version to be used.crate_name = { version = "1.2+hotfix-1" }
Pins to local crates: a local directory will fulfill the crate dependency, no matter what version is given in its local manifest. “Raw” Ada projects without an Alire manifest can be used too, as long as their project file matches the crate name and it is located in the directory given as override.
path
: an absolute or relative path to the crate directory.crate_name = { path = "../my/wip/crate" }
For the common case of directories containing an Alire manifest, dependencies and pins will be included recursively in the build context.
Pins to git repositories: the repository will be cloned locally and its directory will be used as in the previous case. This pin may optionally include a commit to fix the checkout to be used, or a branch to track. Otherwise, the default branch will be used. Running alr update
will refresh the checkout.
url
: the URL of a git repositorycommit
(optional): a complete git commit hash.crate_name = { url = "https://my/repo.git" } # Updatable pin to default branch
crate_name = { url = "https://my/repo.git", branch="feature" } # Updatable pin
crate_name = { url = "https://my/repo.git", commit="abcdef..." } # Fixed pin
Pins are also useful to have a separate test project that depends on your main crate. The recommended setup is as follows:
/path/to/my_crate
├── alire.toml
└── tests
└── alire.toml
I.e., a tests
crate is initialized within the main my_crate
. In tests
manifest, you have a dependency and local relative path pin for my_crate
:
# tests/alire.toml
[[depends-on]]
my_crate = "*" # Any version of the main crate
aunit = "*" # We can have dependencies for testing only
[[pins]]
my_crate = { path = ".." } # Overridden by the latest sources
Then, my_crate
is published normally, and tests
can be used locally for any kind of testing needed on my_crate
without polluting my_crate
manifest with test specifics (like extra dependencies used by the test setup).
The above information applies to regular releases distributed from sources (that is, the Ada projects whose distribution is the main Alire goal). Some special supporting releases also exist that are described differently.
A release is considered “external” when it is not built from sources and,
furthermore, its semantic version cannot be known until run time. Hence, the
availability and version of these releases is detected by alr
.
Several definitions for these external releases may exist so they are
defined in a manifest as a vector with key external
:
[[external]]
# Common entries to all externals
kind = "hint" # One of several predefined external kinds
hint = "Please install SDL in your platform from source or system packages"
# Specific external kind parameters might follow
All external kinds can define these regular properties:
available
: when defined, it restricts the external detection to the given
environment conditions.
hint
: optional dynamic string containing an explanation for the user on
how to make the external entity available. This explanation is shown on request
with alr show --external
, or after alr get
, for any external dependency
that could not be detected.
A plain undetectable external kind intended to simply serve as a hint. For
crates that are known to be unavailable through Alire, it serves to
provide a generic or customized hint to the user. It has no specific
fields, other than the common ones just described. Its key is "hint"
:
[[external]]
kind = "hint" # Identifies this external kind
# Bare minimum external. Optionally, the hint/available fields can be used.
This external kind is used to describe commands that can be run in the system, and that are able to provide their own version via some particular invocation. Their specific fields are (all mandatory):
kind = "version-output" # Identifies this external kind
version-command = ["gnat", "--version"]
# Invocation that will provide the version when the tool is available
version-regexp = "^GNAT ([\\d\\.]+).*|^GNAT Community ([\\d]{4}).*"
# TOML-escaped GNAT.Regpat-compatible regular expression. Parenthesized
# matches will cause the matched expression to be parsed as the Semantic
# Version of the tool.
provides = "another_crate_name"
# This crate will be equivalent to `another_crate_name` for the solver. The
# version will be the same as detected for the current external. For example,
# all GNAT compilers provide the "gnat" crate, and so there cannot be two
# compilers in the same solution.
Systems that have their own package manager (e.g. Linux) can readily provide many complex dependencies still unpackaged as source code in Alire. Alire can use these on supported platforms (at this time, Debian & Ubuntu. Do not hesitate to contact us if you would like to maintain other distributions) during resolution.
A system external gives a list of platform package names that supply the
dependency natively. The platform package manager will be used to detect their
availability and version. To that effect, the origin
field is used (which can
accept dynamic expressions in this context):
kind = "system" # Identifies this external kind
origin = ["libncursesada3", "libncursesada5"]
# As versions appear this list will grow. To speed up detection, dynamic
# expressions may become recommended for certain system packages.
For Ada pre-compiled system libraries that require the platform compiler for
linking (e.g., in Debian/Ubuntu), and that cannot be used with other GNAT
compilers, this should be expressed with the available
property, e.g.:
available.'case(toolchain)'.user = false
# `available` defaults to true, so it is enough to flag the user toolchains
os
: name of the OS. Currently supported values are: linux
, macos
and
windows
.
distribution
: name of the Linux distribution, or none
if running on a
different OS. Currently supported values are: debian
, ubuntu
.
toolchain
: takes system
value in distributions with the system Ada
compiler first in PATH (GNAT FSF in Debian/Ubuntu), user
otherwise (GNAT
Community editions, other cross-target toolchains).
word-size
: architecture word size. Currently supported values are:
bits-32
, bits-64
, bits-unknown
Alire
provides a mechanism for crates to expose a list of variables that can
be set by other crates depending on them. The configuration variables will then
be converted to Ada, C and GPR source files that can be used to change the
behavior or feature set of the code.
Let’s start with a simple example. A crate named test
can print debug log on
the console. However printing on the console has a performance impact, for an
embedded project it can even have a significant code size impact. Therefore it
would be best if this logging can be disabled/enabled at compile time.
To achieve this, a crate maintainer can define a configuration variable in the
crate manifest alire.toml
. The definition will be like so:
[configuration.variables]
Enable_Logs = {type = "Boolean", default = false}
A single variable of type Boolean
with a default value of false
.
From this definition, Alire
will generate various source files, including an
Ada package specification:
package Test_Config is
Enable_Logs : constant Boolean := False;
end Test_Config;
In the crate source code, this configuration package can be used like so:
if Test_Config.Enable_Logs then
Print_Log ("This is a log message.");
end if;
If one of the crates depending on test
sets the configuration variable to
true
, e.g.:
[configuration.values]
test.Enable_Logs = true
The constant value will change in the generated configuration package:
package Test_Config is
Enable_Logs : constant Boolean := True;
end Test_Config;
Which will enable logging in the test
crate.
It is possible for multiple depending crates to set test.Enable_Logs
to the
same value, however if two depending crates set the variable to a different
value then the configuration is invalid and Alire
will print an error. If no
depending crates set the test.Enable_Logs
variable, then its default value is
used.
Usually when something has to be static or known at compiler-time, either for performance or memory usage.
When the Ada languages provides a better alternative. There are many ways to provide an Ada API that will result in compile time optimization or static memory usage.
For instance, discriminants are an effective way to let the user define the size of a buffer:
type Buffered_Thing (Size : Positive) is private;
private
type Buffer_Array is array (Positive range <>) of Unsigned_8;
type Buffered_Thing (Size : Positive) is record
Buf : Buffer_Array (1 .. Size);
end record;
With this definition, users are then able to allocate either statically, on the stack or on the heap depending on their project.
Thing : Buffered_Thing (Size => 256);
Enumerations variables in crate configuration can be used to set a level of log verbosity:
[configuration.variables]
Log_Level = {type = "Enum", values = ["Info", "Debug", "Warn", "Error"], default = "Warn"}
Integer variables can be used the define the size of a static buffer:
[configuration.variables]
Buffer_Size = {type = "Integer", first = 0, last = 1024, default = 256}
This is useful in particular for embedded projects where compile time memory usage is preferred over dynamic allocation.
String variables can be used to define the URL of a website or service:
[configuration.variables]
URL_Name = {type = "String", default = "example.com"}
Real variables can be used for PID coefficients:
[configuration.variables]
Proportional = {type = "Real"}
Integral = {type = "Real"}
Derivative = {type = "Real"}
Integer variable can be used to define The maximum length of file names in a file-system:
[configuration.variables]
Max_Filename_Length = {type = "Integer", first = 5, last = 128}
Crate configuration also generates a GPR project file, therefore it can be used to control which units are compiled in the project.
[configuration.variables]
Sort_Algorithm = {type = "Enum", values = ["bubble", "quick", "merge"]}
The generated GPR will look something like this:
project Test_Config is
type Sort_Algorith_Kind is ("bubble", "quick", "merge");
Sort_Algorith : Debug_Level_Kind := "quick";
end Test_Config;
It can be used in the main GPR file like so:
package Naming is
for Body ("Test.Sort") use "test-sort__" & Test_Config.Sort_Algorith;
end Naming;
With the files test-sort__bubble.adb
, test-sort__quick.adb
and
test-sort__merge.adb
each implementing a different algorithm.
In the crate configuration Alire also generates a few built-in values to identify the host platform:
Alire_Host_OS
Alire_Host_Arch
Alire_Host_Distro
They can be used in the main GPR file to add a different source directory based on the OS. For instance:
for Source_Dirs use ("src",
"src/" & Test_Config.Alire_Host_OS);
with the following directory tree:
+-- src
+-- host_specific.ads
+-- linux
| +-- host_specific.adb
+-- macos
| +-- host_specific.adb
+-- windows
+-- host_specific.adb
As part of crate configuration, Alire will generate a list of compiler switches in the configuration GPR file. The list of switches for a given crate is controlled from two features:
There are 3 build profiles available in Alire:
Development
Release
Validation
By default, the root crate is in Development
and the dependencies are in
Release
. The defaults can be overridden in two ways:
alr build
command:
$ alr build --release
$ alr build --validation
$ alr build --development
(default)In the root crate manifest, the build profile of each crate in the solution
can be changed with the [build-profiles]
table.
This can be used, for instance, in a unit test crate to set the crate under
test in validation
profile, or to debug one of the dependencies.
Example:
[build-profiles]
lib_under_test = "validation"
lib_to_debug = "development"
Each crate can customize the compiler switches corresponding to its profiles
using the [build-switches]
table. In general, this should be avoided to
preserve consistency in the ecosystem. However, there are cases where it makes
sense for a crates to change its build switches. For instance, a SPARK crate
that is proved to be safe from errors can disable run-time checks in all
profiles:
[build-switches]
"*".runtime_checks = "none"
It is also possible to specify a custom list of compiler switches for a category:
[build-switches]
release.optimization = ["-O1", "-gnatn"]
Alire will generate a list of switches in the crate configuration GPR file. It will look something like this:
abstract project my_crate_Config is
[...]
Ada_Compiler_Switches := External_As_List ("ADAFLAGS", " ") &
(
"-Os" -- Optimize for code size
,"-gnatn" -- Enable inlining
);
[...]
In the main GPR file, “with” the crate config GPR and use the
Ada_Compiler_Switches
variable to define compiler switches:
with "config/my_crate_config.gpr";
project My_Crate is
[...]
package Compiler is
for Default_Switches ("Ada") use My_Crate_Config.Ada_Compiler_Switches;
end Compiler;
Dependencies in Alire are used also to deal with compiler versions and
cross-compilers. Also related is the information on toolchains available in the
Toolchain management document or via alr help toolchains
.
One may know that a particular compiler version has a problem with some code.
This may be expressed with dependencies on the generic gnat
crate, which
although is not found in the catalog, is a crate that all GNAT compilers
provide. (Such a crate without actual releases, but provided by other crates,
is called a virtual crate.) For example:
gnat = ">=7" # We require a minimum compiler version
gnat = "/=7.3" # We know a precise version is incompatible
Since only one dependency on a same crate may appear, the relational operators
&
(and), |
(or) can be used instead:
[[depends-on]]
gnat = "/=7.3 & >=7"
The other use of compiler dependencies is to specify that a compiler for a particular target is needed. (Note that the project file also has to specify the proper target and runtime.) This way Alire can configure the appropriate environment for the build. For example:
gnat_arm_elf = "*" # Any compiler targeting ARM
Dependencies on cross-compilers should only be used in crates that actually require a concrete target (e.g., final binaries) to avoid preventing their use as general libraries with any compiler.
You can inspect index files to get an idea of how projects are included into the catalog.
alr
provides a generic mechanism to list
, get
, set
or
unset
configuration options, either in a local or global context.
Option names (keys) can use lowercase and uppercase alphanumeric characters from the Latin alphabet. Underscores and dashes can also be used except as the first or last character. Dot ‘.’ is used to specify sub-categories, e.g. ‘user.name’ or ‘user.email’.
Option values can be integers, floats, Booleans (true or false), or strings. The type detection is automatic, e.g. 10 is integer, 10.1 is float, true is Boolean. You can force a value to be a string by using double-quotes, e.g. “10.1” or “true”. Extra type checking is used for built-in options (see below).
Specific config options:
--list
List configuration options--show-origin
Show origin of configuration values in --list
--get
Print value of a configuration option--set
Set a configuration option--unset
Unset a configuration option--global
Set and Unset global configuration instead of the local one--builtins-doc
Print Markdown list of built-in configuration optionsExamples:
alr config --global --set my_option option_value
Will set a configuration option with the key my_option
and the string
value option_value
in the global configuration file.
alr config --get my_option
Will print the value configuration option my_option
if it is defined,
otherwise the command fails.
The alr config
command allows you to set and get any combination of
configuration option key
and value
. You can use this feature to store your
own project related configuration, or implement tools that integrate in an
Alire
context. However, be careful when naming custom configuration options
because Alire
may use the same key
in the future. We recommend using a
distinctive sub-category name, for instance: my_project.my_config_option
.
The options used by Alire
are pre-defined and documented. We call these
options built-ins
.
A built-in option has a pre-defined type that is checked when setting or loading a configuration file. For instance:
alr config --global --set user.email "This is not an email address"
will fail because the value tentatively assigned to user.email
is not an
email address.
The built-ins also have a short description to document their type and usage.
Here is the list of Alire
built-in configuration options. You can also get
this from alr
with alr help config
.
index.auto_community
[Boolean]:
When unset (default) or true, the community index will be added automatically when required if no other index is configured.
user.name
[String]:
User full name. Used for the authors and maintainers field of a new crate.
user.email
[Email address]:
User email address. Used for the authors and maintainers field of a new crate.
user.github_login
[GitHub login]:
User GitHub login/username. Used to for the maintainers-logins field of a new crate.
editor.cmd
[String]:
Editor command and arguments for editing crate code (alr edit). The executables and arguments are separated by a single space character. The token ${GPR_FILE} is replaced by a path to the project file to open.
msys2.do_not_install
[Boolean]:
If true, Alire will not try to automatically install msys2 system package manager. (Windows only)
msys2.install_dir
[Absolute path]:
Directory where Alire will detect and/or install msys2 system package manager. (Windows only)
msys2.installer
[String]:
Filename of the executable msys2 installer, e.g. ‘msys2-x86_64-20220319.exe’. (Windows only)
msys2.installer_url
[String]:
URL of the executable msys2 installer, e.g. ‘https://github.com/msys2/msys2-installer/releases/download/2022-03-19/msys2-x86_64-20220319.exe’. (Windows only)
update-manually-only
[Boolean]:
If true, Alire will not attempt to update dependencies even after the manifest is manually edited, or when no valid solution has been ever computed. All updates have to be manually requested through alr update
distribution.disable_detection
[Boolean]:
If true, Alire will report an unknown distribution and will not attempt to use the system package manager.
solver.autonarrow
[Boolean]:
If true, alr with
will replace ‘any’ dependencies with the appropriate caret/tilde dependency.
warning.caret
[Boolean]:
If true, Alire will warn about the use of caret (^) for pre-1 dependencies.
warning.old_index
[Boolean]:
When unset (default) or true, a warning will be emitted when using a compatible index with a lower version than the newest known.
toolchain.assistant
[Boolean]:
If true, and assistant to select the default toolchain will run when first needed.
Because Alire comes late in the history of the Ada and SPARK languages we will not apply a strict “first come, first served” policy on crate names. At least for the first months or years, we allow ourselves a degree of control on the projects/crates published in the index, with the following goals:
To that end we will potentially reject a crate or transfer the ownership of a crate.
We count on the goodwill of the contributors to help us conduct this moderation in a kind and courteous way. Do not submit a crate to the Alire index if you are not willing to comply with this policy.
As the Alire project matures, we expect to do less moderating and potentially remove this policy in favor of a “first come, first served” policy.
A release (identified by a unique semantic version) is protected against changes by its integrity hashes. If errors are identified post-publication, a release could be withdrawn, or superseded by a new one (using the appropriate major/minor/patch/build version changes), but not modified.
Avoid using ada
as a prefix for your crate name, this will make the
project harder to find in a list. ada
suffix is ok when the project is a
binding for an existing library (e.g. sdlada
, gtkada
).
Split big projects in multiple crates:
If your project is a collection of components (like GNATcoll for instance) and each component has different dependencies, you should consider splitting the collection into multiple Alire crates. The components can still be maintained in the same repository and use the same release archive/commit (e.g. gnatcoll_sqlite, gnatcoll_sql, gnatcoll_postgres).
If your project is an application/executable/tool, some parts of the application may be interesting on their own and could benefit the ecosystem. For instance a parser for a standard file format would be useful across projects.
GPR project file clashes: to prevent issues when combining the GPR project files of different crates, we recommend to follow the rules below:
Use a project file name that matches the name of the crate (e.g.
my_crate.gpr
for a crate named my_crate
)
Avoid using multiple GPR project files for a single crate
Avoid using common names for GPR project files such as shared.gpr
,
common.gpr
, config.gpr
, etc.
Build_Mode := External ("MY_CRATE_BUILD_MODE", "release");
Avoid common names for GPR scenario variables such as OS
, TARGET
,
BUILD_MODE
, MODE
, etc.
For library projects, do use the “standard” LIBRARY_TYPE
external, but
wrap it in a crate specific external:
type Library_Type_Type is ("relocatable", "static", "static-pic");
Library_Type : Library_Type_Type :=
external ("MY_CRATE_LIBRARY_TYPE", external ("LIBRARY_TYPE", "static"));
for Library_Kind use Library_Type;
Having the MY_CRATE_LIBRARY_TYPE
external will allow users to override
the value LIBRARY_TYPE
just for this crate, if need be.
This document is a development diary summarizing changes in alr
that notably
affect the user experience. It is intended as a one-stop point for users to
stay on top of alr
new features.
PR #983
Actions defined in a working release can be listed now with alr action
. A
specific kind of action can be triggered by specifying its kind. Actions in the
complete dependency tree can be listed and triggered with the --recursive
switch.
$ alr action # Display actions defined in the root release
$ alr action --recursive # Display all actions in the root and dependencies
$ alr action post-build # Run post-build actions in the root release
$ alr action post-build -r # Run post-build actions in the root and dependencies
PR #939
A crate can now be located nested within a repository and still be published
as a repository origin. This enables simpler publishing of such crates, as alr
publish
will automatically recognize the situation. For example, let us say we
have this structure:
my_repo
+-- my_crate
+-- my_crate_examples
Running alr publish
at ./git_repo/my_crate
or
./git_repo/my_crate_examples
will detect that the crate is not at the
root and adjust the origin metadata to take into account the extra path.
Other typical hierarchies that should likewise work are:
my_crate (also a repository)
+-- examples
my_repo
+-- crate1
+-- examples
+-- crate2
+-- examples
At this time alr publish
will not remove pins, so that is still a manual
adjustment that the user may have to perform prior to publishing; that is, the
manifest at each nested crate must be manually readied for publishing (just as
for any other regular crate).
PR #896
The default build profile for the root crate is Development
. This
can be changed with the --release
, --validation
and --development
switches for alr build
.
$ alr build --release # build with release profile
$ alr build --validation # build with validation profile
$ alr build --development # build with development profile
$ alr build # build with development profile
PR #895
As part of the crate configuration feature, Alire will generate a list of compiler switches in the configuration GPR file. The list of switches is controlled from two features:
PR #853
It is now possible to define in configuration (local or global) aliases for the
alr
commands.
$ alr config --set --global alias.graph 'show --graph'
$ alr graph
Will run the alr show
command with the --graph
switch.
alr exec -- <command line>
PR #853
This new command takes an executable and arguments and run them in the Alire environment/context of the current crate.
$ alr exec -- sh -c 'echo ${ALIRE}'
True
PR #853
Using the --
delimiter the switches and arguments for alr clean
can now be
passed to the underlying gprclean
execution.
For instance:
$ alr clean -- -XTEST=42
PR #850
Using the --
delimiter, the switches and arguments for alr build
are now
passed to the underlying gprbuild
execution.
For instance:
$ alr build -- -f
will force recompilation.
PR #850
Before this change the global switches (-f
, -n
, --config=
, etc.) could be
placed anywhere on the command line. For instance, the following two commands
were equivalent:
$ alr -f show
$ alr show -f
Global switches are now only allowed before the sub-command name. Such that:
$ alr -f show # Is OK
$ alr show -f # Is not OK (unrecognized option '-f' for 'show')
1.1
alire
folderPR #789
The lock file (alire.lock
) is now a purely internal file, regenerated
as needed from scratch, and needs not be put under version control. Since,
furthermore, this file is not intended for user edition or inspection, it is
now created inside the alire
folder of a crate.
Existing lock files at the root of a crate will be automatically migrated to
their new location the first time an alr
command that uses the lock file is
run inside a crate with the old situation.
This change obsoletes the recommendation that accompanied PR #501 about putting the lock file under version control.
PR #781
For releases that have known incompatibilities (duplicated source names,
drop-in equivalent crates), it is now possible to express this information
through a forbids
table array, with the same syntax as dependencies. For
example:
[[forbids]]
conflicting_crate = "^1"
Releases related by a forbids
property will not appear simultaneously as
dependencies in a solution, as the solver will discard these combinations.
PR #775
A variety of GNAT compilers (native and cross-target) is now available through
Alire. These compilers are managed with the alr toolchain
new command. The
available compilers can be listed with alr search --full gnat_
.
Toolchain configuration is common to all crates in the active configuration
prefix (which can be switched with the global -c
option or by providing a
path with the ALR_CONFIG
environment variable).
The alr toolchain --select
subcommand allows selecting the preferred default
compiler (or none at all, to continue using the previous mode of operation) for
crates that do not specify one.
Crates that require a particular cross-compiler may now specify it as a regular
dependency on, e.g., gnat_riscv_elf
.
In addition to a default compiler, the preferred version of a compiler for a
target may be made available with alr toolchain --install <crate[=version]>
.
When launching a build, Alire will use preferably the default selected compiler
or, if the default is for a different target, one of the other installed
compilers. If no installed compiler is available for the crate target, Alire
will offer to download the appropriate cross-target compiler.
Finally, running alr toolchain
without arguments will list the currently
installed compilers and gprbuild versions.
PR #754
A new option for remote pins exist to track branches:
[[pins]]
wip = { url = "https://gitrepo.com/wip.git" branch="feature" }
Running alr update
will pull any changes from the branch.
PR #743.
The options to modify pins through the command-line (with --use
, alr pin
[--unpin] crate
have been disabled in favor of direct edition of the manifest.
This way, pins are more robust against lockfile format changes. These kinds of
pins exist:
[[pins]]
foo = { version = "1.3.2+bugfix" } # Require a specific version
bar = { path = "../my/bar" } # Use a local crate to override a dependency
baz = { url = "https://github.com/baz.git" } # No commit, will use HEAD, will update on `alr update`
gru = { url = "https://gitlab.com/gru.git" commit="123456890abcdef..." } # Explicit commit, won't update
PR #740.
When adding or removing dependency with alr with
, the list of with
statement for each project files of the dependencies is now automatically added
to the GPR crate configuration file instead of the root project file.
PR #715
The pinning commands (alr with --use
, alr pin --use
) now also accept a git
repository URL, which will be downloaded and used to override a dependency, as
previously could be done only with local directories. The pinning feature works
recursively, so unpublished crates can now have complete dependencies prior to
submission to the community index (which relies only on indexed dependencies).
PR #635.
The alr publish
command now supports a new --manifest <file>
switch, to
help with packaging sources that provide several crates. Maintainers can now
prepare different manifest files for the corresponding crates, and select each
one in turn for publishing, without the repository itself being an actual Alire
crate. Source management must still be taken care of by maintainers; sources
should not be shared by project files in different crates intended to be
simultaneously included.
Pre-compilation parameterization of source files can be now achieved by declaring variables and initial constant values for these variables in the Alire manifests. This allows customizing code in both the root crate and dependencies. For example:
[configuration.variables]
Device_Name = {type = "String", default = "no device name"}
Debug_Level = {type = "Enum", values = ["Info", "Debug", "Warn", "Error"], default = "Warn"}
Buffer_Size = {type = "Integer", first = 0, last = 1024, default = 256}
[configuration.values]
crate_1.var1 = 42
crate_1.var2 = true
crate_2.var1 = "Debug"
Check more examples and details in the catalog specification section “Using configuration”.
1.0
PR #675.
When a user requests a dependency without narrowing down its version set (e.g.,
alr with foo
), the solved version will be used to instead add an
“update-safe” dependency (e.g., foo^1.x
, foo~0.x
). To truly request any
version, this can be explicitly entered as alr with 'foo>=0'
.
This behavior can be disabled by setting the solver.autonarrow
configuration
option to false.
alr list
has been renamed to alr search --crates
PR #671.
To consolidate search functionality under the single alr search
command, the
old behavior of alr list
can now be achieved with alr search --crates
. By
default, alr search
looks into releases, but now it can look too into crates
with the new --crates
switch.
PR #669.
Alire does not change the meaning of caret (^) and tilde (~) operators for
pre/post-1.0 versions. This interpretation has been clarified in the catalog
specification, and alr
will warn about any suspicious usage. This warning may
be disabled by the user with the new warning.caret
configuration option.
PR #667.
GPRBuild machinery for build relocation is incompatible with some use cases, so now all builds are performed in place, using the locations given in project files. This should only have a user-visible impact for pinned dependencies, which will see changes in their build directory when Alire builds for dependent crates are run.
PR #656.
To allow backwards-compatible use of new supported environment configurations
in the index, unknown values in dynamic case expressions are silently ignored
when loading an index. In order to allow pinpointing these values (or truly
wrong entries), a new switch alr index --check
can be used that will reject
an index containing unknown values.
This error, either in indexes or a local manifest, can be downgraded to a
warning with --force
.
licenses
field to SPDX expressionsPR #629.
The licenses
in crate manifests now expects a valid SPDX
expression. Custom license identifiers are
accepted with the format: custom-[0-9a-zA-Z.-]+
.
Example:
licenses = "MIT OR custom-my-own-license"
For the 1.x
release, usage of the previous licenses
format is obsolete and
will trigger a warning. In future major releases this format will not be
accepted at all.
alr edit
PR #611.
The code editor launched by alr edit
can now be configured instead of using
the hard-coded GNATstudio. Use
alr config --set --global editor.cmd "<BINARY> <ARGS>"
for custom editor and command line arguments. The token ${GPR_FILE} is
replaced by a path to the project file to open.
For instance:
$ alr config --set --global editor.cmd "emacs ${GPR_FILE}"
The default editor is still GNATstudio.
0.7-beta
PR #529.
By using alr publish --tar
, the publishing assistant starts with the
creation of a tarball of the sources in an Alire workspace. The user must
upload this tarball to an online location, after which the assistant proceeds
as if it had been invoked with alr publish http[s]://url/to/tarball.tgz
.
PR #527.
A new publishing assistant can be invoked with alr publish [URL [commit]]
. At
this time, the assistant requires that all necessary metadata for a release,
excepting the [origin]
table, is informed in the alire.toml
file.
The assistant has local and remote modes of operation. In the local mode, the
user invokes the assistant from within a repository on its computer that is
up-to-date with its remote, and that contains an Alire workspace. In this case,
it is enough to run alr publish
.
In the remote mode, the user must prepare a source file or repository in their
final online locations, and use alr publish <URL> [<commit>]
, with the commit
being mandatory for repositories and not needed for source archives.
In all cases, alr
will fetch the sources, perform a few checks on the
completeness of the information, and generate a final metadata file, intended
to be submitted to the community index via pull request. An upload link is
provided for convenience that can be used to create this pull request.
Complete information about this feature is available in the updated Publishing page.
Other features of the assistant are that, in the local mode, a branch or tag
can be specified to pinpoint a commit, and that the test build of the crate can
be skipped with --skip-build
.
PR #501.
The metadata information about a crate/release has been reworked to simplify
user workflows and internal operation. Metadata is stored in the manifest file,
which as of this PR is always called alire.toml
and located at the root
directory of an Alire-enabled workspace. A companion lock file, alire.lock
,
stores information about the dependency solution and overrides.
These two files can be safely put under version control. The manifest, in particular, is intended to evolve with your Ada project, by being an up-to-date record of any necessary dependencies and other properties (version, project files, executables, maintainers, etc.).
The manifest internal format has been simplified by eliminating the possibility of multiple releases from its contents, which removes some nesting, and removing or making optional some fields that only make sense at the time of publishing a crate to some index. Check the [catalog-format-spec.md] file for details.
The alire
directory continues to exist, and it is used to store the source
code of dependencies, local configuration and backup files. It can be safely
ignored for VCS, as its contents are either not critical or can be
reconstructed from the manifest information.
alr with --versions
switchPR #464.
A new alr with --versions
switch is available to obtain version-focused
information of dependencies. Namely, the combined dependencies on a crate are
shown, with the release in the solution, and the last known version for the
crate:
CRATE DEPENDENCY SOLVED LATEST
a_project (root) 0.0.0 unknown
hello ^1 1.0.1 4.0.0
libhello (^1.0) & (~1.0) 1.0.1 2.0.0
superhello * 1.0.0 1.0.0
unobtanium * missing unknown
wip * /fake unknown
alr with --graph
and alr with --tree
switchesPR #465.
The ASCII art dependency graph generated with graph-easy
, that was printed at
the end of alr with --solve
output, is moved to its own alr with --graph
switch. A fallback tree visualization is generated when graph-easy
is
unavailable. This new tree visualization can also be obtained with alr with
--tree
:
my_project=0.0.0
├── hello=1.0.1 (^1)
│ └── libhello=1.0.1 (^1.0)
├── superhello=1.0.0 (*)
│ └── libhello=1.0.1 (~1.0)
├── unobtanium* (direct,missed) (*)
└── wip* (direct,linked,pin=/fake) (*)
PR #458.
When adding or removing dependency with alr with
, a list of with
statement
for each project files of the dependencies can be automatically added to the
root project file:
-- begin auto-gpr-with --
-- This section was automatically added by Alire
with "libhello.gpr";
-- end auto-gpr-with --
project Test is
...
This feature can be permanently enabled or disabled with a local or global configuration option:
alr config --global --set auto-gpr-with false
Crates with project files not compatible with this feature can disable it using
the auto-gpr-with
entry:
auto-gpr-with=false
PR #453.
The dependency solution shown with the --solve
switch now details for each
release the particular version set with which a dependency is brought into the
dependency closure. For example:
Dependencies (graph):
hello=1.0.1 --> libhello=1.0.1 (^1.0)
superhello=1.0.0 --> libhello=1.0.1 (~1.0)
PR #450.
When pinning a dependency to a directory (alr pin|with <crate> --use
), detect
if the target contains Alire metadata (as usual, in an alire
subdir). In that
case, use it to determine further dependencies and project file scopes. Also,
the target dependency name is verified.
For such a target directory, a shortcut with
command is available since the
crate name can be determined from the metadata: alr with --use
/path/to/target
(note the absence of a crate name).
PR #447.
Before this patch, any change in dependencies that resulted in an incomplete solution caused a final “invalid solution” error. Now, any incomplete solution will be presented to the user with details about the unfulfilled dependencies. This solution can be accepted and worked with normally, although the user is responsible to provide in the environment any missing project files.
This change affects all commands that compute a dependency solution, i.e.,
get
, pin
, update
, with
.
PR #439
A local path can now be used to fulfill a dependency. The path can be supplied
during initial dependency addition or afterwards during pinning, via the
--use
switch. Such a path will be added to the environment generated by alr
setenv
. Examples:
$ alr with some_crate --use /some/absolute/or/relative/path
# To simultaneously add a dependency and the directory to use for its GPR file.
# The dependency needs not to exist in the loaded indexes.
$ alr with indexed_crate
$ alr pin indexed_crate --use /path/to/gpr/containing/folder
# To pin a previously added dependency.