Autoconf 循环但在第一次成功后停止?

Autoconf loop but stop after first success?

我有这个片段来检测并要求最高可用的 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])
     ])
    ])
   ])
  ])
 ])
])

有没有办法把它变成一个列表?我理想中想要的是类似于以下伪代码的东西,以便 add/remove 特定的 C++ 变体只是更改列表而不是整个树:

foreach([-std=c++20, -std=c++2a, -std=c++17, etc],
[if(AX_CHECK_COMPILE_FLAG(, [CXXFLAGS+=]), break)])

据我所知,m4 根本无法循环。它可以递归,但是打破递归是我显然无法工作的那种m4黑魔法。

不,更改为另一个构建系统不是一个选项。这在 CMake 中是微不足道的,但这个项目是 autotools。

From what I can find, m4 simply cannot loop. It can recurse, but breaking out of a recursion is the kind of m4 black magic that I apparently can't get to work.

M4 absolutely can loop,但您不需要它来实现您的目的,而且您可能不想要它。事实上,通常 不想在自己的 Autoconf 代码中直接利用 M4 功能。

请始终记住,M4 在您构建构建系统时运行,而不是在您配置项目时运行。它生成 configure、shell 脚本和 用于 configure-time 控制流,您需要 configure 来利用 shell 特征。 Autoconf 围绕某些 shell 特性提供了宏,但您没有义务使用它们,您当然也没有义务避免使用 shell 特性只是因为没有 Autoconf 宏包装它们。主要警告是您应该小心编写 portable shell 代码。事实上,Autoconf 为 shell flow-control.

提供任何宏都是为了 objective

考虑到这一点,这里有一种使用 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 足以满足您程序的目的,那么通过有条件地 select 使用更新的版本可以获得什么?

也许确实有一点 - 例如,源代码可能包含预处理器条件,以便在按照更新的标准构建时启用其他功能。然而,在那种特殊情况下,更好的 Autoconf 习惯用法是为条件特征添加一个或多个 --enable 标志,并向 select 添加所需的 C++ 版本标志,如果有的话,被选中。然后就没有必要测试任何其他选项,而且对于想要影响实际启用的功能的构建者来说,它就不那么神奇了。