Nicolas Boulenguez wrote:
With the gnat-4.8 transition, we may consider changing the policy
-dev packages to avoid architecture-dependent contents in /usr/share/.
You may want to (re-)read Björn's idea about projects [π], the
discussion about arch-dependent sources ([√2] and same thread next
month [i]), or the wiki about multiarch in Debian [-1].
Another relevant development is that I recently published Comfignat, a
common foundation for build systems built around the GNAT tools. It
supports directories projects and specifies a set of variables that
just happen to be compatible with Fedora:
The gnat package would install a configuration project in
"/usr/share/ada/adainclude/", inheriting the target architecture at
each build, and implementing the local directory hierarchy policy.
I have no idea of the best way to inherit TARGET_ARCH, though. Ideas?
The best I could come up with was a pair of shellscript fragments
in /etc/profile.d that define an environment variable:
setenv HARDWARE_PLATFORM `uname --hardware-platform`
The directories project then picks up the environment variable as an
"external value". That works for builds started manually from an
interactive shell, although users have to use setarch instead of passing
an option such as -m32 to the compiler. I don't think it works in cron
jobs and the like, so it's not perfect, but in those cases there's
always a script or something that can set HARDWARE_PLATFORM.
When we build RPM packages the architecture is available in an RPM
macro, which we use to define HARDWARE_PLATFORM in the standard
parameters that are passed to every Gnatmake or GPRbuild invocation.
Perhaps Debian has something similar that is available when packages are
I would have preferred to have Gnatmake and GPRbuild provide the target
architecture in a variable for project files to use, but as far as I
could find out they don't provide anything like that.
In Debian I suppose you also need the kernel name to be able to figure
out the whole triplet. "uname --kernel-name" seems useful for that
In order to share library projects with at least Fedora, we should
agree on some details.
The project name must avoid collision with any user-defined project
name. The "system" and "variable" words do not carry much
in that context. Why not "installed_library_directories.gpr"?
As I wrote last year, the "library" part isn't entirely accurate. If you
think "system" is too vague, then how do you feel about
"operating_system_directories", or "os_directories" for short? Or is
"distribution_directories" better? The name should convey that this
directories project specifies directories that the distribution controls
(specifically its package manager, for distributions that have one).
Other directories projects with other names might specify directories
controlled by the user (under /home), by third-party add-ons
(under /opt), or by the system administrator (under /usr/local for
I usually try to avoid the term "operating system" because people can't
agree on what it means, but I suppose it's at least somewhat more
specific than just "system".
There are a few different use cases to consider:
Case 1: Upstream has no project file, or we need to patch their project
file. Debian and Fedora want to share a project file. This is currently
the common case.
Case 2: Upstream provides project files but has no way of configuring
them. The project files unconditionally require a directories project.
We can safely assume that there are no such upstreams yet, but they
might appear if the idea of directories projects catches on.
Case 3: Upstream has a configurable build system based on Comfignat,
Autoconf or something similar, and the build system supports directories
projects. I hope this case will become more common over time.
In Comfignat I defined a Make variable that lets the installing user
provide the name of the directories project. I had to make using a
directories project optional anyway, as I wanted Comfignat to work in
environments that don't have one, so making the name configurable wasn't
a big addition. That way users can have their own directories projects
in their home directories, and it would be possible to set up multiple
build environments in separate directories.
If an Autoconf-using upstream adds support for directories projects, it
won't be difficult to make the project name configurable there too.
To support cases 1 and 2 we need to agree on the project name. If we
decide to support only case 3, then it doesn't really matter.
Configurable build systems will work fine even if Debian and Fedora use
different names for the directories projects. I think we should try to
support all three cases though.
Either way, we need to agree on which variables a directories project
must provide. Otherwise we'll just make a big mess.
If I understand well, this project is only useful for compilation.
so, bindir and libexecdir, intended as installation destinations,
should not belong to it. Installation belongs to dpkg/rpm, not to gnat
Bindir and Libexecdir are for use in Exec_Dir in build projects – and
that's why "installed_library_directories.gpr" isn't entirely accurate.
A project file that builds some programs that are only meant to be run
by other programs might contain a line like this:
for Exec_Dir use external("DESTDIR", "") &
System_Directories.Libexecdir & "/subdir";
In Fedora Libexecdir is "/usr/libexec" and in Debian it would be
"/usr/lib", and the programs would be installed in the right place in
In case 1 above we need Libexecdir to be able to share build projects.
We can do without it if we only want to share usage projects. In case 2
Libexecdir is the only thing that can tell the upstream build project
where to install this kind of programs. Bindir might prove useful for
installing programs in /bin instead of /usr/bin, and who knows, maybe a
need for /usr/bin64 arises some day in some distribution.
If we decide to support only case 3, then we don't need Bindir and
Libexecdir. Comfignat does currently use them but I can change that.
Defining an "Archincludedir" variable would encourage
libraries to use
the same layout, at least inside a distribution.
If Debian aims at minimal changes, "/usr/lib/ARCH/ada/adainclude/NAME"
seems a natural choice.
I fail to imagine why anyone would write architecture-dependent package
specifications in Ada. It shouldn't be hard to encapsulate the
architecture-dependent bits in a package body. But if they do exist then
I suppose we need a place to put them, so I'm willing to standardize
For convenience of programmers and code browsing tools, a symbolic
link could be provided from Archincludedir/SRC to Includedir/SRC for
every arch-indep source. Gnat would not be confused because when it
finds identical file names in two directories, it only considers the
first one. I mention the idea for the record, but I dislike link
I don't much like that. I don't want to encourage people to make a
habit of looking for everything in Archincludedir. Architecture-specific
APIs *should* be inconvenient. It encourages programmers to encapsulate
the architecture-dependent bits properly and keep the API clean.
I suppose we can refrain from banning such links, but let's not make
them mandatory at least.
-- Debian version of /usr/share/ada/adainclude/installed_lib_dirs.gpr
abstract project Installed_Lib_Dirs is
for Source_Files use ();
Deb_Host_Multiarch := external ("TARGET_ARCH");
Library_Dir := "/usr/lib/" & Deb_Host_Multiarch;
Library_ALI_Dir := "/usr/lib/" & Deb_Host_Multiarch &
Arch_Dep_Source_Dir := "/usr/lib/" & Deb_Host_Multiarch &
Arch_Indep_Source_Dir := "/usr/share/ada/adainclude";
Ah, I see that we also need a variable for the ALI directory. I've just
been putting ALI files in subdirectories of Libdir, but that's OK, let's
define a separate variable for this.
I think it could be confusing to have variables with the same names as
the attributes. The difference between Installed_Lib_Dirs.Library_Dir
and Installed_Lib_Dirs'Library_Dir is very subtle. I chose to copy the
variable names from the GNU Coding Standards. Many programmers,
packagers and system administrators are familiar with them due to the
popularity of Autoconf. I still think this is a good choice, and that
new variables we define should be named in the same style. I also don't
want to change the variable names that are already in use in Fedora and
Comfignat, unless there is a very good reason.
-- Common contents for /usr/share/ada/adainclude/NAME.gpr
-- This project file is designed to help build applications that use NAME.
-- Here is an example of how to use this project file:
-- with "NAME";
-- project Example is
-- for Main use ("example.adb");
-- end Example;
library project NAME is
for Library_Name use project'Name;
for Library_Kind use "dynamic";
for Externally_Built use "true";
for Source_Dirs use
(Installed_Lib_Dirs.Arch_Indep_Source_Dir & "/" &
Installed_Lib_Dirs.Arch_Dep_Source_Dir & "/" &
for Library_ALI_Dir use Installed_Lib_Dirs.Library_ALI_Dir & "/" &
for Library_Dir use Installed_Lib_Dirs.Library_Dir;
package Linker is
for Linker_Options use ("-ldep_providing_no_importable_project");
This example shows a shared library that depends on a second library but
isn't linked to that library. Instead the first library requires that
programs and libraries that use it must link to the second library. I
suppose this is normal for static libraries, but a shared library should
normally be linked to the libraries it depends on.
I actually have a library that needs to do this. The Ada Milter API has
a thread wrapper to work around certain problems in certain versions of
Libgnat. To work reliably the thread wrapper must be statically linked
into the program so that it's present before shared libraries are
loaded, so the usage project Milter_API uses Linker_Options to make the
program link to the thread wrapper. It's a very special case, definitely
not something that a shared library should usually do.
A connected problem: in worst cases, the list of dependencies
providing no importable projects may depend on the target
architecture. As long as #717014 exists, this may happen even for Ada
An arch-indep work-around for this exact bug is to append
"-Wl,--as-needed -lbar -Wl,--no-as-needed" to linker options (or -lbar
if --as-needed is already the default). This embeds -lbar when and
only when needed on the target architecture, but not efficiently.
I mention the problem here because any better idea is welcome, and
because the work-around should be documented in policy in the
paragraph enforcing arch-indep gpr files.
In the case of a bug where a shared library uses another shared library
but isn't linked to it, that would typically be worked around in build
projects rather than usage projects. I think --as-needed is good enough
for this as long as the needed library exists even on architectures
where it isn't needed. Presumably the linker will complain if it can't
find the library.
Another solution could be to select on Hardware_Platform:
case OS_Directories.Hardware_Platform is
when "armel" | "armhf" | "ia64" | "m68k" |
"mips" | "mipsel" |
"powerpc" | "s390" | "s390x" | "sparc"
for Library_Options use ("-lm");
I specified in the Comfignat documentation that directories projects
shall define Hardware_Platform, but my intent then was that it should be
used in filenames, for example subdirectories in a build directory. For
use in case statements it's more important to coordinate the possible
values of Hardware_Platform, and I'm not sure how standardized those
architecture labels are.
To avoid the need to define all the possible architecture labels in a
type declaration, the decision could be moved from the build project to
whatever script, makefile or spec file launches the build. Define an
option in the project file:
type Boolean is ("false", "true");
Need_Libm : Boolean := external ("need_libm", "false");
case Need_Libm is
when "true" =>
for Library_Options use ("-lm");
and then pass -Xneed_libm=true to the builder on those architectures
where it's needed.
Anyway, here's my draft proposal for a specification:
A directories project is a GNAT project file that defines directory
variables for use by other project files. An operating system
distribution may include a directories project named [to be decided].gpr
which specifies the directories where programs and libraries packaged in
that distribution are installed. Users and system administrators may
write other directories projects with other names to encode local
A directories project shall define the following variables:
A short string, suitable for use in filenames, that identifies the
hardware platform (sometimes called the hardware implementation) that
is currently being compiled for. The directories project may depend
on external values to know this.
The directory for programs that can be run from a command prompt.
The top-level directory for programs that are intended to be run by
other programs rather than by users.
The directory for binary libraries to be used by other software, and
the top-level directory for other architecture-specific files.
The parent of libraries' separate library-specific directories for
Ada library information files.
The top-level directory for architecture-independent source files to
be used in the compilation of software using libraries.
The top-level directory for architecture-specific source files to be
used in the compilation of software using libraries.