首页 > 解决方案 > 如何在 AC_COMPILE_IFELSE 程序中使用 AC_CHECK_HEADER 标头

问题描述

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

AC_CHECK_HEADER([x86intrin.h])

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

checking x86intrin.h usability... yes
checking x86intrin.h presence... yes
checking for x86intrin.h... yes

然后我在测试中使用它:

CXXFLAGS="-mrdseed"
XXX_PROGRAM="#include <immintrin.h>
   #ifdef HAVE_X86INTRIN_H
   # include <x86intrin.h>
   #endif
   int main(int argc, char** argv) {
      unsigned int x;
      return _rdseed32_step(&x);
   }"

AC_MSG_CHECKING([if $CXXNAME supports $CXXFLAGS])
AC_COMPILE_IFELSE(
   [AC_LANG_SOURCE([$XXX_PROGRAM])],
   [AC_MSG_RESULT([yes])],
   [AC_MSG_RESULT([no])]
)

测试失败:

checking if g++ supports -mrdseed... no

该机器具有该功能并且编译器支持它。从节目condefs.h中看没有按预期设置。config.logHAVE_X86INTRIN_H

该手册显示了如何使用由5.6.3 Generic Header Checks中的检查产生的标题。我想我在做大致相同的事情:

AC_CHECK_HEADERS([foo.h])
AC_CHECK_HEADERS([bar.h], [], [],
[#ifdef HAVE_FOO_H
 # include <foo.h>
 # endif
])

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


这是我的测试驱动程序:

$ cat test.cxx
#include <immintrin.h>
#ifdef HAVE_X86INTRIN_H
# include <x86intrin.h>
#endif
int main(int argc, char** argv) {
    unsigned int x;
    return _rdseed32_step(&x);
}

$ g++ -mrdseed test.cxx -o test.exe
test.cxx: In function ‘int main(int, char**)’:
test.cxx:7:12: error: ‘_rdseed32_step’ was not declared in this scope
     return _rdseed32_step(&x);
            ^~~~~~~~~~~~~~
test.cxx:7:12: note: suggested alternative: ‘_rdrand32_step’
     return _rdseed32_step(&x);
            ^~~~~~~~~~~~~~
            _rdrand32_step

$ g++ -DHAVE_X86INTRIN_H -mrdseed test.cxx -o test.exe
$ ./test.exe
$

这是发行版和编译器:

$ lsb_release -a
LSB Version:    :core-4.1-amd64:core-4.1-noarch
Distributor ID: Fedora
Description:    Fedora release 28 (Twenty Eight)
Release:        28

$ g++ --version
g++ (GCC) 8.1.1 20180712 (Red Hat 8.1.1-5)

以下是来自的相关部分config.log

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

标签: cx86autotoolsautoconf

解决方案


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

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

(重点补充)

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

对于存在的以空格分隔的参数列表中的每个给定系统头文件头文件,定义HAVE_*header-file*(全部大写)。如果给出了找到时采取的行动,[...]

请注意,与 forAC_CHECK_HEADERS的文档不同,文档 forAC_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

推荐阅读