如何使 Autoconf 从外部文件测试源代码?
How can Autoconf be made to test source code from an external file?
我们使用 GNUmakefile 作为我们的主要构建系统。 makefile 使用源文件中的测试程序执行功能测试:
$ ls TestPrograms/
dump2def.cxx test_arm_sm4.cxx test_x86_avx.cxx
test_32bit.cxx test_cxx.cxx test_x86_avx2.cxx
test_64bit.cxx test_mixed_asm.cxx test_x86_avx512.cxx
...
一个测试程序是人们所期望的:
$ cat test_cxx.cxx
#include <string>
int main(int argc, char* argv[])
{
unsigned int x=0;
return x;
}
我们支持 Debian 和 Fedora 等发行版的 Autotools。我们希望 Autotools 使用 GNUmakefile 和 CMake 等测试程序。 AC_COMPILE_IFELSE
上的 Autools 文档是 here,但它像往常一样可怜。它不讨论主题或提供示例。
暗中刺杀:
CXXFLAGS="-msse2"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS and Foo Bar])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([TestPrograms/test_x86_sse2.cxx])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])]
)
结果:
checking if g++ supports -msse2 and Foo Bar... no
与 cat
将文件转换为字符串的结果相同:
CXXFLAGS="-msse2"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS and Foo Bar])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(`cat TestPrograms/test_x86_sse2.cxx`)],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])]
)
Skylake 机器上的结果不正确。 SSE2 是核心指令集的一部分,始终可用:
$ g++ -msse2 TestPrograms/test_x86_sse2.cxx
$
我们如何告诉 Autoconf 编译测试文件?
Autools documentation on AC_COMPILE_IFELSE
[...] is pathetic as usual. It does not discuss the topic or provide examples.
虽然那个单独的页面没有提供完整的细节,但它是一个更大的手册的一部分,该手册在附近的部分提供了更多的细节和一些相关的例子。然而,即使该页面本身也建议 AC_LANG_PROGRAM
作为为该宏生成 input
参数的适当方法,并且 documentation for that macro 给出了它生成的一般形式的合理概念 - 实际来源程序代码,而不是文件名。
当涉及到刺探答案时,我建议不要故意蒙在鼓里。即使您没有找到足够的文档,至少 configure
的日志文件 (config.log
) 应该包含大量关于失败的原因、失败的原因和方式的信息。如果出现故障,它将向您显示它使用的测试程序的完整源代码、实际执行测试所执行的命令以及发出的任何诊断信息。
例如,使用派生自此 configure.ac
受您的示例启发的配置脚本 ...
AC_INIT([test_test], [0.0.1])
AC_CONFIG_SRCDIR([test_src/test_cxx.cxx])
AC_PROG_CXX
CXXFLAGS="-msse2"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS and Foo Bar])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([`cat test_src/test_cxx.cxx`])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])]
)
AC_OUTPUT
...我在日志中的相关输出中得到失败结果:
configure:2891: gcc -o conftest -g -O2 conftest.c >&5
conftest.c:9:18: fatal error: string: No such file or directory
#include <string>
^
compilation terminated.
configure:2891: $? = 1
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME "test_test"
| #define PACKAGE_TARNAME "test_test"
| #define PACKAGE_VERSION "0.0.1"
| #define PACKAGE_STRING "test_test 0.0.1"
| #define PACKAGE_BUGREPORT ""
| #define PACKAGE_URL ""
| /* end confdefs.h. */
| #include <string>
| int main(int argc, char* argv[])
| {
| unsigned int x=0;
| return x;
| }
| int
| main ()
| {
|
| ;
| return 0;
| }
configure:2895: result: no
这说明确实是从外部文件中读取源代码,同时也暴露了两个关键问题:
在这种情况下,AC_LANG_PROGRAM
提供的内容比您想要的要多(与其文档一致)。事实上,如果您为测试程序提供完整的源代码,您根本不需要它。
测试程序作为C程序被编译和链接,但它的源代码是C++。此默认值已记录 in the manual.
问题 (1) 可以通过将源代码直接提供给 AC_LINK_IFELSE
来解决,而无需通过 AC_LANG_PROGRAM
包装它,但 Autoconf 在这种情况下会警告没有看到 AC_LANG_SOURCE
.一个相当舒适的解决方案是直接使用 AC_LANG_SOURCE
,而不是 AC_LANG_PROGRAM
。这将为提供的来源添加一些额外的 #defines
,但是,这可能不适合您。如果您不想这样,那么我认为在这种情况下忽略警告是安全的。
问题 (2) 可以通过使用 AC_LANG
宏告诉 Autoconf 应该使用 C++ 编译器和 C++ 标志的相关 Autotools 变量执行测试来解决。
因此,如果我将 configure.ac
更新为
AC_INIT([test_test], [0.0.1])
AC_CONFIG_SRCDIR([test_src/test_cxx.cxx])
AC_PROG_CXX
AC_LANG([C++])
CXXFLAGS="-msse2"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS and Foo Bar])
AC_LINK_IFELSE(
[AC_LANG_SOURCE([`cat test_src/test_cxx.cxx`])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])]
)
AC_OUTPUT
然后我的配置运行成功了,我在日志中看到它执行的编译命令成功,是
configure:2296: g++ -o conftest -msse2 conftest.cpp >&5
。也就是说,它使用选定的 C++ 编译器进行编译,使用 CXXFLAGS
中指定的标志,并将测试源文件适当地命名为 C++ 以进行编译。
我们使用 GNUmakefile 作为我们的主要构建系统。 makefile 使用源文件中的测试程序执行功能测试:
$ ls TestPrograms/
dump2def.cxx test_arm_sm4.cxx test_x86_avx.cxx
test_32bit.cxx test_cxx.cxx test_x86_avx2.cxx
test_64bit.cxx test_mixed_asm.cxx test_x86_avx512.cxx
...
一个测试程序是人们所期望的:
$ cat test_cxx.cxx
#include <string>
int main(int argc, char* argv[])
{
unsigned int x=0;
return x;
}
我们支持 Debian 和 Fedora 等发行版的 Autotools。我们希望 Autotools 使用 GNUmakefile 和 CMake 等测试程序。 AC_COMPILE_IFELSE
上的 Autools 文档是 here,但它像往常一样可怜。它不讨论主题或提供示例。
暗中刺杀:
CXXFLAGS="-msse2"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS and Foo Bar])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([TestPrograms/test_x86_sse2.cxx])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])]
)
结果:
checking if g++ supports -msse2 and Foo Bar... no
与 cat
将文件转换为字符串的结果相同:
CXXFLAGS="-msse2"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS and Foo Bar])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(`cat TestPrograms/test_x86_sse2.cxx`)],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])]
)
Skylake 机器上的结果不正确。 SSE2 是核心指令集的一部分,始终可用:
$ g++ -msse2 TestPrograms/test_x86_sse2.cxx
$
我们如何告诉 Autoconf 编译测试文件?
Autools documentation on
AC_COMPILE_IFELSE
[...] is pathetic as usual. It does not discuss the topic or provide examples.
虽然那个单独的页面没有提供完整的细节,但它是一个更大的手册的一部分,该手册在附近的部分提供了更多的细节和一些相关的例子。然而,即使该页面本身也建议 AC_LANG_PROGRAM
作为为该宏生成 input
参数的适当方法,并且 documentation for that macro 给出了它生成的一般形式的合理概念 - 实际来源程序代码,而不是文件名。
当涉及到刺探答案时,我建议不要故意蒙在鼓里。即使您没有找到足够的文档,至少 configure
的日志文件 (config.log
) 应该包含大量关于失败的原因、失败的原因和方式的信息。如果出现故障,它将向您显示它使用的测试程序的完整源代码、实际执行测试所执行的命令以及发出的任何诊断信息。
例如,使用派生自此 configure.ac
受您的示例启发的配置脚本 ...
AC_INIT([test_test], [0.0.1])
AC_CONFIG_SRCDIR([test_src/test_cxx.cxx])
AC_PROG_CXX
CXXFLAGS="-msse2"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS and Foo Bar])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([`cat test_src/test_cxx.cxx`])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])]
)
AC_OUTPUT
...我在日志中的相关输出中得到失败结果:
configure:2891: gcc -o conftest -g -O2 conftest.c >&5 conftest.c:9:18: fatal error: string: No such file or directory #include <string> ^ compilation terminated. configure:2891: $? = 1 configure: failed program was: | /* confdefs.h */ | #define PACKAGE_NAME "test_test" | #define PACKAGE_TARNAME "test_test" | #define PACKAGE_VERSION "0.0.1" | #define PACKAGE_STRING "test_test 0.0.1" | #define PACKAGE_BUGREPORT "" | #define PACKAGE_URL "" | /* end confdefs.h. */ | #include <string> | int main(int argc, char* argv[]) | { | unsigned int x=0; | return x; | } | int | main () | { | | ; | return 0; | } configure:2895: result: no
这说明确实是从外部文件中读取源代码,同时也暴露了两个关键问题:
-
在这种情况下,
AC_LANG_PROGRAM
提供的内容比您想要的要多(与其文档一致)。事实上,如果您为测试程序提供完整的源代码,您根本不需要它。测试程序作为C程序被编译和链接,但它的源代码是C++。此默认值已记录 in the manual.
问题 (1) 可以通过将源代码直接提供给 AC_LINK_IFELSE
来解决,而无需通过 AC_LANG_PROGRAM
包装它,但 Autoconf 在这种情况下会警告没有看到 AC_LANG_SOURCE
.一个相当舒适的解决方案是直接使用 AC_LANG_SOURCE
,而不是 AC_LANG_PROGRAM
。这将为提供的来源添加一些额外的 #defines
,但是,这可能不适合您。如果您不想这样,那么我认为在这种情况下忽略警告是安全的。
问题 (2) 可以通过使用 AC_LANG
宏告诉 Autoconf 应该使用 C++ 编译器和 C++ 标志的相关 Autotools 变量执行测试来解决。
因此,如果我将 configure.ac
更新为
AC_INIT([test_test], [0.0.1])
AC_CONFIG_SRCDIR([test_src/test_cxx.cxx])
AC_PROG_CXX
AC_LANG([C++])
CXXFLAGS="-msse2"
AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS and Foo Bar])
AC_LINK_IFELSE(
[AC_LANG_SOURCE([`cat test_src/test_cxx.cxx`])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])]
)
AC_OUTPUT
然后我的配置运行成功了,我在日志中看到它执行的编译命令成功,是
configure:2296: g++ -o conftest -msse2 conftest.cpp >&5
。也就是说,它使用选定的 C++ 编译器进行编译,使用 CXXFLAGS
中指定的标志,并将测试源文件适当地命名为 C++ 以进行编译。