【问题标题】:Read a version number from a file in configure.ac从 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) ])

这当然行不通。这里的诀窍是什么? (我知道我失去了一些便携性 - 我现在不在乎)。谢谢!

【问题讨论】:

    标签: autoconf


    【解决方案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' &lt;VERSION]))
    • 您可以使用m4_esyscmd_s 而不是m4_esyscmd 来删除尾随换行符而不使用tr
    • 这是 autoconf 本身用来动态生成自己的版本号的方法。见this mailing list postthe source code
    • 此解决方案仍会为我生成警告。我正在提取一个哈希值并查看:configure.ac:3: warning: AC_INIT: not a literal: a0aabf81
    【解决方案2】:

    您可以简单地使用本机宏 m4_include()(而不是按照 ldav1s 的建议通过 m4_esyscmd_s() 调用 trcat),

    AC_INIT([foo], m4_normalize(m4_include([VERSION])))
    

    这也是GNU M4的官方指南suggests类似案例:

    $ cat examples/incl.m4
    ⇒Include file start
    ⇒foo
    ⇒Include file end
    

    […]

    includesinclude 扩展为 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_MAJORFOO_VERSION_MINORFOO_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_MAJORFOO_VERSION_MINORFOO_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]))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-22
      • 2014-10-22
      • 2012-10-16
      • 2011-09-08
      • 1970-01-01
      • 2020-11-02
      • 1970-01-01
      相关资源
      最近更新 更多