我有这个片段要检测,并且需要最高可用的C++标准。它的工作方式正是我想要的——首先检查最高,在第一次成功后停止搜索。它也非常丑陋,很难维护。
# Require highest supported C++ standard
AC_LANG(C++)
AX_CHECK_COMPILE_FLAG([-std=c++20], [CXXFLAGS="$CXXFLAGS -std=c++20"], [
AX_CHECK_COMPILE_FLAG([-std=c++2a], [CXXFLAGS="$CXXFLAGS -std=c++2a"], [
AX_CHECK_COMPILE_FLAG([-std=c++17], [CXXFLAGS="$CXXFLAGS -std=c++17"], [
AX_CHECK_COMPILE_FLAG([-std=c++1z], [CXXFLAGS="$CXXFLAGS -std=c++1z"], [
AX_CHECK_COMPILE_FLAG([-std=c++14], [CXXFLAGS="$CXXFLAGS -std=c++14"], [
AX_CHECK_COMPILE_FLAG([-std=c++1y], [CXXFLAGS="$CXXFLAGS -std=c++1y"], [
AC_MSG_ERROR([Could not enable at least C++1y (C++14) - upgrade your compiler])
])
])
])
])
])
])
有没有办法把它变成一个单一的列表?理想情况下,我想要的是以下伪代码,这样添加/删除特定的C++变体只需更改列表,而不是整个树:
foreach([-std=c++20, -std=c++2a, -std=c++17, etc],
[if(AX_CHECK_COMPILE_FLAG($1, [CXXFLAGS+=$1]), break)])
据我所知,m4根本无法循环。它可以递归,但突破递归是一种m4黑色魔法,我显然无法发挥作用。
不,更改为另一个构建系统不是一种选择。这在CMake中是微不足道的,但这个项目是自动工具。
M4绝对可以循环,但你不需要它,你可能也不想要它。事实上,通常不想直接利用Autoconf代码中的M4功能。
请记住,M4在构建构建系统时运行,而不是在配置项目时运行。它生成configure
,一个shell脚本,并且用于配置时间控制流,您需要configure
来利用shell功能。Autoconf提供了一些围绕此类外壳功能的宏,但您没有义务使用它们,当然也没有义务仅仅因为没有Autoconf宏包装外壳功能而避免使用它们。主要的警告是,您应该小心编写可移植shell代码。事实上,Autoconf为shell流控制提供任何宏都是为了实现这一目标。
考虑到这一点,这里有一种使用shell循环来更干净地实现检查的方法:
# language versions to test, in priority order:
for version in 20 2a 17 1z 14 1y; do
version_flag="-std=c++${version}"
AX_CHECK_COMPILE_FLAG([${version_flag}], [
break
], [
version_flag=none
])
done
AS_IF([test "$version_flag" == none], [
AC_MSG_ERROR([Could not enable at least C++1y (C++14) - upgrade your compiler])
])
CXXFLAGS="$CXXFLAGS ${version_flag}"
如果您想将测试的版本或您的优先级更改为首选版本,那么您只需更改for
语句中的列表即可。
然而,我提出了一个框架挑战:重点是什么?如果-std=c++1y
足以满足您的程序的目的,那么有条件地选择更新的版本会得到什么?
也许确实有一点——例如,源代码可能包含预处理器条件,以便在按照更新的标准构建时启用附加功能。然而,在这种特殊情况下,更好的Autoconf习惯用法是为条件特性添加一个或多个--enable
标志,并选择所需的C++版本标志(如果有的话(。这样就没有必要测试任何其他选项,对于想要影响实际启用的功能的构建者来说,这也不那么神奇。