从 configure.ac 中的文件读取版本号
Posted
技术标签:
【中文标题】从 configure.ac 中的文件读取版本号【英文标题】:Read a version number from a file in configure.ac 【发布时间】:2012-01-23 11:20:33 【问题描述】:出于某些原因,我在纯文本文件而不是 configure.ac 中定义了我的项目版本号。我想创建一个语句来读取版本号并在编译期间存储它。
现在我的 configure.ac 看起来像这样:
AC_INIT([my program],[999.9.9])
我想要类似的东西:
AC_INIT([my program],[ $(cat VERSION) ])
这当然行不通。这里的诀窍是什么? (我知道我失去了一些便携性 - 我现在不在乎)。谢谢!
【问题讨论】:
【参考方案1】:试试:
AC_INIT([my program], m4_esyscmd([tr -d '\n' < VERSION]))
使用 cmets 中建议的修复进行了编辑。
我还能够使用以下方法删除不可移植的 tr
调用:
AC_INIT([my program], [m4_translit(m4_esyscmd([cat VERSION]),m4_newline)])
这似乎和 Enrico 在下面的 cmets 中建议的解决方案一样有效:
AC_INIT([my program], [m4_esyscmd_s([cat VERSION])])
【讨论】:
得到了 configure.ac:5: warning: AC_INIT: not a literal: m4_esyscmd([echo 9.9| tr -d '\n']) 但它有效!谢谢。 @lzap:您可以删除m4_esyscmd(...)
周围的引号,以便在调用 AC_INIT
之前对其进行评估。这样AC_INIT
得到一个文字。为了提高效率,我还将删除cat
的调用:AC_INIT([my program], m4_esyscmd([tr -d '\n' <VERSION]))
您可以使用m4_esyscmd_s
而不是m4_esyscmd
来删除尾随换行符而不使用tr
。
这是 autoconf 本身用来动态生成自己的版本号的方法。见this mailing list post 和the source code。
此解决方案仍会为我生成警告。我正在提取一个哈希值并查看:configure.ac:3: warning: AC_INIT: not a literal: a0aabf81
【参考方案2】:
您可以简单地使用本机宏 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]))
【讨论】:
以上是关于从 configure.ac 中的文件读取版本号的主要内容,如果未能解决你的问题,请参考以下文章
autotools:将常量从 configure.ac 传递给 python 脚本
configure.ac中如何处理多个版本的Automake
更改 configure.ac 中的 PYTHON_PREFIX
Linux下使用automakeautoconf生成configure文件