One of the common criticisms of automake
is that most projects that make use of it use multiple
Makefile.am
files, one per sub-directory of
the project, causing pollution, confusion and further
problems. For quite a while, though,
automake supports non-recursive builds,
with a single Makefile.am
(or at least a
reduced number of those).
This is, actually, the best method to use with automake, since this not only covers the problems discussed in [MillerRecursiveMake] but also avoids the need for multiple convenience libraries to store the partial results.
To summarise, the advantages of non-recursive make over the recursive “classic” version are:
make knows all the dependencies of all the files, and thus only rebuilds object files when their sources (or the headers used by the sources) have changed;
the sources from the sub-directories are compiled and linked in directly in the final target, without requiring convenience libraries to be created, which spend time for the archiving or linking tasks;
as an extension, make doesn't have to serialize the calls to sub-directories, which allows for a higher number of build processes to be executable in parallel, if so requested; this is particularly important for modern multi-core systems;
the entire builds working directory is not changed, which allows for a single point of reference for relative paths;
there is a single Makefile.am
to edit,
and a single Makefile.in
to be processed
during ./configure.
The use of non-recursive automake is
actually simpler than the use of the recursive variant; instead
of creating multiple files, you just need a top-level
Makefile.am
file that references source
files with a relative path:
bin_PROGRAMS = foo foo_SOURCES = \ src/component1/component1.c \ src/component2/component2.c \ src/main.c
Even though repeating the same path prefix for each source file might seem a useless
repetition, it is a common mistake to try using a variable to hold the prefix. Indeed
automake does not expand variables in _SOURCES
definitions.
While this is likely going to be addressed in future versions of automake, at the time of writing (January 2016) no released version contains a fix for this. Even if they did, it is recommended against relying on it for maximum compatibility.
This will compile all the source files in object files directly inside the top build directory; this works fine for most cases, but it might not be desirable if either the source tree is very big (and thus a high number of files would be added to the same directory) or there are source files with the same name minus the path.
To solve this problem, you just have to ask
automake to create objects in
sub-directories, following the same structure the sources are
in. To do so, you just have to change the
AM_INIT_AUTOMAKE
call in
configure.ac
and add the option
subdir-objects
:
AM_INIT_AUTOMAKE([subdir-objects])
For most needs, this will solve the problem of non-recursive automake just fine, and no more tweaks will be needed. For more specific cases, check the following sections as well.
While the previous section has shown the use of
subdir-objects
to keep the object files in the
same structure as the source files, it has only declared the
main program to be built in the top-level build
directory. Sometimes this is not the needed behaviour.
It is certainly common to desire some organisation of the build products. For grouping together libraries, tools, examples and tests for instance and automake allows that without having to resort to the recursive variant.
Example 2.2. Grouping tests together in a non-recursive
Makefile.am
FOO_BUILT_TESTS = tests/foo_test1 tests/foo_test2 tests/foo_test3 TESTS = $(FOO_BUILT_TESTS) tests/foo_test4.sh check_PROGRAMS = $(FOO_BUILT_TESTS) tests_foo_test1_SOURCES = tests/foo_test1.c tests_foo_test1_LDADD = libfoo.la tests_foo_test2_SOURCES = tests/foo_test2.c tests_foo_test2_LDADD = libfoo.la tests_foo_test3_SOURCES = tests/foo_test3.c tests_foo_test3_LDADD = libfoo.la
In the fragment of Makefile.am
above, you
can see that the tests for the package are listed with their
relative path even in the check_PROGRAMS
variable, where the output names are used.
Further down the file, the variables used for passing sources
and libraries to the tests also use the full relative path,
replacing the /
character with the
safe value for variable names _
.
When using custom rules to generate files, there are a few problems to be considered. Rules that don't use full relative paths for targets and dependencies could be fouled up by stray files left around. Take for instance the following snippet:
pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = pkgconfig/foo.pc pkgconfig/foo-bar.pc %-bar.pc: %.pc $(LN_S) $^ $@
If a Makefile.am
is using the code above,
it would fail, creating a symbolic link that also contains the
relative path: pkgconfig/foo-bar.pc
→
pkgconfig/pkgconfig/foo.pc
.
To avoid this kind of problem, you can make use of GNU make extended functions in the rules, to transform the path from full-relative form to base form (without the path). For instance the fragment above should be replaced by the following:
pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = pkgconfig/foo.pc pkgconfig/foo-bar.pc %-bar.pc: %.pc $(LN_S) $(notdir $^) $@