automake-1.16: CVS
26.1 CVS and generated files
============================
Background: distributed generated Files
---------------------------------------
Packages made with Autoconf and Automake ship with some generated files
like ‘configure’ or ‘Makefile.in’. These files were generated on the
developer’s machine and are distributed so that end-users do not have to
install the maintainer tools required to rebuild them. Other generated
files like Lex scanners, Yacc parsers, or Info documentation are usually
distributed on similar grounds.
Automake output generates rules in ‘Makefile’s to rebuild these
files. For instance, ‘make’ will run ‘autoconf’ to rebuild ‘configure’
whenever ‘configure.ac’ is changed. This makes development safer by
ensuring a ‘configure’ is never out-of-date with respect to
‘configure.ac’.
As generated files shipped in packages are up-to-date, and because
‘tar’ preserves times-tamps, these rebuild rules are not triggered when
a user unpacks and builds a package.
Background: CVS and Timestamps
------------------------------
Unless you use CVS keywords (in which case files must be updated at
commit time), CVS preserves timestamp during ‘cvs commit’ and ‘cvs
import -d’ operations.
When you check out a file using ‘cvs checkout’ its timestamp is set
to that of the revision that is being checked out.
However, during ‘cvs update’, files will have the date of the update,
not the original timestamp of this revision. This is meant to make sure
that ‘make’ notices that sources files have been updated.
This timestamp shift is troublesome when both sources and generated
files are kept under CVS. Because CVS processes files in lexical order,
‘configure.ac’ will appear newer than ‘configure’ after a ‘cvs update’
that updates both files, even if ‘configure’ was newer than
‘configure.ac’ when it was checked in. Calling ‘make’ will then trigger
a spurious rebuild of ‘configure’.
Living with CVS in Autoconfiscated Projects
-------------------------------------------
There are basically two clans amongst maintainers: those who keep all
distributed files under CVS, including generated files, and those who
keep generated files _out_ of CVS.
All Files in CVS
................
• The CVS repository contains all distributed files so you know
exactly what is distributed, and you can check out any prior
version entirely.
• Maintainers can see how generated files evolve (for instance, you
can see what happens to your ‘Makefile.in’s when you upgrade
Automake and make sure they look OK).
• Users do not need Autotools to build a check-out of the project; it
works just like a released tarball.
• If users use ‘cvs update’ to update their copy, instead of ‘cvs
checkout’ to fetch a fresh one, timestamps will be inaccurate.
Some rebuild rules will be triggered and attempt to run developer
tools such as ‘autoconf’ or ‘automake’.
Calls to such tools are all wrapped into a call to the ‘missing’
script discussed later (⇒maintainer-mode), so that the user
will see more descriptive warnings about missing or out-of-date
tools, and possible suggestions about how to obtain them, rather
than just some “command not found” error, or (worse) some obscure
message from some older version of the required tool they happen to
have installed.
Maintainers interested in keeping their package buildable from a
CVS checkout even for those users that lack maintainer-specific
tools might want to provide a helper script (or to enhance their
existing bootstrap script) to fix the timestamps after a ‘cvs
update’ or a ‘git checkout’, to prevent spurious rebuilds. In case
of a project committing the Autotools-generated files, as well as
the generated ‘.info’ files, such a script might look something
like this:
#!/bin/sh
# fix-timestamp.sh: prevents useless rebuilds after "cvs update"
sleep 1
# aclocal-generated aclocal.m4 depends on locally-installed
# '.m4' macro files, as well as on 'configure.ac'
touch aclocal.m4
sleep 1
# autoconf-generated configure depends on aclocal.m4 and on
# configure.ac
touch configure
# so does autoheader-generated config.h.in
touch config.h.in
# and all the automake-generated Makefile.in files
touch `find . -name Makefile.in -print`
# finally, the makeinfo-generated '.info' files depend on the
# corresponding '.texi' files
touch doc/*.info
• In distributed development, developers are likely to have different
versions of the maintainer tools installed. In this case rebuilds
triggered by timestamp lossage will lead to spurious changes to
generated files. There are several solutions to this:
• All developers should use the same versions, so that the
rebuilt files are identical to files in CVS. (This starts to
be difficult when each project you work on uses different
versions.)
• Or people use a script to fix the timestamp after a checkout
(the GCC folks have such a script).
• Or ‘configure.ac’ uses ‘AM_MAINTAINER_MODE’, which will
disable all of these rebuild rules by default. This is
further discussed in ⇒maintainer-mode.
• Although we focused on spurious rebuilds, the converse can also
happen. CVS’s timestamp handling can also let you think an
out-of-date file is up-to-date.
For instance, suppose a developer has modified ‘Makefile.am’ and
has rebuilt ‘Makefile.in’, and then decides to do a last-minute
change to ‘Makefile.am’ right before checking in both files
(without rebuilding ‘Makefile.in’ to account for the change).
This last change to ‘Makefile.am’ makes the copy of ‘Makefile.in’
out-of-date. Since CVS processes files alphabetically, when
another developer ‘cvs update’s his or her tree, ‘Makefile.in’ will
happen to be newer than ‘Makefile.am’. This other developer will
not see that ‘Makefile.in’ is out-of-date.
Generated Files out of CVS
..........................
One way to get CVS and ‘make’ working peacefully is to never store
generated files in CVS, i.e., do not CVS-control files that are
‘Makefile’ targets (also called _derived_ files).
This way developers are not annoyed by changes to generated files.
It does not matter if they all have different versions (assuming they
are compatible, of course). And finally, timestamps are not lost;
changes to sources files can’t be missed as in the
‘Makefile.am’/‘Makefile.in’ example discussed earlier.
The drawback is that the CVS repository is not an exact copy of what
is distributed and that users now need to install various development
tools (maybe even specific versions) before they can build a checkout.
But, after all, CVS’s job is versioning, not distribution.
Allowing developers to use different versions of their tools can also
hide bugs during distributed development. Indeed, developers will be
using (hence testing) their own generated files, instead of the
generated files that will be released. The developer who prepares the
tarball might be using a version of the tool that produces bogus output
(for instance a non-portable C file), something other developers could
have noticed if they weren’t using their own versions of this tool.
Third-party Files
-----------------
Another class of files not discussed here (because they do not cause
timestamp issues) are files that are shipped with a package, but
maintained elsewhere. For instance, tools like ‘gettextize’ and
‘autopoint’ (from Gettext) or ‘libtoolize’ (from Libtool), will install
or update files in your package.
These files, whether they are kept under CVS or not, raise similar
concerns about version mismatch between developers’ tools. The Gettext
manual has a section about this; see ⇒Integrating with Version
Control Systems (gettext)Version Control Issues.