如何在 AC_COMPILE_IFELSE 程序中使用 AC_CHECK_HEADER 标头

jww*_*jww 3 c x86 autoconf autotools

<x86intrin.h>我正在对 Clang 和 GCC 提供的非标准标头执行标头检查。其他编译器遵循英特尔并使用<immintrin.h>

\n\n
AC_CHECK_HEADER([x86intrin.h])\n
Run Code Online (Sandbox Code Playgroud)\n\n

Autotools 在 Linux 测试系统上找到它:

\n\n
checking x86intrin.h usability... yes\nchecking x86intrin.h presence... yes\nchecking for x86intrin.h... yes\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后我在测试中使用它:

\n\n
CXXFLAGS="-mrdseed"\nXXX_PROGRAM="#include <immintrin.h>\n   #ifdef HAVE_X86INTRIN_H\n   # include <x86intrin.h>\n   #endif\n   int main(int argc, char** argv) {\n      unsigned int x;\n      return _rdseed32_step(&x);\n   }"\n\nAC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS])\nAC_COMPILE_IFELSE(\n   [AC_LANG_SOURCE([$XXX_PROGRAM])],\n   [AC_MSG_RESULT([yes])],\n   [AC_MSG_RESULT([no])]\n)\n
Run Code Online (Sandbox Code Playgroud)\n\n

测试失败:

\n\n
checking if g++ supports -mrdseed... no\n
Run Code Online (Sandbox Code Playgroud)\n\n

机器有该功能并且编译器支持它。condefs.hconfig.log节目中看HAVE_X86INTRIN_H并没有按预期设置。

\n\n

该手册展示了如何使用5.6.3 通用标头检查中检查产生的标头中检查产生的标头。我想我正在做大致相同的事情:

\n\n
AC_CHECK_HEADERS([foo.h])\nAC_CHECK_HEADERS([bar.h], [], [],\n[#ifdef HAVE_FOO_H\n # include <foo.h>\n # endif\n])\n
Run Code Online (Sandbox Code Playgroud)\n\n

如何AC_CHECK_HEADERAC_COMPILE_IFELSE

\n\n
\n\n

这是我的测试驱动程序:

\n\n
$ cat test.cxx\n#include <immintrin.h>\n#ifdef HAVE_X86INTRIN_H\n# include <x86intrin.h>\n#endif\nint main(int argc, char** argv) {\n    unsigned int x;\n    return _rdseed32_step(&x);\n}\n\n$ g++ -mrdseed test.cxx -o test.exe\ntest.cxx: In function \xe2\x80\x98int main(int, char**)\xe2\x80\x99:\ntest.cxx:7:12: error: \xe2\x80\x98_rdseed32_step\xe2\x80\x99 was not declared in this scope\n     return _rdseed32_step(&x);\n            ^~~~~~~~~~~~~~\ntest.cxx:7:12: note: suggested alternative: \xe2\x80\x98_rdrand32_step\xe2\x80\x99\n     return _rdseed32_step(&x);\n            ^~~~~~~~~~~~~~\n            _rdrand32_step\n\n$ g++ -DHAVE_X86INTRIN_H -mrdseed test.cxx -o test.exe\n$ ./test.exe\n$\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

这是发行版和编译器:

\n\n
$ lsb_release -a\nLSB Version:    :core-4.1-amd64:core-4.1-noarch\nDistributor ID: Fedora\nDescription:    Fedora release 28 (Twenty Eight)\nRelease:        28\n\n$ g++ --version\ng++ (GCC) 8.1.1 20180712 (Red Hat 8.1.1-5)\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

以下是相关部分config.log

\n\n
configure:17624: checking if g++ supports -mrdseed\nconfigure:17631: g++ -o conftest -mrdseed   conftest.cpp  >&5\nconftest.cpp: In function \'int main(int, char**)\':\nconftest.cpp:38:17: error: \'_rdseed32_step\' was not declared in this scope\n          return _rdseed32_step(&x);\n                 ^~~~~~~~~~~~~~\nconftest.cpp:38:17: note: suggested alternative: \'_rdrand32_step\'\n          return _rdseed32_step(&x);\n                 ^~~~~~~~~~~~~~\n                 _rdrand32_step\nconfigure:17631: $? = 1\nconfigure: failed program was:\n| /* confdefs.h */\n| #define PACKAGE_NAME "Crypto++"\n| ...\n| #define STDC_HEADERS 1\n| #define HAVE_SYS_TYPES_H 1\n| #define HAVE_SYS_STAT_H 1\n| #define HAVE_STDLIB_H 1\n| #define HAVE_STRING_H 1\n| #define HAVE_MEMORY_H 1\n| #define HAVE_STRINGS_H 1\n| #define HAVE_INTTYPES_H 1\n| #define HAVE_STDINT_H 1\n| #define HAVE_UNISTD_H 1\n| #define HAVE_DLFCN_H 1\n| #define LT_OBJDIR ".libs/"\n| ...\n| /* end confdefs.h.  */\n| #include <immintrin.h>\n|       #ifdef HAVE_X86INTRIN_H\n|       # include <x86intrin.h>\n|       #endif\n|       int main(int argc, char** argv) {\n|          unsigned int x;\n|          return _rdseed32_step(&x);\n|       }\nconfigure:17645: result: no\n
Run Code Online (Sandbox Code Playgroud)\n

Joh*_*ger 6

您被 Autoconf 的陷阱绊倒了。 文档AC_CHECK_HEADER说:

如果系统头文件 header-file 可编译,则执行 shell 命令action-if-found,否则执行action-if-not-found. 如果您只想在头文件可用的情况下定义一个符号,请考虑使用AC_CHECK_HEADERS

(强调已添加)

将其与以下文档进行对比AC_CHECK_HEADERS

对于存在的空白分隔参数列表中的每个给定系统头文件 header-file,定义HAVE_*header-file*(全部大写)。如果给出了 action-if-found,[...]

请注意,与 的文档不同AC_CHECK_HEADERS, 的 文档AC_CHECK_HEADER并不声明如果找到标头就会定义任何符号。在这种情况下,除了报告检查结果之外,唯一要做的就是运行action-if-found. 您当然可以AC_DEFINE在其中放置一个来定义符号,但您不能像从 中那样免费获得它AC_CHECK_HEADERS。如果您愿意,您AC_CHECK_HEADERS甚至可以使用单个标头。

我确信差异的最初原因与检查可能的许多标头这一事实有关AC_CHECK_HEADERS。此外,有时您并不关心定义符号,或者您可能明确希望避免这样做;对于这些情况,您可以使用AC_CHECK_HEADER.

这是一个完整的 Autoconf 输入文件,演示了支票的工作变体:

AC_PREREQ([2.69])
AC_INIT([test], [0.0.0])

# Checks for programs.
AC_PROG_CC
AC_PROG_CXX

# Ensure that tests are run with the C++ compiler
AC_LANG([C++])

# Checks for header files.
AC_CHECK_HEADERS([x86intrin.h])

# Check support for -mrdseed
AS_IF([test "$ac_cv_header_x86intrin_h" = "yes"], [
  CXXFLAGS_save=$CXXFLAGS
  CXXFLAGS="$CXXFLAGS -mrdseed"

  XXX_PROGRAM="
#include <immintrin.h>
#ifdef HAVE_X86INTRIN_H
#include <x86intrin.h>
#endif
int main(void) {
    unsigned int x;
    return _rdseed32_step(&x);
}
"
  AC_MSG_CHECKING([whether $CXX supports -mrdseed])
  AC_COMPILE_IFELSE(
    [AC_LANG_SOURCE([$XXX_PROGRAM])],
    [AC_MSG_RESULT([yes])],
    [AC_MSG_RESULT([no])]
  )

  CXXFLAGS=$CXXFLAGS_save
])

AC_OUTPUT
Run Code Online (Sandbox Code Playgroud)