reversed(top()) code tags rss about

Fix constant rebuilding of static libraries by GNU make

February 5, 2014
[make] [build] [static-library]

The issue explained

Say directory structure is as follows:

$ tree
.
|-- Makefile
`-- lib.cpp

0 directories, 2 files

With lib.cpp:

void libfunc()
{
}

and Makefile:

lib.a: lib.o Makefile
        $(AR) rcuvs $@ $<

The issue:

$ make
g++    -c -o lib.o lib.cpp
ar rcuvs lib.a lib.o
a - lib.o
$ make
make: `lib.a' is up to date.
$ touch Makefile
$ make
ar rcuvs lib.a lib.o
$ make
ar rcuvs lib.a lib.o
...

So there is a flaw in how ar tool operates on replacing archive members when used with make: if output file already exists, but none of input files is newer than corresponding file in the archive, modification date of the archive remains the same. As a result, make file rule is always triggered.

It happens only when ar is told to update object files. Which is done in this case using r switch and u modifier. From man ar:

r   Insert the files member... into archive (with replacement).
u   Normally, ar r... inserts all files listed into the archive.  If you
    would like to insert only those of the files you list that are newer than
    existing members of the same names, use this modifier.  The u modifier is
    allowed only for the operation r (replace).  In particular, the combination
    qu is not allowed, since checking the timestamps would lose any speed
    advantage from the operation q.

The solution (or workaround)

Add touch library.a after calling ar. Updated Makefile:

lib.a: lib.o Makefile
        $(AR) rcuvs $@ $<
        touch $@

Now output is as expected:

$ make
ar rcuvs lib.a lib.o
touch lib.a
$ make
make: `lib.a' is up to date.