reversed(top()) code tags rss about

How to recompile source file on each build using make

January 18, 2014
[make] [build] [programming]

Motivation

It’s sometimes useful to see precise date and time an application was compiled. So such information should be embedded into application at compile time and displayed on user’s request.

Initial solution

Usage of such timestamps is quite straightforward. There are two standard macros that are generally used for this, namely __DATE__ and __TIME__ (see Standard Predefined Macros). As first try I just wrote the following piece of code:

list[x++] = strdup("Compiled at: " __DATE__ " " __TIME__);

It displayed message of this form:

Compiled at: Jan 18 2014 14:07:23

The issue is that when the file with this code (version.c) is not compiled output of an application never changes (quite obvious…). So that simple code isn’t enough and build process should satisfy a couple of requirements:

  1. version.c should be recompiled if any other file is compiled.
  2. version.c should be recompiled if application is relinked.
  3. version.c should not be recompiled if application is not relinked.

Working solution

Adding various fake targets into Makefile.am didn’t work out great. Search on the Web didn’t get much good results, but eventually this post on one of mailing lists helped to do the thing correctly. Here’s a quote from it:

One way which should work with any make is to have the object in
question depend on all source files even though the action only refers to
one of them.

In a Makefile.am it looks like this:

version.o: $(filter-out version.o, $(app_OBJECTS))

Note filtering out version.o from its list of dependencies to avoid creating of circular dependency, in which case make prints warning about dropped circular dependency.

And here is how it satisfies requirements outlined above. The first requirement holds as recompilation of any of object files will update modification date of appropriate .o-file, thus triggering version.o compilation rule.

The second requirement also holds simply because list of dependencies for the link target is almost the same as for version.o target (it additionally includes version.o). Thanks to topological sorting make will recompile version.o before linking the application, which is what we need.

Finally, the third requirement works for the same reason as the second one. When all files (including output executable) are up to date, none of version.o prerequisites is newer it, hence version.o not recompiled, no need to relink anything.