[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
9.4.1 Built Sources Example
Suppose that ‘foo.c’ includes ‘bindir.h’, which is
installation-dependent and not distributed: it needs to be built. Here
‘bindir.h’ defines the preprocessor macro bindir
to the
value of the make
variable bindir
(inherited from
‘configure’).
We suggest several implementations below. It's not meant to be an exhaustive listing of all ways to handle built sources, but it will give you a few ideas if you encounter this issue.
First Try
This first implementation will illustrate the bootstrap issue mentioned in the previous section (see section Built Sources).
Here is a tentative ‘Makefile.am’.
# This won't work. bin_PROGRAMS = foo foo_SOURCES = foo.c nodist_foo_SOURCES = bindir.h CLEANFILES = bindir.h bindir.h: Makefile echo '#define bindir "$(bindir)"' >$@ |
This setup doesn't work, because Automake doesn't know that ‘foo.c’ includes ‘bindir.h’. Remember, automatic dependency tracking works as a side-effect of compilation, so the dependencies of ‘foo.o’ will be known only after ‘foo.o’ has been compiled (see section Automatic dependency tracking). The symptom is as follows.
% make source='foo.c' object='foo.o' libtool=no \ depfile='.deps/foo.Po' tmpdepfile='.deps/foo.TPo' \ depmode=gcc /bin/sh ./depcomp \ gcc -I. -I. -g -O2 -c `test -f 'foo.c' || echo './'`foo.c foo.c:2: bindir.h: No such file or directory make: *** [foo.o] Error 1 |
In this example ‘bindir.h’ is not distributed nor installed, and
it is not even being built on-time. One may wonder if the
‘nodist_foo_SOURCES = bindir.h’ line has any use at all. This
line simply states that ‘bindir.h’ is a source of foo
, so
for instance, it should be inspected while generating tags
(see section Interfacing to etags
). In other words, it does not help our present problem,
and the build would fail identically without it.
Using BUILT_SOURCES
A solution is to require ‘bindir.h’ to be built before anything
else. This is what BUILT_SOURCES
is meant for (see section Built Sources).
bin_PROGRAMS = foo foo_SOURCES = foo.c nodist_foo_SOURCES = bindir.h BUILT_SOURCES = bindir.h CLEANFILES = bindir.h bindir.h: Makefile echo '#define bindir "$(bindir)"' >$@ |
See how ‘bindir.h’ gets built first:
% make echo '#define bindir "/usr/local/bin"' >bindir.h make all-am make[1]: Entering directory `/home/adl/tmp' source='foo.c' object='foo.o' libtool=no \ depfile='.deps/foo.Po' tmpdepfile='.deps/foo.TPo' \ depmode=gcc /bin/sh ./depcomp \ gcc -I. -I. -g -O2 -c `test -f 'foo.c' || echo './'`foo.c gcc -g -O2 -o foo foo.o make[1]: Leaving directory `/home/adl/tmp' |
However, as said earlier, BUILT_SOURCES
applies only to the
all
, check
, and install
targets. It still fails
if you try to run ‘make foo’ explicitly:
% make clean test -z "bindir.h" || rm -f bindir.h test -z "foo" || rm -f foo rm -f *.o % : > .deps/foo.Po # Suppress previously recorded dependencies % make foo source='foo.c' object='foo.o' libtool=no \ depfile='.deps/foo.Po' tmpdepfile='.deps/foo.TPo' \ depmode=gcc /bin/sh ./depcomp \ gcc -I. -I. -g -O2 -c `test -f 'foo.c' || echo './'`foo.c foo.c:2: bindir.h: No such file or directory make: *** [foo.o] Error 1 |
Recording Dependencies manually
Usually people are happy enough with BUILT_SOURCES
because they
never build targets such as ‘make foo’ before ‘make all’, as
in the previous example. However if this matters to you, you can
avoid BUILT_SOURCES
and record such dependencies explicitly in
the ‘Makefile.am’.
bin_PROGRAMS = foo foo_SOURCES = foo.c nodist_foo_SOURCES = bindir.h foo.$(OBJEXT): bindir.h CLEANFILES = bindir.h bindir.h: Makefile echo '#define bindir "$(bindir)"' >$@ |
You don't have to list all the dependencies of ‘foo.o’ explicitly, only those that might need to be built. If a dependency already exists, it will not hinder the first compilation and will be recorded by the normal dependency tracking code. (Note that after this first compilation the dependency tracking code will also have recorded the dependency between ‘foo.o’ and ‘bindir.h’; so our explicit dependency is really useful to the first build only.)
Adding explicit dependencies like this can be a bit dangerous if you are not careful enough. This is due to the way Automake tries not to overwrite your rules (it assumes you know better than it). ‘foo.$(OBJEXT): bindir.h’ supersedes any rule Automake may want to output to build ‘foo.$(OBJEXT)’. It happens to work in this case because Automake doesn't have to output any ‘foo.$(OBJEXT):’ target: it relies on a suffix rule instead (i.e., ‘.c.$(OBJEXT):’). Always check the generated ‘Makefile.in’ if you do this.
Build ‘bindir.h’ from ‘configure’
It's possible to define this preprocessor macro from ‘configure’,
either in ‘config.h’ (see (autoconf)Defining Directories section `Defining Directories' in The Autoconf Manual), or by processing a
‘bindir.h.in’ file using AC_CONFIG_FILES
(see (autoconf)Configuration Actions section `Configuration Actions' in The Autoconf Manual).
At this point it should be clear that building ‘bindir.h’ from ‘configure’ works well for this example. ‘bindir.h’ will exist before you build any target, hence will not cause any dependency issue.
The Makefile can be shrunk as follows. We do not even have to mention ‘bindir.h’.
bin_PROGRAMS = foo foo_SOURCES = foo.c |
However, it's not always possible to build sources from ‘configure’, especially when these sources are generated by a tool that needs to be built first.
Build ‘bindir.c’, not ‘bindir.h’.
Another attractive idea is to define bindir
as a variable or
function exported from ‘bindir.o’, and build ‘bindir.c’
instead of ‘bindir.h’.
noinst_PROGRAMS = foo foo_SOURCES = foo.c bindir.h nodist_foo_SOURCES = bindir.c CLEANFILES = bindir.c bindir.c: Makefile echo 'const char bindir[] = "$(bindir)";' >$@ |
‘bindir.h’ contains just the variable's declaration and doesn't need to be built, so it won't cause any trouble. ‘bindir.o’ is always dependent on ‘bindir.c’, so ‘bindir.c’ will get built first.
Which is best?
There is no panacea, of course. Each solution has its merits and drawbacks.
You cannot use BUILT_SOURCES
if the ability to run ‘make
foo’ on a clean tree is important to you.
You won't add explicit dependencies if you are leery of overriding an Automake rule by mistake.
Building files from ‘./configure’ is not always possible, neither is converting ‘.h’ files into ‘.c’ files.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |