您可以简单地使用本机宏 m4_include()(而不是按照 ldav1s 的建议通过 m4_esyscmd_s() 调用 tr 或 cat),
AC_INIT([foo], m4_normalize(m4_include([VERSION])))
这也是GNU M4的官方指南suggests类似案例:
$ cat examples/incl.m4
⇒Include file start
⇒foo
⇒Include file end
[…]
include 和 sinclude 扩展为
file 可用于定义对整个文件进行操作的宏。这里
是一个例子,它定义了‘bar’来扩展为
incl.m4:
$ m4 -I examples
define(`bar', include(`incl.m4'))
⇒
This is `bar': >>bar<<
⇒This is bar: >>Include file start
⇒foo
⇒Include file end
⇒<<
优点:
- 通过使用
m4_normalize(m4_include([VERSION])) 而不是m4_esyscmd_s([cat VERSION]),VERSION 文件被添加到Makefile 中的DIST_COMMON 变量中——这意味着VERSION 文件在用户启动时自动重新分发make dist
- 通过使用
m4_normalize(m4_include([VERSION])) 而不是m4_esyscmd_s([cat VERSION]),VERSION 文件被添加到make aclocal.m4 的先决条件中(这意味着每次修改VERSION 文件时,configure 脚本都会自动更新)
GNU M4 还提供 support for regular expressions,因此如果您想确保版本字符串始终遵循特定模式 - 或者如果 VERSION 文件包含的文本不仅仅是版本字符串– 您可以使用m4_bregexp() 找到您要查找的内容:
AC_INIT([foo], m4_bregexp(m4_quote(m4_include([VERSION])), [[0-9]+\.[0-9]+\.[0-9]+], [\&]))
这也是最安全的方法,因为如果在VERSION 文件中找不到上面的正则表达式,AC_INIT() 的第二个参数会简单地扩展为一个空字符串,并且 Autoconf 会抛出以下错误消息:
error: AC_INIT should be called with package and version arguments
调用m4_bregexp() 来处理VERSION 文件的内容很有用的典型情况是,该文件包含三个数字的版本字符串(MAJOR.MINOR.REVISION),但您只需要一个两个数字的版本字符串 (MAJOR.MINOR) 作为 AC_PACKAGE_VERSION 宏的扩展。
如果您熟悉正则表达式和捕获括号,并且希望能够完成更复杂的任务,我已经编写了这个通用的可变参数宏(您可以将其粘贴在 configure.ac 的开头),
dnl n4_define_substrings_as(string, regexp, macro0[, macro1[, ... macroN ]])
dnl ***************************************************************************
dnl
dnl Searches for the first match of `regexp` in `string` and defines custom
dnl macros accordingly
dnl
dnl For both the entire regular expression `regexp` (`\0`) and each
dnl sub-expression within capturing parentheses (`\1`, `\2`, `\3`, ... , `\N`)
dnl a macro expanding to the corresponding matching text will be created,
dnl named according to the argument `macroN` passed. If a `macroN` argument is
dnl omitted or empty, the corresponding parentheses in the regular expression
dnl will be considered as non-capturing. If `regexp` cannot be found in
dnl `string` no macro will be defined. If `regexp` can be found but some of
dnl its capturing parentheses cannot, the macro(s) corresponding to the latter
dnl will be defined as empty strings.
dnl
dnl Source: https://github.com/madmurphy/not-autotools
dnl
dnl ***************************************************************************
m4_define([n4_define_substrings_as],
[m4_bregexp([$1], [$2],
m4_ifnblank([$3],
[[m4_define(m4_normalize([$3]), [m4_quote(\&)])]])[]m4_if(m4_eval([$# > 3]), [1],
[m4_for([_idx_], [4], [$#], [1],
[m4_ifnblank(m4_quote(m4_argn(_idx_, $@)),
[[m4_define(m4_normalize(m4_argn(]_idx_[, $@)), m4_quote(\]m4_eval(_idx_[ - 3])[))]])])]))])
可以用来做:
n4_define_substrings_as(
m4_include([VERSION]),
[\([0-9]+\)\s*\.\s*\([0-9]+\)\s*\.\s*\([0-9]+\)],
[FOO_VERSION_STRING], [FOO_VERSION_MAJOR], [FOO_VERSION_MINOR], [FOO_VERSION_REVISION]
)
AC_INIT([foo], FOO_VERSION_MAJOR[.]FOO_VERSION_MINOR[.]FOO_VERSION_REVISION)
这样FOO_VERSION_MAJOR、FOO_VERSION_MINOR 和FOO_VERSION_REVISION 的宏在configure.ac 中始终可用。
注意:n4_define_substrings_as() 宏名称中的n4_ 前缀代表“Not m4sugar”。 p>
如果在VERSION 文件中找不到上面的正则表达式,n4_define_substrings_as() 安全地没有定义相应的宏名称。这允许针对这种特殊情况生成错误(必须在AC_INIT() 之后立即粘贴以下行):
m4_ifndef([FOO_VERSION_STRING], [AC_MSG_ERROR([invalid version format in `VERSION` file])])
尽管读取一个简单的VERSION 文件看起来很简单,但如果您想从package.json 文件中检索版本字符串,事情就会变得更加棘手。这里n4_define_substrings_as() 宏可以派上用场:
n4_define_substrings_as(
m4_quote(m4_include([package.json])),
["?version"?:\s*"?\s*\(\([0-9]+\)\s*\.\s*\([0-9]+\)\s*\.\s*\([0-9]+\)\)\s*"?],
[JSON_ENTRY], [FOO_VERSION_STRING], [FOO_VERSION_MAJOR], [FOO_VERSION_MINOR], [FOO_VERSION_REVISION]
)
AC_INIT([foo], FOO_VERSION_MAJOR[.]FOO_VERSION_MINOR[.]FOO_VERSION_REVISION)
n4_define_substrings_as() 宏也接受空参数,因此如果您愿意,可以将 [JSON_ENTRY] 参数替换为 [],因为您可能永远不会使用 JSON 源字符串 "version": "999.9.9"。
如果您只需要从package.json 文件中检索完整版本字符串,但不需要使用FOO_VERSION_MAJOR、FOO_VERSION_MINOR 和FOO_VERSION_REVISION,则可以去掉其中的一些捕获括号上面的正则表达式,如下例:
n4_define_substrings_as(
m4_quote(m4_include([package.json])),
["?version"?:\s*"?\s*\([0-9]+\.[0-9]+\.[0-9]+\)\s*"?],
[], [FOO_VERSION_STRING]
)
AC_INIT([foo], FOO_VERSION_STRING)
为了完整起见,由于最后一个示例只有一个字符串要捕获,因此也可以不使用n4_define_substrings_as() 将其重写为:
AC_INIT([foo],
m4_bregexp(m4_quote(m4_include([package.json])),
["?version"?:\s*"?\s*\([0-9]+\.[0-9]+\.[0-9]+\)\s*"?],
[\1]))