Discussion:
Strategy to specify major, minor, and patch versions
2014-08-27 09:52:56 UTC
Permalink
What's the best way to set up an autoconf project so that the major,
minor and patch version numbers are made available to the entire package
(automake and source code) and used to define the VERSION and
PACKAGE_VERSION variables?


Thanks,

Eric Blake
2014-08-27 15:10:27 UTC
Permalink
Post by Zé
What's the best way to set up an autoconf project so that the major,
minor and patch version numbers are made available to the entire package
(automake and source code) and used to define the VERSION and
PACKAGE_VERSION variables?
Here's how libvirt does it:

AC_INIT([libvirt], [1.2.8], [libvir-***@redhat.com], [],
[http://libvirt.org])

# First extract pieces from the version number string
LIBVIRT_MAJOR_VERSION=`echo $VERSION | awk -F. '{print $1}'`
LIBVIRT_MINOR_VERSION=`echo $VERSION | awk -F. '{print $2}'`
LIBVIRT_MICRO_VERSION=`echo $VERSION | awk -F. '{print $3}'`
LIBVIRT_VERSION=$LIBVIRT_MAJOR_VERSION.$LIBVIRT_MINOR_VERSION.$LIBVIRT_MICRO_VERSION$LIBVIRT_MICRO_VERSION_SUFFIX
LIBVIRT_VERSION_NUMBER=`expr $LIBVIRT_MAJOR_VERSION \* 1000000 +
$LIBVIRT_MINOR_VERSION \* 1000 + $LIBVIRT_MICRO_VERSION`

AGE=`expr $LIBVIRT_MAJOR_VERSION '*' 1000 + $LIBVIRT_MINOR_VERSION`
REVISION=$LIBVIRT_MICRO_VERSION
CURRENT=`expr $LIBVIRT_SONUM + $AGE`
LIBVIRT_VERSION_INFO=$CURRENT:$REVISION:$AGE

AC_SUBST([LIBVIRT_MAJOR_VERSION])
AC_SUBST([LIBVIRT_MINOR_VERSION])
AC_SUBST([LIBVIRT_MICRO_VERSION])
AC_SUBST([LIBVIRT_SONUM])
AC_SUBST([LIBVIRT_VERSION])
AC_SUBST([LIBVIRT_VERSION_INFO])
AC_SUBST([LIBVIRT_VERSION_NUMBER])

which may be more than what you needed, but sure seems to fit the bill.

That took the 'AC_INIT is canonical, derive everything else from it'
approach. It should also be possible to do the reverse: declare m4
macros and shell variables up front for major/minor/patch, then generate
AC_INIT by calling those macros rather than open-coding the version.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
2014-08-28 08:05:26 UTC
Permalink
Post by Eric Blake
That took the 'AC_INIT is canonical, derive everything else from it'
approach.
Yeah, that approach is sub-optimal. I was thinking of a way to specify
the major/minor/patch version numbers beforehand, and then pass them off
to AC_INIT.

I tried doing that with variables but as my autoconf/m4 skills are close
to nonexisting, I failed to get anything to work properly.
Post by Eric Blake
It should also be possible to do the reverse: declare m4
macros and shell variables up front for major/minor/patch, then generate
AC_INIT by calling those macros rather than open-coding the version.
That would be preferable. Is there any way to pull that off? I've
tried with variables, but nothing behaved quite as I expected it to
behave. For example, say there these variables are declared in
configure.ac prior to calling AC_INIT:

MAJOR_VERSION = 1
MINOR_VERSION = 0
PATCH_VERSION = 0

let's say the intended outcome is to pass the version number to AC_INIT,
so that it would be equivalent to:

AC_INIT([foo], [1.0.0])


What arcane magic would be required to get this to work?


Thanks,

Eric Blake
2014-08-28 10:28:56 UTC
Permalink
Post by Zé
Post by Eric Blake
It should also be possible to do the reverse: declare m4
macros and shell variables up front for major/minor/patch, then generate
AC_INIT by calling those macros rather than open-coding the version.
That would be preferable. Is there any way to pull that off? I've
tried with variables, but nothing behaved quite as I expected it to
behave. For example, say there these variables are declared in
MAJOR_VERSION = 1
MINOR_VERSION = 0
PATCH_VERSION = 0
let's say the intended outcome is to pass the version number to AC_INIT,
AC_INIT([foo], [1.0.0])
Untested:

# M4 macros, for use during autoconf time...
m4_define([MAJOR_VERSION], [1])
m4_define([MINOR_VERSION], [0])
m4_define([PATCH_VERSION], [0])
AC_INIT([foo], MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION)

# Now reflect it for use during configure time...
m4_divert_text([DEFAULTS], [
[MAJOR_VERSION]=MAJOR_VERSION
[MINOR_VERSION]=MINOR_VERSION
[PATCH_VERSION]=PATCH_VERSION
])

But that approach will let you use the m4 macros that expand as needed
(calling AC_INIT([foo], [1.0.0]) as desired) as well as letting your
configure start with shell variables (a line such as MAJOR_VERSION=1).
Actually, picking _different_ names for the m4 macros than for the shell
variables may make use of it less confusing, particularly if you also
end up wanting to AC_DEFINE a substitution variable for use in C code.
Hope that gives you some ideas.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
2014-08-29 12:52:05 UTC
Permalink
Post by Eric Blake
# M4 macros, for use during autoconf time...
m4_define([MAJOR_VERSION], [1])
m4_define([MINOR_VERSION], [0])
m4_define([PATCH_VERSION], [0])
AC_INIT([foo], MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION)
Thanks for providing an example. It appears to have worked. I've used
it in a project with the addition of a couple of very minor tweaks.

The configure.in file starts off with this:

# Autoconf script

AC_PREREQ(2.61)

m4_define([MAJOR_VERSION], [1])
m4_define([MINOR_VERSION], [0])
m4_define([PATCH_VERSION], [0])

AC_INIT(foo,[MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION])
AM_INIT_AUTOMAKE(foo,[MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION])

# (...)

Two questiosn:

1) is there anything wrong with the way this script has been set?

2) I realize this is a very basic question, but here it goes: is there a
way to list the MAJOR_VERSION, MINOR_VERSION and PATCH_VERSION variables
in the config.h file?


Thanks,

Eric Blake
2014-08-29 13:02:43 UTC
Permalink
Post by Zé
Post by Eric Blake
# M4 macros, for use during autoconf time...
m4_define([MAJOR_VERSION], [1])
m4_define([MINOR_VERSION], [0])
m4_define([PATCH_VERSION], [0])
AC_INIT([foo], MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION)
Note that in my version, I _specifically_ used the macros unquoted.
That is, I'm calling AC_INIT([foo], 1.0.0), since unquoted macros in
arguments are expanded prior to the outer macro being called.
Post by Zé
AC_INIT(foo,[MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION])
But you are calling AC_INIT([foo],
[MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION]), with a literal string.
Those macros may be later expanded, depending on what AC_INIT expands
to, but it's harder to guarantee that you are not going to have any
situations where the macros are left unexpanded and you ended up with a
literal string name of the macro instead of its value.
Post by Zé
1) is there anything wrong with the way this script has been set?
If it worked for you, that's the ultimate test. But I would remove the
quoting, to make sure it works by design and not just by chance.
Post by Zé
2) I realize this is a very basic question, but here it goes: is there a
way to list the MAJOR_VERSION, MINOR_VERSION and PATCH_VERSION variables
in the config.h file?
anything similar to AC_DEFINE([varname], MAJOR_VERSION) should do the trick.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
2014-08-29 13:58:07 UTC
Permalink
Post by Eric Blake
Post by Zé
1) is there anything wrong with the way this script has been set?
If it worked for you, that's the ultimate test. But I would remove the
quoting, to make sure it works by design and not just by chance.
Your comments made sense, and it's always preferable that things should
work due to more than pure chance. I've removed the quotes from the script.
Post by Eric Blake
Post by Zé
2) I realize this is a very basic question, but here it goes: is there a
way to list the MAJOR_VERSION, MINOR_VERSION and PATCH_VERSION variables
in the config.h file?
anything similar to AC_DEFINE([varname], MAJOR_VERSION) should do the trick.
Is varname supposed to be a variable defined through the m4_define() macro?


Thanks,

Shawn H Corey
2014-08-29 14:01:47 UTC
Permalink
On Fri, 29 Aug 2014 13:52:05 +0100
Post by Zé
# Autoconf script
AC_PREREQ(2.61)
m4_define([MAJOR_VERSION], [1])
m4_define([MINOR_VERSION], [0])
m4_define([PATCH_VERSION], [0])
AC_INIT(foo,[MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION])
AM_INIT_AUTOMAKE(foo,[MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION])
I'm new to all this but can this be done?

m4_define([MAJOR_VERSION], [1])
m4_define([MINOR_VERSION], [0])
m4_define([PATCH_VERSION], [0])
m4_define([VERSION],[MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION])

AC_INIT(foo,[VERSION])
AM_INIT_AUTOMAKE(foo,[VERSION])
--
Don't stop where the ink does.
Shawn
Eric Blake
2014-08-29 14:18:56 UTC
Permalink
Post by Shawn H Corey
I'm new to all this but can this be done?
m4_define([MAJOR_VERSION], [1])
m4_define([MINOR_VERSION], [0])
m4_define([PATCH_VERSION], [0])
m4_define([VERSION],[MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION])
AC_INIT(foo,[VERSION])
Sure, but again, you probably want to call:

AC_INIT([foo], VERSION)

instead (quote the package name, so that it is used as a name an not an
expansion of a possible macro foo; leave VERSION unquoted so that it
expands as an m4 macro right away before being an argument to AC_INIT).
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
2014-08-29 18:55:53 UTC
Permalink
Post by Shawn H Corey
I'm new to all this but can this be done?
m4_define([MAJOR_VERSION], [1])
m4_define([MINOR_VERSION], [0])
m4_define([PATCH_VERSION], [0])
m4_define([VERSION],[MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION])
AC_INIT(foo,[VERSION])
AM_INIT_AUTOMAKE(foo,[VERSION])
That's odd. When I add the m4_define([VERSION],...) command to my
configure.in script and run make, the build process throws a bunch of
warning and error messages. The build process manages to stop due to an
error, whose error message is as follows:

configure: error: C compiler cannot create executables


After checking the output in config.log, I find this:

***@debian:build$ tail config.log
#define PACKAGE_NAME "foo"
#define PACKAGE_TARNAME "foo"
#define PACKAGE_VERSION "1.0.0"
#define PACKAGE_STRING "foo 1.0.0"
#define PACKAGE_BUGREPORT ""
#define PACKAGE_URL ""
#define PACKAGE "foo"
#define 0.0.0 "x.0.0"



So, it appears that defining the VERSION variable ends up replacing the
VERSION string in the output with the definition provided by the newly
added m4_define() line.




Shawn H Corey
2014-08-29 19:58:13 UTC
Permalink
On Fri, 29 Aug 2014 19:55:53 +0100
Post by Zé
So, it appears that defining the VERSION variable ends up replacing
the VERSION string in the output with the definition provided by the
newly added m4_define() line.
I thought there might be a conflict. Try:

m4_define([APP_MAJOR_VERSION], [1])
m4_define([APP_MINOR_VERSION], [0])
m4_define([APP_PATCH_VERSION], [0])
m4_define([APP_VERSION],[APP_MAJOR_VERSION.APP_MINOR_VERSION.APP_PATCH_VERSION])

AC_INIT(foo,[APP_VERSION])
AM_INIT_AUTOMAKE(foo,[APP_VERSION])
--
Don't stop where the ink does.
Shawn
Peter Johansson
2014-08-27 22:45:52 UTC
Permalink
Post by Zé
What's the best way to set up an autoconf project so that the major,
minor and patch version numbers are made available to the entire
package (automake and source code) and used to define the VERSION and
PACKAGE_VERSION variables?
I use this macro in my projects

http://dev.thep.lu.se/yat/svn/trunk/m4/my_version.m4

which has the following docs:

# How to use this file
# ====================
#
# Copy this file to your project, e.g. directory 'm4/'. Aclocal will
# not do that due to limitations. In 'configure.ac', include this file
# and call 'MY_VERSION_early' before 'AC_INIT'. After AC_INIT you can
# call MY_VERSION in order to AC_SUBST and AC_DEFINE variables
# FOO_MAJOR_VERSION, FOO_MINOR_VERSION etc., where FOO has been
# replaced with PACKAGE_NAME after appropriate translation (to suit a
# Make variable or PP #define):
#
# m4_include([m4/my_version.m4])
# MY_VERSION_early([3],[1],[4],[true])
# AC_INIT([foo], [my_VERSION])
# MY_VERSION

Cheers,
Peter
Bob Friesenhahn
2014-08-29 18:04:51 UTC
Permalink
All of these strategies are done in m4 and result in the configure
script being re-generated, which seems senseless and annoying to me.
I will do anything in my power to not modify what has already been
exhaustively tested just seconds before a release. The new configure
script might not even work or it may behave differently than before.

I see hardly any relationship between the configure script and the
release versioning other than that the configure script prints it for
the user and records the value.

The logic of the configure script does not depend on the version
values (they are just passed strings) so it was a design error to
require that the user edit configure.ac (or some m4 file) in order to
cut a new release.

Bob
--
Bob Friesenhahn
***@simple.dallas.tx.us, http://www.simplesystems.org/users/bfriesen/
GraphicsMagick Maintainer, http://www.GraphicsMagick.org/
Zack Weinberg
2014-08-29 20:15:46 UTC
Permalink
On Fri, Aug 29, 2014 at 2:04 PM, Bob Friesenhahn
All of these strategies are done in m4 and result in the configure script
being re-generated, which seems senseless and annoying to me.
So, I wonder, does anything break if you do it in shell instead? Just
take Shawn's strategy and make all the M4 macros into shell variables,
like this:

APP_MAJOR_VERSION=1
APP_MINOR_VERSION=0
APP_PATCH_VERSION=0

APP_VERSION=${APP_MAJOR_VERSION}.${APP_MINOR_VERSION}.${APP_PATCH_VERSION}
AC_SUBST([APP_VERSION])
AC_INIT([app], [${APP_VERSION}])
AC_CONFIG_SRCDIR([src/app.c])
AM_INIT_AUTOMAKE

(The braces and AC_SUBST increase the odds that everything will Just
Work should "${APP_VERSION}" wind up getting written verbatim into a
Makefile. I've also corrected the AM_INIT_AUTOMAKE invocation per
https://www.gnu.org/software/automake/manual/html_node/Public-Macros.html
.)

If that works, you can then take the APP_{MAJOR,MINOR,PATCH}_VERSION=
lines and split them out to their own file, let's call it VERSION.sh,
and read it from configure.ac with ". $srcdir/VERSION.sh". I *think*
$srcdir is set already at that point.

If that *doesn't* work, that is a concrete thing that we can try to
fix in Autoconf.

(Whether or not it works, perhaps this is a scenario that we should
try to make *less awkward* in Autoconf, but I think the first step
remains to find out whether that works.)
Bob Friesenhahn
2014-08-29 20:54:16 UTC
Permalink
Post by Zack Weinberg
If that works, you can then take the APP_{MAJOR,MINOR,PATCH}_VERSION=
lines and split them out to their own file, let's call it VERSION.sh,
and read it from configure.ac with ". $srcdir/VERSION.sh". I *think*
$srcdir is set already at that point.
The package I am maintaining does use a version.sh script and shell
variables but it requires using deprecated initialization interfaces.
The configure script only gets updated when there is something
configure-related which needs to be changed. Several releases can go
by without configure being updated at all.

It is really common to want to derive package versioning from the
version control system so that all files can already be committed
when the release is made and the versioning reflects what is already
in the repository.

Bob
--
Bob Friesenhahn
***@simple.dallas.tx.us, http://www.simplesystems.org/users/bfriesen/
GraphicsMagick Maintainer, http://www.GraphicsMagick.org/
Frank Lahm
2014-08-29 20:30:11 UTC
Permalink
All of these strategies are done in m4 and result in the configure script being re-generated, which seems senseless and annoying to me. I will do anything in my power to not modify what has already been exhaustively tested just seconds before a release. The new configure script might not even work or it may behave differently than before.
I see hardly any relationship between the configure script and the release versioning other than that the configure script prints it for the user and records the value.
The logic of the configure script does not depend on the version values (they are just passed strings) so it was a design error to require that the user edit configure.ac (or some m4 file) in order to cut a new release.
Fwiw, Netatalk sources a file containing the version info:

$ cat VERSION
3.1.7dev$

configure.ac:

NETATALK_VERSION=`cat $srcdir/VERSION`
AC_SUBST(NETATALK_VERSION)
AM_INIT_AUTOMAKE(netatalk, ${NETATALK_VERSION})

Cheerio!
-f
Loading...