Прочитать номер версии из файла в файле configure.ac

Я определяю номер своей версии проекта в текстовом файле вместо configure.ac по некоторым причинам. Я хотел бы создать инструкцию, которая будет читать номер версии и хранить ее во время компиляции.

Теперь мой configure.ac выглядит так:

AC_INIT([my program],[999.9.9])

Я хотел бы иметь что-то вроде:

AC_INIT([my program],[ $(cat VERSION) ])

Конечно, эта работа не будет. Что это за трюк? (Я знаю, что теряю некоторую мобильность - на данный момент меня это не волнует). Спасибо!

Ответ 1

Try:

AC_INIT([my program], m4_esyscmd([tr -d '\n' < VERSION]))

Отредактировано исправлениями, предложенными в комментариях.

Мне также удалось удалить непереносимый вызов tr, используя:

AC_INIT([my program], [m4_translit(m4_esyscmd([cat VERSION]),m4_newline)])

который, похоже, работает так же хорошо, как и решение, предложенное Enrico в комментариях ниже:

AC_INIT([my program], [m4_esyscmd_s([cat VERSION])])

Ответ 2

Вы можете просто использовать собственный макрос m4_include() (вместо того, чтобы m4_esyscmd_s() tr или cat через m4_esyscmd_s() как предложено ldav1s),

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

это также то, что официальное руководство GNU M4 предлагает для подобных случаев:

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

[...]

Тот факт, что include и sinclude расширяют содержимое файла, может использоваться для определения макросов, которые оперируют целыми файлами. Вот пример, который определяет ' 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
⇒<<

GNU M4 также предлагает поддержку регулярных выражений, поэтому, если вы хотите убедиться, что строка версии всегда следует определенному шаблону - или если файл VERSION содержит больше текста, чем просто строка версии - вы можете использовать m4_bregexp() чтобы найти то, что вы ищем:

AC_INIT([foo], m4_bregexp(m4_include([VERSION]), [[0-9]+\.[0-9]+\.[0-9]+], [\&]))

Это также самый безопасный подход, поскольку если регулярное выражение выше не может быть найдено в файле VERSION второй аргумент AC_INIT() просто раскрывается в пустую строку, и Autoconf AC_INIT() следующее сообщение об ошибке:

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  NA_DEFINE_SUBSTRINGS_AS(string, regexp, macro0[, macro1[, ... macroN ]])
dnl  ***************************************************************************
dnl
dnl  Searches for the first match of 'regexp' in 'string'. For both the entire
dnl  regular expression 'regexp' ('\0') and each sub-expression within capturing
dnl  parentheses ('\1', '\2', '\3', ... , '\N') a macro expanding to the
dnl  corresponding matching text will be created, named according to the
dnl  argument 'macroN' passed. If a 'macroN' argument is omitted or empty, the
dnl  corresponding parentheses in the regular expression will be considered as
dnl  non-capturing. If 'regexp' cannot be found in 'string' no macro will be
dnl  defined. If 'regexp' can be found but some of its capturing parentheses
dnl  cannot, the macro(s) corresponding to the latter will be defined as empty
dnl  strings.
dnl
dnl  Source: https://github.com/madmurphy/not-autotools
dnl
dnl  ***************************************************************************
AC_DEFUN([NA_DEFINE_SUBSTRINGS_AS], [
    m4_if(m4_eval([$# > 2]), [1], [
        m4_if(m4_normalize(m4_argn([$#], $*)), [], [],
            [m4_bregexp([$1], [$2], [m4_define(m4_normalize(m4_argn([$#], $*)), \]m4_if([$#], [3], [&], m4_eval([$# - 3]))[)])])
        m4_if(m4_eval([$# > 3]), [1], [NA_DEFINE_SUBSTRINGS_AS(m4_reverse(m4_shift(m4_reverse([email protected]))))])
    ])
])

который можно использовать для выполнения:

NA_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.

Примечание. Префикс NA_ в NA_DEFINE_SUBSTRINGS_AS() макроса NA_DEFINE_SUBSTRINGS_AS() означает " N o A utotools".

Если регулярное выражение выше не может быть найдено в файле VERSION, NA_DEFINE_SUBSTRINGS_AS() безопасно не определяет соответствующие имена макросов. Это позволяет генерировать ошибку для данного конкретного случая (следующая строка должна быть вставлена сразу после AC_INIT()):

m4_ifndef([FOO_VERSION_STRING], [AC_MSG_ERROR([invalid version format in 'VERSION' file])])

Поскольку чтение простого файла VERSION может показаться тривиальным, все становится сложнее, если вы хотите извлечь строку версии из файла package.json. Здесь NA_DEFINE_SUBSTRINGS_AS() может очень пригодиться:

NA_DEFINE_SUBSTRINGS_AS(

    m4_join([|], m4_unquote(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)

Примечание. Файлы .json могут содержать запятые и квадратные скобки (которые не очень .json для GNU m4-ish), и их необходимо удалить/заменить перед обработкой строки JSON. В приведенном выше коде макрос m4_unquote() удаляет все квадратные скобки первого уровня, которые могут присутствовать в package.json - если последний содержит вложенные массивы, m4_unquote() должна вызываться сама столько раз, сколько достигает максимальный уровень вложенности массива - тогда макрос m4_join() заменяет все запятые на '|' ,

NA_DEFINE_SUBSTRINGS_AS() принимает также пустые аргументы, поэтому, если вы предпочитаете, вы можете заменить аргумент [JSON_ENTRY] на [], поскольку, вероятно, вы никогда не будете использовать исходную строку JSON "version": "999.9.9".

Если вам нужно только получить полную строку версии из файла package.json но вам не нужно использовать FOO_VERSION_MAJOR, FOO_VERSION_MINOR и FOO_VERSION_REVISION, вы можете избавиться от некоторых скобок в регулярном выражении, описанном выше, как FOO_VERSION_REVISION ниже пример:

NA_DEFINE_SUBSTRINGS_AS(

    m4_join([|], m4_unquote(m4_include([package.json]))),

    ["?version"?:\s*"?\s*\([0-9]+\.[0-9]+\.[0-9]+\)\s*"?],

    [], [FOO_VERSION_STRING]

)

AC_INIT([foo], FOO_VERSION_STRING)

Для полноты, поскольку в последнем примере есть только одна строка для захвата, ее также можно переписать без использования NA_DEFINE_SUBSTRINGS_AS() как:

AC_INIT([foo], m4_bregexp(m4_join([|], m4_unquote(m4_include([package.json]))), ["?version"?:\s*"?\s*\([0-9]+\.[0-9]+\.[0-9]+\)\s*"?], [\1]))