6

I'd like to create a Makefile.am file which generates one header file mentioned in a xxx.c file.

Let's say that xxx.c contains:

#include <version.h>
...

and that I have a rule to create it at the end of Makefile.am:

version.h:
       echo '#define VERSION "'`hg id`'"' > version.h.tmp
       cmp version.h.tmp version.h || mv version.h.tmp version.h

What do I have to change to make the xxx.c compilation depend on version.h? I tried nodist_progname_SOURCES=version.h, but that doesn't seem to do it.

viraptor
  • 33,322
  • 10
  • 107
  • 191

1 Answers1

11
BUILT_SOURCES = version.h

All files mentioned as BUILT_SOURCES will be built before any of the normal compilation rules run.

However, this will create a slight problem: As version.h will need to be rebuilt on every make invocation, the recompilation of every foo.c file which #includes version.h will be triggered again on every make run. We would prefer if the recompilation only happens when there is actually something that has changed.

To get around this problem, use a BUILT_SOURCES dependency on a stamp file which is "created" every time (it never is actually created, so the build rule runs every time). The build rule for that stamp file creates a new version.h file as version.h.tmp, and only copies version.h.tmp to version.h if version.h.tmp is actually different from version.h (just like your version.h rule does). So if nothing has changed in version.h, its timestamp (mtime) remains the same, and no build of objects depending on version.h is triggered:

BUILT_SOURCES = version.stamp

version.stamp:
        echo '#define VERSION "'`hg id`'"' > version.h.tmp
        cmp version.h.tmp version.h || mv version.h.tmp version.h

This solution will do what you are asking for.

Unfortunately though, there will be a slight problem when you are building from a dist tarball: Then hg id will give you bogus information, and there probably is no version.h in your tarball, so the build will fail or contain bogus version information.

I have solved this issue for a the xf86-video-radeonhd project which is using git. The git-version.h file generated in this solution contains some more version information than just a single version number. You can see this update-only-if-different solution of mine at the end of git_version.sh and the BUILT_SOURCES hookup (including handling of hopefully all out-of-source-tree and from-dist-tarball build cases) in RadeonHD.am if you are interested.

ndim
  • 35,870
  • 12
  • 47
  • 57
  • This works great, with one qualification. From the automake manual: "It might be important to emphasize that BUILT_SOURCES is honored only by ‘make all’, ‘make check’ and ‘make install’. This means you cannot build a specific target (e.g., ‘make foo’) in a clean tree if it depends on a built source." Still, it's the best solution I know of. – phs Dec 07 '12 at 07:17
  • I guess if someone knows to specifically run `make foo`, you can reasonably assume some knowledge of what they are building, and thus whether they need to make sure manually that the BUILT_SOURCES are rebuilt. – ndim Dec 10 '12 at 14:02
  • You have to put these into a single line via the ``&&`` operator, otherwise make will be happy to parallelize your version.h construction. – Jan Kundrát Sep 18 '13 at 10:54
  • @JanKundrát No. `make` only runs complete *recipes* for targets in _parallel_. The shell *commands* within a single target recipe are run _sequentially_. – ndim Sep 18 '13 at 12:13
  • Interesting -- when I tried to prepare a patch for Ragel http://repo.or.cz/w/ragel-jkt.git/commitdiff/a980ec473ee66ecb6dd3cc972819c33da8d1a8d7, the parallel build was broken when I did not use a single command. However, I cannot rule out some stupid mistake like using the ``>>`` redirection even on the first line. You must be right -- it wouldn't make any sense if the individual commands were run in parallel by default. – Jan Kundrát Sep 26 '13 at 09:28