How to use subversion revision numbers in autotools-based projects

When developers try to track down bugs, they'd better know what version precisely runs on the user's box. Back in the days of yore, projects used CVS to record the version numbers of the source files. On the up side, the cvs command-line tool would do string replacements in the source files which were commonly used to record the CVS version of each file. Therefore it was simple to design a function that returns the string that cvs inserted into the file. On the down side, this version number reflects only the version of the particular file that contained the function. But as we all know, most projects are built from several to many source files. Therefore the CVS revision number is of limited value only.

Subversion uses a different approach. On the up side, Subversion uses a repository version number to address a particular combination of file revisions at a certain point in time. This is perfect from a developers point of view, but it comes at a price: Subversion cannot do string replacements as CVS does, because a single revision of a file can be part of several revisions of the repository. The Subversion FAQ suggests to use the tool "svnversion" to generate a definition for C files or to generate a small C file containing the version number. I tried to integrate the Subversion revision into the RefDB binaries lately, but it turned out to be far more complicated than the FAQ suggested.

Using svnversion in a Makefile is straightforward, but what happens if you package the project and try to build it on a different box? If Subversion is installed, svnversion will return "exported" instead of a revision number, as it needs the housekeeping files of a Subversion working copy in order to return the revision number. This is not what we want. What happens if you try to build the project on a box that does not have Subversion installed at all? Right, the build fails. That is, the FAQ suggestion will work only for users that build straight from a Subversion working copy.

In order to get useful version informations from builds outside of a Subversion working copy, we need to record the version when the distribution was built, and use that instead of the information returned by svnversion. This needs a little preparation in configure.in:

--8<----

dnl see whether subversion is installed
AC_PATH_PROG(svnversioncommand, svnversion)

dnl use svnversion to record the current repository revision only if
dnl subversion is installed and we are in a working copy
if test "X$svnversioncommand" = "X" || test `$svnversioncommand -n '.'` = "exported"; then
mysvnversion="cat svn_dist_version"
else
mysvnversion="svnversion -n '.'"
fi

AM_CONDITIONAL(HAVESVNWC, test "X$svnversioncommand" != "X" && test `$svnversioncommand -n '.'` != "exported")

AC_SUBST(mysvnversion)

--8<----

Now we have a variable $mysvnversion which contains a command that emits a revision number. This is either set to a call to svnversion (for working copies) or to a cat command which uses a previously generated version number (we'll see how this is generated shortly).

The remaining stuff goes into src/Makefile.am. First, we follow the Subversion FAQ suggestions almost literally:

--8<----

svn_version.c: FORCE
echo -n 'const char* svn_version(void) { const char* SVN_Version = "' > svn_version.c
@mysvnversion@ >> svn_version.c
echo '"; return SVN_Version; }' >> svn_version.c

FORCE:

--8<----

The only change is that we don't call svnversion directly, but use the substituted value of $mysvnversion from configure.in. The result is a short source file which is generated whenever we run "make all" and which we can include into the _SOURCES list of each binary that needs access to the revision number. The number is generated either by svnversion or it is read from the file svn_dist_version. Let's see how this file is generated:

--8<----

if HAVESVNWC
svn_dist_version: FORCE
@mysvnversion@ > svn_dist_version
endif

--8<----

This file is also generated unconditionally whenever you run "make all". However, the conditional "HAVESVNWC" makes sure the target appears in Makefile only if we are in a Subversion working copy. There are two additional things that we need to take care of. First, we have to make sure both version files are built in time, that is before the compiler runs:

--8<----

BUILT_SOURCES=svn_version.c svn_dist_version

--8<----

Then we have to make sure the file is distributed when we run "make dist":

--8<----

EXTRA_DIST=svn_dist_version

--8<----

This should finally give the desired results: in a Subversion working copy, svnversion inserts the proper revision in both the svn_version.c and the svn_dist_version file. In a copy untarred from a release or a prerelease, the svn_dist_version file (which contains the revision when the distribution was packaged) is read, but not created, and the contents are inserted into svn_version.c. The same happens in a working copy on a box that does not have Subversion installed (although I can't imagine how you'd ever get into this situation).

Kommentare

Brian Tanner meint:

I thought you might find this interesting... another take on the same idea:

http://research.tannerpages...
Sonntag 14 September 23:26

markus meint:

Thanks for the input. I've explored the way you suggest initially, but I figured I would forget running configure after each checkin too often, so my revision numbers in the binaries would too often be incorrect. I'm sorry if the description of my method is incorrect or insufficient. I'll have to retrace my steps carefully, but http://refdb.sourceforge.net successfully uses this method.
Montag 15 September 08:20

Peter Johansson meint:

Thanks for your post.

It works fine except when building from an 'svn export'.
Dienstag 09 Dezember 23:08

markus meint:

Would you please provide some details on what happens when you use a svn export? I'd like to see if I can catch this case too.
Dienstag 09 Dezember 23:26

Peter Johansson meint:

svnversion returns 'exported' so one gets

mysvnversion="cat svn_dist_version"

but this causes problem because there is no 'svn_dist_version" in the repository, or did you mean one should check in some kind of dummy version of 'svn_dist_version'?
Freitag 12 Dezember 22:38

markus meint:

If you check out the sources of a program from a svn repository, svnversion should not return 'exported' but a revision number. Therefore the svn_dist_version file is automatically created. 'exported' usually means that you use a tarball, not a svn checkout. But then svn_dist_version is included in the tarball. Please let me know if you still manage to get 'exported' from a svn checkout, I'd like to reproduce that.
Freitag 12 Dezember 22:56

Peter Johansson meint:

Sorry, I was unclear. I am not talking about when checking out a project. In that case it works perfectly.

The problem arises when I export a problem instead (svn export), in which case svnversion returns 'exported'.
Freitag 12 Dezember 23:03

markus meint:

I see. Unless I'm mistaken, svn export mainly helps to build release packages. I use 'make dist' as provided by the autotools, so this problem never arises for me. So at this time I can only acknowledge the problem. If anyone knows a simple solution, let me know.
Freitag 12 Dezember 23:23

baol meint:

Nice work. I needed to adapt your script a little to use a VPATH (http://www.gnu.org/software...)

I modified the Makefile.am snippets adding a $(srcdir)/ in front of the file name to create the files in the correct path and all seems to work fine.

(e.g. as in '@mysvnversion@ >> $(srcdir)/svn_version.c')
Sonntag 16 Mai 15:41

baol meint:

It seems that more modifications are needed if you want VPATHs. You also need to use ${srcdir} instead of '.' in the configure.ac and some other fixes.
Dienstag 25 Mai 23:21

moncler sale meint:

I modified the Makefile.am snippets adding a $(srcdir)/ in front of the file name to create the files in the correct path and all seems to work fine.
Freitag 28 Januar 10:28

Jackman meint:

Thanks for your Website and for this Solution and this builted Subversion!I will use it after downloud!
Montag 03 Oktober 21:30

Mein Kommentar

Dieser Artikel ist geschlossen. Keine Kommentare mehr möglich.