summaryrefslogtreecommitdiff
path: root/m4/init-package-version.m4
blob: 853b6fb794afdbb46034fdd78c3ae026a46b13b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# init-package-version.m4
# serial 3
dnl Copyright (C) 1992-2024 Free Software Foundation, Inc.
dnl This file is free software, distributed under the terms of the GNU
dnl General Public License.  As a special exception to the GNU General
dnl Public License, this file may be distributed as part of a program
dnl that contains a configuration script generated by Autoconf, under
dnl the same distribution terms as the rest of that program.

# Make it possible to pass version numbers extracted from a file in
# $(srcdir) to autoconf.
#
# Autoconf insists on passing the package name and version number to
# every generated .h file and every Makefile. This was a reasonable
# design at times when a version number was changed only once a month.
# Nowadays, people often assign a new version number once a week, or
# even change it each time a 'git' commit is made. Regenerating all
# the files that depend on configure.ac (aclocal.m4, configure,
# config.status, config.h, all Makefiles) may take 15 minutes. These
# delays can severely hamper development.
#
# An alternative is to store the version number in a file in $(srcdir)
# that is separate from configure.ac. It can be a data file, a shell
# script, a .m4 file, or other. The essential point is that the maintainer
# is responsible for creating Makefile dependencies to this version file
# for every file that needs to be rebuilt when the version changes. This
# typically includes
#   - distributable documentation files that carry the version number,
# but does not include
#   - aclocal.m4, configure, config.status, config.h, all Makefiles,
#   - executables.
#
# autoconf and automake make it hard to follow this approach:
#
# - If AC_INIT is used with arguments, there is a chicken-and-egg problem:
#   The arguments need to be read from a file in $(srcdir). The location
#   of $(srcdir) is only determined by AC_CONFIG_SRCDIR. AC_CONFIG_SRCDIR
#   can only appear after AC_INIT (otherwise aclocal gives an error:
#   "error: m4_defn: undefined macro: _m4_divert_diversion").
#   Furthermore, the arguments passed to AC_INIT must be literals; for
#   example, the assignment to PACKAGE_VERSION looks like this:
#     [PACKAGE_VERSION=']AC_PACKAGE_VERSION[']
#
# - If AC_INIT is used without arguments:
#   Automake provides its own variables, PACKAGE and VERSION, and uses them
#   instead of PACKAGE_NAME and PACKAGE_VERSION that come from Autoconf.
#   - If AM_INIT_AUTOMAKE is used with two arguments, automake options
#     like 'silent-rules' cannot be specified.
#   - If AM_INIT_AUTOMAKE is used in its one-argument form or without
#     arguments at all, it triggers an error
#     "error: AC_INIT should be called with package and version arguments".
#   - If AM_INIT_AUTOMAKE is used in its one-argument form or without
#     arguments at all, and _AC_INIT_PACKAGE is used before it, with
#     the package and version number from the file as arguments, we get
#     a warning: "warning: AC_INIT: not a literal: $VERSION_NUMBER".
#     The arguments passed to _AC_INIT_PACKAGE must be literals.
#
# With the macro defined in this file, the approach can be coded like this:
#
#   AC_INIT
#   AC_CONFIG_SRCDIR(WITNESS)
#   . $srcdir/../version.sh
#   gl_INIT_PACKAGE(PACKAGE, $VERSION_NUMBER)
#   AM_INIT_AUTOMAKE([OPTIONS])
#
# and after changing version.sh, the developer can directly configure and build:
#
#   make distclean
#   ./configure
#   make
#
# Some other packages use another approach:
#
#   AC_INIT(PACKAGE,
#           m4_normalize(m4_esyscmd([. ./version.sh; echo $VERSION_NUMBER])))
#   AC_CONFIG_SRCDIR(WITNESS)
#   AM_INIT_AUTOMAKE([OPTIONS])
#
# but here, after changing version.sh, the developer must first regenerate the
# configure file:
#
#   make distclean
#   ./autogen.sh --skip-gnulib
#   ./configure
#   make
#

# gl_INIT_PACKAGE(PACKAGE-NAME, VERSION)
# --------------------------------------
# followed by an AM_INIT_AUTOMAKE invocation,
# is like calling AM_INIT_AUTOMAKE(PACKAGE-NAME, VERSION)
# except that it can use computed non-literal arguments.
AC_DEFUN([gl_INIT_PACKAGE],
[
  AC_BEFORE([$0], [AM_INIT_AUTOMAKE])
  dnl Redefine AM_INIT_AUTOMAKE.
  m4_define([gl_AM_INIT_AUTOMAKE],
    m4_bpatsubst(m4_dquote(
        m4_bpatsubst(m4_dquote(
            m4_bpatsubst(m4_dquote(
                m4_defn([AM_INIT_AUTOMAKE])),
              [AC_PACKAGE_NAME], [gl_INIT_DUMMY])),
          [AC_PACKAGE_TARNAME], [gl_INIT_EMPTY])),
      [AC_PACKAGE_VERSION], [gl_INIT_DUMMY])
    [AC_SUBST([PACKAGE], [$1])
     AC_SUBST([VERSION], [$2])
    ])
  m4_define([AM_INIT_AUTOMAKE],
    m4_defn([gl_RPL_INIT_AUTOMAKE]))
])
m4_define([gl_INIT_EMPTY], [])
dnl Automake 1.16.4 no longer accepts an empty value for gl_INIT_DUMMY.
dnl But a macro that later expands to empty works.
m4_define([gl_INIT_DUMMY], [gl_INIT_DUMMY2])
m4_define([gl_INIT_DUMMY2], [])
AC_DEFUN([gl_RPL_INIT_AUTOMAKE], [
  m4_ifval([$2],
    [m4_fatal([After gl_INIT_PACKAGE, the two-argument form of AM_INIT_AUTOMAKE cannot be used.])])
  gl_AM_INIT_AUTOMAKE([$1 no-define])
  m4_if(m4_index([ $1 ], [ no-define ]), [-1],
    [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
     AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])
    ])
])