autotools - 如何在常见的 Autoconf 宏中包含宏?
问题描述
TL;博士
- 为什么要
AC_DEFUN
尝试扩展AC_PROG_CC
? - 为什么定义的宏
m4_define
似乎没有扩展? - 为什么定义
configure.ac
的宏与另一个文件中定义并包含的宏的行为不同?
背景
我负责为大约六个不同的板子构建固件和库,这些板子都使用相同的嵌入式处理器。由于所有板卡都使用相同的处理器,因此存在重要的通用配置(CC
、CXX
、CPPFLAGS
、CFLAGS
、CXXFLAGS
、LDFLAGS
等)和配方。对于固件,我使用自定义生成文件,其中包含一个通用配置文件,该文件定义了所有通用配置和配方。为了简化在开发人员的计算机上安装库和头文件,我使用 GNU Autotools 来安装库。但是,自定义 makefile 和 GNU Autotools 文件之间存在大量重复配置,因此我将固件迁移到 GNU Autotools。
客观的
我希望尽可能少的样板。板的 Aconfigure.ac
可能如下所示:
AC_INIT([mppt], [0.1.0])
AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Werror])
: ${CC='arm-none-eabi-gcc -specs=nosys.specs'}
AC_PROG_CC
AM_PROG_CC_C_O
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
库的 Aconfigure.ac
可能如下所示:
AC_INIT([gcc-arm-none-eabi-samples], [4.7+])
AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Werror])
: ${CXX='arm-none-eabi-g++ -specs=nosys.specs'}
AC_PROG_CXX
: ${CC='arm-none-eabi-gcc -specs=nosys.specs'}
AM_PROG_AS
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
AC_PROG_RANLIB
AC_PROG_CXX_C_O
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
这些文件之间有很多共同的配置。我想在本地include
目录中有一个文件,该文件定义了一个带有常见 Autoconf 宏的宏:
AC_DEFUN([TIVASDK],
[AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Werror])
: ${CC='arm-none-eabi-gcc -specs=nosys.specs'}
AC_PROG_CC
: ${CXX='arm-none-eabi-g++ -specs=nosys.specs'}
AC_PROG_CXX
AM_PROG_AS
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
AC_PROG_RANLIB
AM_PROG_CC_C_O
AC_PROG_CXX_C_O
AC_CONFIG_FILES([Makefile])])
然后,我希望能够将第一个示例简化为以下内容:
AC_INIT([mppt], [0.1.0])
TIVASDK
AC_OUTPUT
除了简单之外,这还有许多优点。例如,如果 MPPT 开发人员要将 C++ 引入目前完全用 C 编写的固件,那么他们或我就不必更新他们的configure.ac
. 如果我要对工具链进行更改,我只需要将更新推送到一个存储库,而不是将近十个。
问题
Autoconf 并不像我期望的那样理解宏。有几种不同的故障机制。
expanded before it was required
看到这个答案。
我有一个用于测试的骨架项目。它非常简单地Makefile.am
指定ACLOCAL_AMFLAGS
:
ACLOCAL_AMFLAGS = -I "$TIVASDK_HOME"/include
noinst_PROGRAMS = skel.axf
skel_axf_SOURCES = \
src/main.cpp \
src/abort.cpp
TIVASDK_HOME
中定义~/.profile
。
看到这个问题。它configure.ac
使用宏:
AC_INIT([skel], [0.1.0])
m4_define([TIVASDK_HOME], [esyscmd([printf "$TIVASDK_HOME"])])
AC_CONFIG_MACRO_DIR(TIVASDK_HOME[/include])
TIVASDK
AC_OUTPUT
它autogen.sh
在树外构建build
:
#!/bin/sh
autoreconf -vfi .. && \
../configure --prefix="$TIVASDK_HOME" --host=arm-none-eabi
运行autogen.sh
产生以下结果:
$ ./autogen.sh
autoreconf: Entering directory `..'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I /home/matthew/github.gatech.edu/GTSR/tiva-sdk/include
configure.ac:4: warning: AC_REQUIRE: `AC_PROG_CC' was expanded before it was required
configure.ac:4: http://www.gnu.org/software/autoconf/manual/autoconf.html#Expanded-Before-Required
/home/matthew/github.gatech.edu/GTSR/tiva-sdk/include/tivasdk.m4:1: TIVASDK is expanded from...
configure.ac:4: the top level
configure.ac:4: warning: AC_REQUIRE: `AC_PROG_CC' was expanded before it was required
configure.ac:4: http://www.gnu.org/software/autoconf/manual/autoconf.html#Expanded-Before-Required
/home/matthew/github.gatech.edu/GTSR/tiva-sdk/include/tivasdk.m4:1: TIVASDK is expanded from...
configure.ac:4: the top level
autoreconf: configure.ac: tracing
configure.ac:4: warning: AC_REQUIRE: `AC_PROG_CC' was expanded before it was required
configure.ac:4: http://www.gnu.org/software/autoconf/manual/autoconf.html#Expanded-Before-Required
aclocal.m4:1173: TIVASDK is expanded from...
configure.ac:4: the top level
autoreconf: configure.ac: not using Libtool
autoreconf: running: /usr/bin/autoconf --force
configure.ac:4: warning: AC_REQUIRE: `AC_PROG_CC' was expanded before it was required
configure.ac:4: http://www.gnu.org/software/autoconf/manual/autoconf.html#Expanded-Before-Required
aclocal.m4:1173: TIVASDK is expanded from...
configure.ac:4: the top level
autoreconf: configure.ac: not using Autoheader
autoreconf: running: automake --add-missing --copy --force-missing
configure.ac:4: warning: AC_REQUIRE: `AC_PROG_CC' was expanded before it was required
configure.ac:4: http://www.gnu.org/software/autoconf/manual/autoconf.html#Expanded-Before-Required
aclocal.m4:1173: TIVASDK is expanded from...
configure.ac:4: the top level
configure.ac:4: installing './compile'
configure.ac:4: installing './install-sh'
configure.ac:4: installing './missing'
Makefile.am: installing './depcomp'
autoreconf: Leaving directory `..'
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for arm-none-eabi-strip... arm-none-eabi-strip
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking for style of include used by make... GNU
checking for arm-none-eabi-gcc... arm-none-eabi-gcc
checking whether we are using the GNU C compiler... no
checking whether arm-none-eabi-gcc accepts -g... no
checking for arm-none-eabi-gcc option to accept ISO C89... unsupported
checking whether arm-none-eabi-gcc understands -c and -o together... yes
checking dependency style of arm-none-eabi-gcc... gcc3
checking for arm-none-eabi-gcc... (cached) arm-none-eabi-gcc
checking whether the C compiler works... no
configure: error: in `/home/matthew/gatech.edu/sp2019/vip4602/tmp/skel/build':
configure: error: C compiler cannot create executables
See `config.log' for more details
command not found
由于某种原因,我有一种预感会AC_DEFUN
扩展一些 Autoconf 宏。我将其替换AC_DEFUN
为m4_define
:
m4_define([TIVASDK],
[AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Werror])
: ${CC='arm-none-eabi-gcc -specs=nosys.specs'}
AC_PROG_CC
: ${CXX='arm-none-eabi-g++ -specs=nosys.specs'}
AC_PROG_CXX
AM_PROG_AS
AM_PROG_CC_C_O
AC_PROG_CXX_C_O
AC_CONFIG_FILES([Makefile])])
运行autogen.sh
产生以下结果:
$ ./autogen.sh
autoreconf: Entering directory `..'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I /home/matthew/github.gatech.edu/GTSR/tiva-sdk/include
autoreconf: configure.ac: tracing
autoreconf: configure.ac: not using Libtool
autoreconf: running: /usr/bin/autoconf --force
autoreconf: configure.ac: not using Autoheader
autoreconf: configure.ac: not using Automake
autoreconf: Leaving directory `..'
../configure: line 1678: TIVASDK: command not found
configure: creating ./config.status
似乎TIVASDK
根本没有扩大。我尝试替换m4_define
为define
无济于事。
最小的工作示例
只需将宏定义放入即可configure.ac
解决问题:
m4_define([TIVASDK],
[AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Werror])
: ${CC='arm-none-eabi-gcc -specs=nosys.specs'}
AC_PROG_CC
: ${CXX='arm-none-eabi-g++ -specs=nosys.specs'}
AC_PROG_CXX
AM_PROG_AS
AM_PROG_CC_C_O
AC_PROG_CXX_C_O
AC_CONFIG_FILES([Makefile])])
AC_INIT([skel], [0.1.0])
TIVASDK
AC_OUTPUT
运行autogen.sh
产生以下结果:
$ ./autogen.sh
autoreconf: Entering directory `..'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I /home/matthew/github.gatech.edu/GTSR/tiva-sdk/include
autoreconf: configure.ac: tracing
autoreconf: configure.ac: not using Libtool
autoreconf: running: /usr/bin/autoconf --force
autoreconf: configure.ac: not using Autoheader
autoreconf: running: automake --add-missing --copy --force-missing
configure.ac:12: installing './compile'
configure.ac:12: installing './install-sh'
configure.ac:12: installing './missing'
Makefile.am: installing './depcomp'
autoreconf: Leaving directory `..'
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for arm-none-eabi-strip... arm-none-eabi-strip
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking for arm-none-eabi-gcc... arm-none-eabi-gcc -specs=nosys.specs
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... yes
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether arm-none-eabi-gcc -specs=nosys.specs accepts -g... yes
checking for arm-none-eabi-gcc -specs=nosys.specs option to accept ISO C89... none needed
checking whether arm-none-eabi-gcc -specs=nosys.specs understands -c and -o together... yes
checking for style of include used by make... GNU
checking dependency style of arm-none-eabi-gcc -specs=nosys.specs... gcc3
checking whether we are using the GNU C++ compiler... yes
checking whether arm-none-eabi-g++ -specs=nosys.specs accepts -g... yes
checking dependency style of arm-none-eabi-g++ -specs=nosys.specs... gcc3
checking dependency style of arm-none-eabi-gcc -specs=nosys.specs... gcc3
checking whether arm-none-eabi-g++ -specs=nosys.specs understands -c and -o together... yes
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: executing depfiles commands
解决方案
- 为什么 AC_DEFUN 会尝试扩展 AC_PROG_CC?
我无法解释你错误的原因。我确实使用您的代码复制了它,但没有使用我最初尝试的类似代码。似乎涉及多种因素,其中包括两者的存在AC_PROG_CC
和AC_PROG_CXX
共同存在。
但是,从您最初的尝试开始,在“问题”标题上方的问题中提出,并根据错误消息所指的在线 Autoconf 手册页中的信息,我能够通过AC_PROG_CC
间接调用AC_REQUIRE
而不是直接地:
AC_DEFUN([TIVASDK], [
AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Werror])
: ${CC='arm-none-eabi-gcc -specs=nosys.specs'}
# HERE:
AC_REQUIRE([AC_PROG_CC])
: ${CXX='arm-none-eabi-g++ -specs=nosys.specs'}
AC_PROG_CXX
# ...
顺便说一句,我发现至少在骨架项目中没有理由定义或使用TIVASDK_HOME
宏。中的ACLOCAL_AMFLAGS
定义Makefile.in
显然就足够了。
我不太喜欢使用环境变量来定义所需宏包含目录的位置的想法,并且该示例并没有让我清楚为什么这很有用,但是如果您继续这样做,那么我鼓励您
- 用于
AC_ARG_VAR
记录该变量并使其变得珍贵,并且 - 确实确实删除了同名的宏。
- 为什么 m4_define 定义的宏似乎没有展开?
我认为这可能是因为外部宏文件不是直接使用的,而是由处理aclocal
生成的文件aclocal.m4
,这就是包含的内容。我想你会发现m4_define
出现在任何 Autoconf 宏定义范围之外的 direct 并没有被复制。
- 为什么 configure.ac 中定义的宏与另一个文件中定义并包含的宏的行为不同?
我认为不会。但是,在 中定义的 M4 宏的行为肯定与在其他地方定义但未configure.ac
包括在内的宏有所不同。
推荐阅读
- javascript - 将日期值转换为天数
- android - 如何减少android studio中的布局大小?
- asp.net - 在前一个上下文之前开始了第二个操作
- sql - 在唯一列上选择(DISTINCT?)
- reactjs - 将“返回”按钮标签相应地更改为使用 react-router-dom 访问的最后一页
- r - 如何快速创建一个变量,该变量全部组合了数据框中特定列的字符串值?
- php - 获取 woocommerce_form_field 选择的选定值
- r - R Shiny - 如何用 iframe 填充浏览器窗口的整个空间
- vaticle-typedb - 有没有办法只获取最深层的节点?
- javascript - 子组件中未定义 VUE 索引道具