This page informally completes the Debian Policy for Ada.
Links for Debian maintainers of Ada packages
Debian patches GCC so that it handles SOURCE_DATE_EPOCH, so this reproducibility issue should not be a concern anymore. See the dedicated page for details.
The dh-ada-library helper may be convenient, even if the package builds no library.
Here is a full example.
Build flags in Debian
dpkg-buildflags computes CFLAGS, CPPFLAGS and LDFLAGS from the architecture, system-wide defaults, DEB_BUILD_MAINT_OPTIONS (set by the Debian maintainer in debian/rules), and DEB_BUILD_OPTIONS (set at build time). It is usually invoked implicitly by dpkg-buildpackage or buildflags.mk.
For historical reasons, dpkg-buildpackage invokes dpkg-buildflags, then exports the computed values before running debian/rules. It is recommended that debian/rules also computes and exports them, as dpkg-buildpackage is not the only way to invoke debian/rules.
The buildflags.mk Makefile snippet serves this purpose, and ada/debian_packaging.mk adds ADAFLAGS and BUILDER_OPTIONS (GNATMAKEFLAGS and GPRBUILDFLAGS after gnat-11).
1 include /usr/share/dpkg/buildflags.mk
2 include /usr/share/dpkg/buildopts.mk
3 # Build-Depends: gnat (<= 10)
4 include /usr/share/ada/debian_packaging-$(shell gnatgcc -dumpversion)
5 # Build-Depends-Arch: gnat (<= 10)
6 gcc_version != sed -n '/^ gnat-\(.*\),$$/{s//\1/;p;q}' debian/control
7 include $(wildcard /usr/share/ada/debian_packaging-$(gcc_version))
8 # Build-Depends: gnat (>= 11)
9 include /usr/share/ada/debian_packaging.mk
10 # Build-Depends-Arch: gnat (>= 11)
11 include $(wildcard /usr/share/ada/debian_packaging.mk)
12
Suggestions for upstream maintainers
This section describes how to make an Ada build system easy to package for Debian.
The build system should support the configuration of build flags via environment variables or command-line arguments.
* ADAFLAGS should be added to the Ada compiler command line, after default arguments so that they take precedence.
* CFLAGS and CPPFLAGS should similarly affect the C compiler and preprocessor. The preprocessor is usually implicitly run by the compiler, so these variables often ends up concatened.
* A variable should similarly affect the gnatmake or gprbuild command lines. There is no convention, but GNATMAKEFLAGS and GPRBUILDFLAGS follow GNU standards.
* LDFLAGS and LDLIBS should be added respectively before and after the linker default arguments, so that options like -Wl,--as-needed work as expected.
* It should be possible to similarly change the build tool, for example when cross-building. The tradition is to name the variable after the capitalized tool.
* It should be possible to install an unstripped executable.
* For shared libraries, it should be possible to set the shared object version, that is the last part of the -Wl,-soname=libNAME.so.VERSION linker argument. There is no convention, but NAME_soversion comes to mind (or NAME_soname for the whole argument). The prefix matters because a typical link involves several libraries. When a source package builds several libraries, please allow a distinct override for each library, even if the default is common.
Even for C, it is not easy to use the default GNU Make recipes, because for example
give different results for make CFLAGS=-O0 and CFLAGS=-O0 make.
The following Makefile is configurable enough as far as Debian is affected.
1 # https://www.gnu.org/prep/standards/html_node/Command-Variables.html
2 GNATMAKE ?= gnatmake
3 GNATMAKEFLAGS ?= -v
4 ADAFLAGS ?= -g -O2
5 # CC ?= cc
6 CFLAGS ?= -g -O2
7 # CPPFLAGS ?=
8 # LDFLAGS ?=
9 # LDLIBS ?=
10 INSTALL ?= install
11 INSTALL_PROGRAM ?= $(INSTALL)
12 INSTALL_DATA ?= $(INSTALL) -m 644
13 STRIP ?= strip
14
15 # https://www.gnu.org/prep/standards/html_node/DESTDIR.html
16 # DESTDIR =
17
18 # https://www.gnu.org/prep/standards/html_node/Directory-Variables.html
19 # These path may also affect references embedded in executables
20 # (resources), documentation, pkg-config .pc files or GNAT .gpr
21 # projects (sources and libraries)...
22 prefix = /usr/local
23 exec_prefix = $(prefix)
24 bindir = $(exec_prefix)/bin
25 datarootdir = $(prefix)/share
26 mandir = $(datarootdir)/man
27
28 # Override is probable.
29 NUMJOBS != getconf _NPROCESSORS_ONLN
30
31 # Override is unexpected, these settings are either required or inoffensive.
32 executable = tool
33 ada_main_unit = ada_main_unit
34 gnatmakeflags = -eS -j$(NUMJOBS)
35 adaflags = -gnatwa -gnatwe
36 cflags = -Wall -Wextra
37 cppflags = -Ifoo/
38 ldflags = -Wl,--as-needed
39 ldlibs = ../bar/libbar.so libbaz.a -lfoo
40 c_objects = obj/c1.o obj/c2.o
41
42 all: $(c_objects) | obj
43 $(GNATMAKE) $(ada_main_unit) -aIsrc -D obj -o obj/$(executable) \
44 $(gnatmakeflags) $(GNATMAKEFLAGS) \
45 -cargs $(adaflags) $(ADAFLAGS) \
46 -largs $(ldflags) $(LDFLAGS) $(c_objects) $(ldlibs) $(LDLIBS)
47 $(c_objects): obj/%.o: src/%.c src/%.h | obj
48 $(CC) $(cflags) $(CFLAGS) $(cppflags) $(CPPFLAGS) -c -o $@ $<
49 obj/c1.o: src/c2.h
50 obj:
51 mkdir obj
52 install: all
53 $(INSTALL_PROGRAM) obj/$(executable) -Dt $(DESTDIR)$(bindir)
54 $(INSTALL_DATA) $(executable).1 -Dt $(DESTDIR)$(mandir)
55 install-strip: install
56 $(STRIP) $(DESTDIR)$(bindir)/$(executable)
57 clean:
58 rm -fr obj
59 .PHONY: all install clean
Here is an example of GNAT project.
1 package Compiler is
2 Adaflags := ("-g", "-O2");
3 case Mode is
4 when "production" => Adaflags := Adaflags & ("-gnatn");
5 when "debug" => Adaflags := Adaflags & ("-gnata");
6 end case;
7 Adaflags := Adaflags & External_As_List ("ADAFLAGS", " ");
8 for Switches ("Ada") use Adaflags;
9 for Switches ("C") use ("-g", "-O2", "-Ifoo/")
10 & External_As_List ("CFLAGS", " ")
11 & External_As_List ("CPPFLAGS", " ");
12 end Compiler;
13 package Linker is
14 for Leading_Switches ("Ada") use ("-Wl,--as-needed")
15 & External_As_List ("LDFLAGS", " ");
16 for Switches ("Ada") use ("../bar/libbar.so", "libbaz.a", "-lfoo")
17 & External_As_List ("LDLIBS", " ");
18 end Linker;
For a library project, there is no need to change the Compiler package. The object and library directoy paths should be reasonably unique for a given set of build flags. At least, PIC and non-PIC objects should be stored separately so that a static archive and a shared object may be built in a row.
1 Pic := ""; -- for now
2 Ldlibs := ("../bar/libbar.so", "libbaz.a", "-lfoo")
3 & External_As_List ("LDLIBS", " ");
4 case project'Library_Kind is
5 when "dynamic" | "relocatable" =>
6 for Library_Version use "libNAME.so."
7 & External ("NAME_soversion", "3.4");
8 for Leading_Library_Options use ("-Wl,--as-needed")
9 & External_As_List ("LDFLAGS", " ");
10 for Library_Options use Ldlibs;
11 Pic := "pic";
12 when "static" =>
13 Pic := "static";
14 when "static-pic" =>
15 Pic := "pic";
16 end case;
17 for Object_Dir use "build/obj-" & Pic & "-" & Mode;
18 for Library_Dir use "build/lib-" & Pic & "-" & Mode;
19 package Linker is
20 for Linker_Options use Ldlibs;
21 end Linker;
Scenario variables from the environment or -X options should be prefered to constructs like gprbuild -cargs $(ADAFLAGS). The interaction of -cargs with Compiler.Switches is under-documented and hardly predictable. For the same reason, the options for gprbuild itself should be set either on the command line or in a Builder package, but not both.
At least for libraries, gprinstall or install targets are usually not flexible enough for Debian and completely ignored.
The clean target should simply rm -fr the build directory. gprclean is complex, slow, and typically requires several runs with different scenario variables.
In Makefiles, please try to catch only the expected error instead of prefixing a recipe with a dash. For example, if rm -fr foo ever fails, the error is probably important and unexpected enough to stop execution.
In Makefiles, please avoid .SILENT and use the @ prefix with parcimony. Verbose logs are quite useful when debugging.