While modernising an old C version of Adventure, I discovered that
the Makefile
for the
BTree library was not working correctly. Running
make
always rebuilt the entire library and all test
programs even if nothing had changed. This happened on both Linux
(Debian Buster) and FreeBSD 12.1.
The Btree library (libbt.a
) is built using GNU make
default rules for archives, triggered by a dependency line of the
form:
libtbt.a: libbt.a(${OBJS})
The rule fired by the above dependency is something like:
.c.a: $(CC) -c $(CFLAGS) $< ar -rv $@ $*.o rm -f $*.o
It seems that at some point, ar
defaulted to a
deterministic build, as described in the man
page:
D Operate in deterministic mode. When adding files and the archive index use zero for UIDs, GIDs, timestamps, and use consistent file modes for all files. When this option is used, if ar is used with identical options and identical input files, multiple runs will create identical output files regardless of the input files' owners, groups, file modes, or modification times. If binutils was configured with --enable-deterministic-archives, then this mode is on by default. It can be disabled with the U modifier, below.
This is the reason that the library is being rebuilt; there are no
timestamps in the archive file. To return to the previous behaviour,
the ar
flag U
must be specified via the
ARFLAGS
macro:
ARFLAGS=rvU
By the time I figured this out, I had already re-written the rules that rebuilt the BTree library:
libbt.a: $(SRC) ${CC} -c ${CFLAGS} $? ${AR} ${ARFLAGS} $@ *.o rm -f *.o $(SRC): $(HEADERS) touch $@
This is arguable more efficient, as the C compiler and
ar
are invoked only once, irrespective of how many
source files have changed. I could also simplify the Makefile by
removing the rule that created the dependencies between objects,
sources and headers. The downside is that any header changes will
cause all the source files to be recompiled, although some are
only dependent on a subset of the header files.
Perhaps the default for make
's
ARFLAGS
should be changed to include the U
flag?
However, the GNU make team view the issue as a defect in
binutils
(which contains ar
). See this
mail in bug-make.
Only three years late to the party.