bug-automake
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: automake 1.7.1 dependency tracking regression?


From: Alexandre Duret-Lutz
Subject: Re: automake 1.7.1 dependency tracking regression?
Date: Mon, 02 Dec 2002 18:56:55 +0100
User-agent: Gnus/5.090008 (Oort Gnus v0.08) Emacs/20.7 (i386-debian-linux-gnu)

>>> "David" == David Relson <address@hidden> writes:

 David> Alexandre,
 David> The proposed documentation is well written and easy to understand.
 David> The content is excellent.  I have a few corrections and suggestions.

Thank you.  Here is the documentation I'm checking in.  It will
be in Automake 1.7.2 (due soon).

I've moved the "generate bindir.h from configure" idea at the
begining of the Example, not before, because I think it's
specific to this example (How to #define bindir is an Autoconf
FAQ) and not appliable to all $(BUILT_SOURCES) uses.

Built sources
=============

   Occasionally a file which would normally be called `source' (e.g. a
C `.h' file) is actually derived from some other file.  Such files
should be listed in the `BUILT_SOURCES' variable.

   `BUILT_SOURCES' is actually a bit of a misnomer, as any file which
must be created early in the build process can be listed in this
variable.

   A source file listed in `BUILT_SOURCES' is created on `make all' or
`make check' before other targets are made.  However, such a source
file is not compiled unless explicitly requested by mentioning it in
some other `_SOURCES' variable.

   So, for instance, if you had header files which were created by a
script run at build time, then you would list these headers in
`BUILT_SOURCES', to ensure that they would be built before any other
compilations (perhaps ones using these headers) were started.

Example
-------

   Here is an example.  Suppose that `foo.c' includes `bindir.h', which
is built on demand and not distributed.  Here `bindir.h' defines the
preprocessor macro `bindir' to the value of the `make' variable
`bindir' (inherited from `configure') as follows.

     bindir.h:
             echo '#define bindir "$(bindir)"' >$@

   It would be possible to define this preprocessor macro from
`configure', either in `config.h' (*note Defining Directories:
(autoconf)Defining Directories.), or by processing a `bindir.h.in' file
using `AC_CONFIG_FILES' (*note Configuration Actions:
(autoconf)Configuration Actions.).  It's even safer because you won't
have to play the dirty tricks discussed below.  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...).
So let's ignore this possibility and discuss the implication of
building `bindir.h' at `make' time.

   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:
             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 (*note Dependencies::).  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

   A solution is to require `bindir.h' to be built before anything
else.  This is what `BUILT_SOURCES' is meant for.

     bin_PROGRAMS = foo
     foo_SOURCES = foo.c
     BUILT_SOURCES = bindir.h
     CLEANFILES = bindir.h
     bindir.h:
             echo '#define bindir "$(bindir)"' >$@

   See how `bindir.h' get 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' and `check' 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 core *.core
     % : > .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

   Usually people are happy enough with `$(BUILT_SOURCES)' because they
never run such targets before `make all'.  However if this matters to
you, you can record such dependencies explicitly in the `Makefile.am'.

     bin_PROGRAMS = foo
     foo_SOURCES = foo.c
     foo.$(OBJEXT): bindir.h
     CLEANFILES = bindir.h
     bindir.h:
             echo '#define bindir "$(bindir)"' >$@

   You don't have to list _all_ the dependencies of `foo.o' explicitly,
only those which 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.am' if you do this.

   It should be clearer now why building `bindir.h' from `configure' is
seducing for this example: `bindir.h' will exist before you build any
target, hence will not cause any dependency issue.
-- 
Alexandre Duret-Lutz





reply via email to

[Prev in Thread] Current Thread [Next in Thread]