在 configure.ac 中更改 *FLAGS 与使用子项目进行缓存
Changing *FLAGS in configure.ac vs. caching with subprojects
说我想在我的 configure
脚本中向 CFLAGS
添加一个特定的标志,它应该传播到所有子项目的 configure
脚本:
CFLAGS+=" -Dfoobar"
export CFLAGS
AC_CONFIG_SUBDIRS([sub])
这在 configure
被平凡调用时有效。一旦发生以下情况之一:
CFLAGS
在调用configure
时在环境中导出
CFLAGS
设置在 configure
命令行
- 使用了缓存 (
configure -C
)
这种方法不再有效。在前两种情况下,导出的 CFLAGS
被简单地忽略了;在最后一个中,configure
失败并显示
configure: error: `CFLAGS' was not set in the previous run
我通过以下方式使它可靠地工作:
AM_CFLAGS+=" -Dfoobar"
export AM_CFLAGS
AC_SUBST([AM_CFLAGS]) # repeat this line in every configure.ac for each *FLAGS
AC_CONFIG_SUBDIRS([sub])
考虑到有多个子项目,并且可能需要这样设置多个 *FLAGS
变量,这是半途而废,但仍然不是最佳选择。有没有办法只通过破解顶级 configure.ac
?
来完成这项工作
除了在多个顶级 configure
运行中缓存之外,我终于让这个工作起来了。这个想法是破解 autoconf 的内部变量以获得所需的功能,这并不难:
- 修改
CFLAGS
- hack
ac_configure_args
以包含修改后的 CFLAGS
而不是任何外部检测到的 CFLAGS
这立即解决了问题描述中的问题 1. 和 2.(外部 CFLAGS
)。为了修复缓存,我必须:
- hack
ac_cv_env_CFLAGS_{set,value}
分别包含 set
和修改后的 CFLAGS
这会导致两个问题:
- 使用缓存,
./config.status --recheck
将再次执行对 CFLAGS 的修改,即使此修改已被缓存,导致重复标志。仅在未完成修改的情况下进行修改解决了此问题。
- 当使用现有的
config.cache
调用顶级配置时,损坏是不可避免的,因为 config.cache
一致性检查执行得太早,因此不会受到影响。只有当我们在命令行(或环境)上通过 CFLAGS
包括 configure
修改时,此检查才会通过,没有办法绕过它。唯一的解决办法是在配置完所有子包后删除 config.cache
。由于子包配置期间的缓存仍然有效,我认为这是可以接受的。
顶级 configure.ac
:
AC_INIT([test], [0.1])
AC_CONFIG_MACRO_DIR([m4]) # for ax_append_flag.m4
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CC
AC_PROG_SED
# Modify the CFLAGS. AX_APPEND_FLAG makes sure not to add the flag if it's already there
AX_APPEND_FLAG([-Dtop-configure], [CFLAGS])
# Replace/add CFLAGS in/to ac_configure_args
AS_CASE([$ac_configure_args],
[*CFLAGS=*], [ac_configure_args=`AS_ECHO "$ac_configure_args" | $SED ["s|CFLAGS=[^']*|CFLAGS=$CFLAGS|"]`],
[AS_VAR_APPEND([ac_configure_args],[" 'CFLAGS=$CFLAGS'"])]
)
# Fix the cache vars
ac_cv_env_CFLAGS_set=set
ac_cv_env_CFLAGS_value=$CFLAGS
# exporting CFLAGS is not needed for sub-packages: they get CFLAGS from ac_configure_args
AC_CONFIG_SUBDIRS([sub])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
AC_MSG_NOTICE([removing config.cache])
rm -f config.cache
子级别configure.ac
:
AC_INIT([test-sub], [0.1])
AC_CONFIG_MACRO_DIR([../m4])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CC
AX_APPEND_FLAG([-Dsub-configure], [CFLAGS])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
Makefile
s 仅在 all-local
目标中打印 $CFLAGS
的值。
输出如下所示:
$ autoconf && ./configure -C >/dev/null && make | grep CFLAGS # 1st run
sub CFLAGS: -g -O2 -Dtop-configure -Dsub-configure
top CFLAGS: -g -O2 -Dtop-configure
$ ./configure -C >/dev/null && make | grep CFLAGS # 2nd run
sub CFLAGS: -g -O2 -Dtop-configure -Dsub-configure
top CFLAGS: -g -O2 -Dtop-configure
$ touch configure.ac && make | grep CFLAGS # recheck run
running CONFIG_SHELL=/bin/sh /bin/sh ./configure -C CFLAGS=-g -O2 -Dtop-configure --no-create --no-recursion
sub CFLAGS: -g -O2 -Dtop-configure -Dsub-configure
top CFLAGS: -g -O2 -Dtop-configure
$ CFLAGS=-Dexternal ./configure -C >/dev/null && make | grep CFLAGS # 1st run
sub CFLAGS: -Dexternal -Dtop-configure -Dsub-configure
top CFLAGS: -Dexternal -Dtop-configure
$ CFLAGS=-Dexternal ./configure -C >/dev/null && make | grep CFLAGS # 2nd run
sub CFLAGS: -Dexternal -Dtop-configure -Dsub-configure
top CFLAGS: -Dexternal -Dtop-configure
$ touch configure.ac && make | grep CFLAGS # recheck run
running CONFIG_SHELL=/bin/sh /bin/sh ./configure -C CFLAGS=-Dexternal -Dtop-configure --no-create --no-recursion
sub CFLAGS: -Dexternal -Dtop-configure -Dsub-configure
top CFLAGS: -Dexternal -Dtop-configure
最终解决方案是 受影响的变量:
顶级 configure.ac:
AC_INIT([test], [0.1])
AC_CONFIG_MACRO_DIR([m4]) # for ax_append_flag.m4
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CC
AC_PROG_SED
# Modify the CFLAGS. AX_APPEND_FLAG makes sure not to add the flag if it's already there
AX_APPEND_FLAG([-Dtop-configure], [CFLAGS])
AC_DEFUN([AX_UNPRECIOUS], [
m4_define([_AC_PRECIOUS_VARS], m4_bpatsubst(_AC_PRECIOUS_VARS, [
], []))
])
AX_UNPRECIOUS([CFLAGS])
export CFLAGS
AC_CONFIG_SUBDIRS([sub])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
在幕后,CFLAGS
从未被视为珍贵,因此从未被缓存或传递给子包 configure
s — 他们将其视为环境变量 独占,然后自己缓存在common顶层config.cache
.
这非常可靠,并且通过在顶级配置运行中允许缓存值(并且更简单)改进了我以前的解决方案。
说我想在我的 configure
脚本中向 CFLAGS
添加一个特定的标志,它应该传播到所有子项目的 configure
脚本:
CFLAGS+=" -Dfoobar"
export CFLAGS
AC_CONFIG_SUBDIRS([sub])
这在 configure
被平凡调用时有效。一旦发生以下情况之一:
CFLAGS
在调用configure
时在环境中导出CFLAGS
设置在configure
命令行- 使用了缓存 (
configure -C
)
这种方法不再有效。在前两种情况下,导出的 CFLAGS
被简单地忽略了;在最后一个中,configure
失败并显示
configure: error: `CFLAGS' was not set in the previous run
我通过以下方式使它可靠地工作:
AM_CFLAGS+=" -Dfoobar"
export AM_CFLAGS
AC_SUBST([AM_CFLAGS]) # repeat this line in every configure.ac for each *FLAGS
AC_CONFIG_SUBDIRS([sub])
考虑到有多个子项目,并且可能需要这样设置多个 *FLAGS
变量,这是半途而废,但仍然不是最佳选择。有没有办法只通过破解顶级 configure.ac
?
除了在多个顶级 configure
运行中缓存之外,我终于让这个工作起来了。这个想法是破解 autoconf 的内部变量以获得所需的功能,这并不难:
- 修改
CFLAGS
- hack
ac_configure_args
以包含修改后的CFLAGS
而不是任何外部检测到的CFLAGS
这立即解决了问题描述中的问题 1. 和 2.(外部 CFLAGS
)。为了修复缓存,我必须:
- hack
ac_cv_env_CFLAGS_{set,value}
分别包含set
和修改后的CFLAGS
这会导致两个问题:
- 使用缓存,
./config.status --recheck
将再次执行对 CFLAGS 的修改,即使此修改已被缓存,导致重复标志。仅在未完成修改的情况下进行修改解决了此问题。 - 当使用现有的
config.cache
调用顶级配置时,损坏是不可避免的,因为config.cache
一致性检查执行得太早,因此不会受到影响。只有当我们在命令行(或环境)上通过CFLAGS
包括configure
修改时,此检查才会通过,没有办法绕过它。唯一的解决办法是在配置完所有子包后删除config.cache
。由于子包配置期间的缓存仍然有效,我认为这是可以接受的。
顶级 configure.ac
:
AC_INIT([test], [0.1])
AC_CONFIG_MACRO_DIR([m4]) # for ax_append_flag.m4
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CC
AC_PROG_SED
# Modify the CFLAGS. AX_APPEND_FLAG makes sure not to add the flag if it's already there
AX_APPEND_FLAG([-Dtop-configure], [CFLAGS])
# Replace/add CFLAGS in/to ac_configure_args
AS_CASE([$ac_configure_args],
[*CFLAGS=*], [ac_configure_args=`AS_ECHO "$ac_configure_args" | $SED ["s|CFLAGS=[^']*|CFLAGS=$CFLAGS|"]`],
[AS_VAR_APPEND([ac_configure_args],[" 'CFLAGS=$CFLAGS'"])]
)
# Fix the cache vars
ac_cv_env_CFLAGS_set=set
ac_cv_env_CFLAGS_value=$CFLAGS
# exporting CFLAGS is not needed for sub-packages: they get CFLAGS from ac_configure_args
AC_CONFIG_SUBDIRS([sub])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
AC_MSG_NOTICE([removing config.cache])
rm -f config.cache
子级别configure.ac
:
AC_INIT([test-sub], [0.1])
AC_CONFIG_MACRO_DIR([../m4])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CC
AX_APPEND_FLAG([-Dsub-configure], [CFLAGS])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
Makefile
s 仅在 all-local
目标中打印 $CFLAGS
的值。
输出如下所示:
$ autoconf && ./configure -C >/dev/null && make | grep CFLAGS # 1st run
sub CFLAGS: -g -O2 -Dtop-configure -Dsub-configure
top CFLAGS: -g -O2 -Dtop-configure
$ ./configure -C >/dev/null && make | grep CFLAGS # 2nd run
sub CFLAGS: -g -O2 -Dtop-configure -Dsub-configure
top CFLAGS: -g -O2 -Dtop-configure
$ touch configure.ac && make | grep CFLAGS # recheck run
running CONFIG_SHELL=/bin/sh /bin/sh ./configure -C CFLAGS=-g -O2 -Dtop-configure --no-create --no-recursion
sub CFLAGS: -g -O2 -Dtop-configure -Dsub-configure
top CFLAGS: -g -O2 -Dtop-configure
$ CFLAGS=-Dexternal ./configure -C >/dev/null && make | grep CFLAGS # 1st run
sub CFLAGS: -Dexternal -Dtop-configure -Dsub-configure
top CFLAGS: -Dexternal -Dtop-configure
$ CFLAGS=-Dexternal ./configure -C >/dev/null && make | grep CFLAGS # 2nd run
sub CFLAGS: -Dexternal -Dtop-configure -Dsub-configure
top CFLAGS: -Dexternal -Dtop-configure
$ touch configure.ac && make | grep CFLAGS # recheck run
running CONFIG_SHELL=/bin/sh /bin/sh ./configure -C CFLAGS=-Dexternal -Dtop-configure --no-create --no-recursion
sub CFLAGS: -Dexternal -Dtop-configure -Dsub-configure
top CFLAGS: -Dexternal -Dtop-configure
最终解决方案是
顶级 configure.ac:
AC_INIT([test], [0.1])
AC_CONFIG_MACRO_DIR([m4]) # for ax_append_flag.m4
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CC
AC_PROG_SED
# Modify the CFLAGS. AX_APPEND_FLAG makes sure not to add the flag if it's already there
AX_APPEND_FLAG([-Dtop-configure], [CFLAGS])
AC_DEFUN([AX_UNPRECIOUS], [
m4_define([_AC_PRECIOUS_VARS], m4_bpatsubst(_AC_PRECIOUS_VARS, [
], []))
])
AX_UNPRECIOUS([CFLAGS])
export CFLAGS
AC_CONFIG_SUBDIRS([sub])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
在幕后,CFLAGS
从未被视为珍贵,因此从未被缓存或传递给子包 configure
s — 他们将其视为环境变量 独占,然后自己缓存在common顶层config.cache
.
这非常可靠,并且通过在顶级配置运行中允许缓存值(并且更简单)改进了我以前的解决方案。