Search code examples
makefilegnuautotoolsautoconfautomake

Use PACKAGE_VERSION in the argument of AC_OUTPUT()


I apologize in advance for my lack of experience with m4sh.

I have a configure.ac file containing the following lines:

AC_INIT([libhelloworld], [2.5])

...

AC_OUTPUT([
Makefile
src/helloworld-${PACKAGE_VERSION}.pc
src/Makefile
])

The reason behind the argument of AC_OUTPUT() is that I would like to avoid to copy and paste the new version of my program in multiple places on every update. Therefore I decided to exploit the PACKAGE_VERSION macro, automatically defined when invoking AC_INIT() at the beginning of configure.ac.

The line src/helloworld-${PACKAGE_VERSION}.pc then correctly expands into src/helloworld-2.5.pc and everything seems to be working fine. However I have a couple of questions.

  1. I use ${PACKAGE_VERSION} as a shell variable, but PACKAGE_VERSION itself is a m4 macro. Can I trust that this will always work? Will it always be defined as such when AC_OUTPUT() is invoked?
  2. Are there other ways of obtaining the value of PACKAGE_VERSION within configure.ac? For example, if instead of configure.ac I were inside Makefile.am I would not use the curly brackets, but the command evaluation syntax instead, as in $(PACKAGE_VERSION). What is the proper correct way of doing what I want within configure.ac?

Solution

  • The documentation for AC_INIT states that PACKAGE_VERSION is an "output variable", meaning when you call AC_INIT, something like this gets executed:

    AC_SUBST([PACKAGE_VERSION], [2.5])
    

    This allows the configuration of input files such as Makefile.in (generated from Makefile.am) to rely on @PACKAGE_VERSION@ inside those files being replaced by 2.5.

    There's nothing wrong with your approach if it works, but you might consider using AS_VAR_SET([hello_version], [AC_PACKAGE_VERSION]) to set the hello_version shell variable and src/helloworld-${hello_version}.pc in Autoconf input. This way, even if Autoconf no longer exposes a PACKAGE_VERSION shell variable in some future release, your code won't break because you'll be relying upon your own hello_version variable.


    As an aside, it's a bit irregular to use helloworld-2.5.pc when the helloworld version is 1.0 or greater (i.e. the API is stable). It's common to see helloworld.pc, except then there's the problem of what happens when you release 3.0 and replace the installed 2.x version of helloworld.pc with the 3.0 version: assuming you're using semantic versioning, 3.0 is incompatible with 2.x, and any code relying on something like pkg-config --libs helloworld will break.

    You might then consider using helloworld-2.pc instead and when you release 3.0, you'd instead have helloworld-3.pc to avoid users of your library linking the incorrect/incompatible library (and also allowing users the option of moving to the new version at their own pace); one can also apply this idea in Automake for a version-specific header directory:

    ## SOURCE PATH     => INSTALL PATH
    ## include/hello.h => $(includedir)/helloworld-2/hello.h
    helloincludedir = @includedir@/helloworld-@hello_major@
    helloinclude_HEADERS = include/hello.h
    

    Autoconf also allows you to specify an output file's inputs, so an output file src/helloworld-${hello_major}.pc in the build directory could be generated from src/helloworld.pc.in in the source directory without you needing to update the src/helloworld.pc.in filename when moving from 2.x to 3.0; this could also be used with AC_INIT if you're OK with macros, allowing you to control the version info in one central location:

    m4_define([hello_version_major], [2]) dnl
    m4_define([hello_version_minor], [5]) dnl
    m4_define([hello_version], [hello_version_major[.]hello_version_minor]) dnl
    AC_PREREQ([2.69])
    AC_INIT([libhelloworld], [hello_version])
    AS_VAR_SET([hello_major], [hello_version_major])
    AS_VAR_SET([hello_minor], [hello_version_minor])
    # For automake and configuration of pkg-config file
    AC_SUBST([hello_major])
    AC_SUBST([hello_minor])
    AC_SUBST([hello_version])
    ...
    AC_CONFIG_FILES([
        Makefile
        src/Makefile
        src/helloworld-]hello_version_major[.pc:src/helloworld.pc.in
    ])
    AC_OUTPUT
    

    I realize it looks surprisingly more complicated than one might expect, but that's Autoconf for you. Note that I had to use some odd quoting in AC_CONFIG_FILES to make use of the macro. Using

    src/helloworld-${hello_major}.pc:src/helloworld.pc.in
    

    instead of the macro resulted in a crippled config.status file being generated in Autoconf 2.69 (try config.status with no arguments, then config.status src/helloworld-2.pc to see the issue); I haven't tested any other versions. I've reported the bug, but the macro works until the next release.