首页 > 解决方案 > 如何在常见的 Autoconf 宏中包含宏?

问题描述

TL;博士

背景

我负责为大约六个不同的板子构建固件和库,这些板子都使用相同的嵌入式处理器。由于所有板卡都使用相同的处理器,因此存在重要的通用配置(CCCXXCPPFLAGSCFLAGSCXXFLAGSLDFLAGS等)和配方。对于固件,我使用自定义生成文件,其中包含一个通用配置文件,该文件定义了所有通用配置和配方。为了简化在开发人员的计算机上安装库和头文件,我使用 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_DEFUNm4_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_definedefine无济于事。

最小的工作示例

只需将宏定义放入即可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

标签: autotoolsautoconf

解决方案


  • 为什么 AC_DEFUN 会尝试扩展 AC_PROG_CC?

我无法解释你错误的原因。我确实使用您的代码复制了它,但没有使用我最初尝试的类似代码。似乎涉及多种因素,其中包括两者的存在AC_PROG_CCAC_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包括在内的宏有所不同。


推荐阅读