更改包含在 AC_CHECK_HEADER 中的顺序

Change ordering of includes in AC_CHECK_HEADER

我遇到一个问题,我需要检查 header 文件 rose.h 是否存在。 使用 AC_CHECK_HEADER 时,header 包含在一系列其他(默认,我假设)header 之后。 其中一个 header 是 sys/stat.h。 不幸的是,rose.h header 文件(我无法以任何方式控制)必须包含在之前 sys/stat.h header 包括在内:

#if defined(_SYS_STAT_H)
#error "sys/stat.h should not have been included before the _FILE_OFFSET_BITS macro is set! (use rose.h first...)"
#endif

这会导致配置脚本出错:

checking rose.h usability... no
checking rose.h presence... yes
configure: WARNING: rose.h: present but cannot be compiled
configure: WARNING: rose.h:     check for missing prerequisite headers?
configure: WARNING: rose.h: see the Autoconf documentation
configure: WARNING: rose.h:     section "Present But Cannot Be Compiled"
configure: WARNING: rose.h: proceeding with the compiler's result
checking for rose.h... no
configure: error: A Working Rose installation is required. (Missing rose.h.)

问题:有没有办法告诉 AC_CHECK_HEADER 在 sys/stat.h 的包含之前松散地创建 rose.h 的包含?

违背 autoconf 经文:

AC_CHECK_HEADERS(
  [rose.h],
  [],
  [AC_MSG_ERROR(A Working Rose installation is required. (Missing rose.h.))]
)

相关 config.log 输出:

configure:3995: $? = 0
configure:4013: result: yes
configure:4032: checking rose.h usability
configure:4032: g++ -std=c++11 -c -fPIC -Wall -Wno-deprecated -Wextra -O3  -DUSE_CBC  conftest.cpp >&5
In file included from /home/username/.local/opt/rose/include/rose/sage3basic.h:38:0,
                 from /home/username/.local/opt/rose/include/rose/sage3basic.hhh:4,
                 from /home/username/.local/opt/rose/include/rose/rose.h:10,
                 from conftest.cpp:56:
/home/username/.local/opt/rose/include/rose/fileoffsetbits.h:16:2: error: #error "sys/stat.h should not have been included before the _FILE_OFFSET_BITS macro is set! (use rose.h first...)"
 #error "sys/stat.h should not have been included before the _FILE_OFFSET_BITS macro is set! (use rose.h first...)"
  ^
configure:4032: $? = 1
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME "project"
| #define PACKAGE_TARNAME "project"
| #define PACKAGE_VERSION "version-0.1"
| #define PACKAGE_STRING "project version-0.1"
| #define PACKAGE_BUGREPORT ""
| #define PACKAGE_URL ""
| #define HAVE_CXX11 1
| #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_ISL_VERSION_H 1
| #define HAVE_LINEAR_SOLVER_LINEAR_SOLVER_H 1
| #define HAVE_LIBORTOOLS 1
| /* end confdefs.h.  */
| #include <stdio.h>
| #ifdef HAVE_SYS_TYPES_H
| # include <sys/types.h>
| #endif
| #ifdef HAVE_SYS_STAT_H
| # include <sys/stat.h>
| #endif
| #ifdef STDC_HEADERS
| # include <stdlib.h>
| # include <stddef.h>
| #else
| # ifdef HAVE_STDLIB_H
| #  include <stdlib.h>
| # endif
| #endif
| #ifdef HAVE_STRING_H
| # if !defined STDC_HEADERS && defined HAVE_MEMORY_H
| #  include <memory.h>
| # endif
| # include <string.h>
| #endif
| #ifdef HAVE_STRINGS_H
| # include <strings.h>
| #endif
| #ifdef HAVE_INTTYPES_H
| # include <inttypes.h>
| #endif
| #ifdef HAVE_STDINT_H
| # include <stdint.h>
| #endif
| #ifdef HAVE_UNISTD_H
| # include <unistd.h>
| #endif
| #include <rose.h>
configure:4032: result: no
configure:4032: checking rose.h presence
configure:4032: g++ -std=c++11 -E  conftest.cpp
configure:4032: $? = 0
configure:4032: result: yes
configure:4032: WARNING: rose.h: present but cannot be compiled
configure:4032: WARNING: rose.h:     check for missing prerequisite headers?
configure:4032: WARNING: rose.h: see the Autoconf documentation
configure:4032: WARNING: rose.h:     section "Present But Cannot Be Compiled"
configure:4032: WARNING: rose.h: proceeding with the compiler's result
configure:4032: checking for rose.h
configure:4032: result: no
configure:4039: error: A Working Rose installation is required. (Missing rose.h.)

## ---------------- ##
## Cache variables. ##
## ---------------- ##

ac_cv_cxx_compiler_gnu=yes
ac_cv_env_CCC_set=
ac_cv_env_CCC_value=
ac_cv_env_CPPFLAGS_set=
ac_cv_env_CPPFLAGS_value=
ac_cv_env_CXXCPP_set=
ac_cv_env_CXXCPP_value=
ac_cv_env_CXXFLAGS_set=
ac_cv_env_CXXFLAGS_value=
ac_cv_env_CXX_set=
ac_cv_env_CXX_value=
ac_cv_env_LDFLAGS_set=
ac_cv_env_LDFLAGS_value=
ac_cv_env_LIBS_set=
ac_cv_env_LIBS_value=
ac_cv_env_build_alias_set=
ac_cv_env_build_alias_value=
ac_cv_env_host_alias_set=
ac_cv_env_host_alias_value=
ac_cv_env_target_alias_set=
ac_cv_env_target_alias_value=
ac_cv_header_inttypes_h=yes
ac_cv_header_isl_version_h=yes
ac_cv_header_linear_solver_linear_solver_h=yes
ac_cv_header_memory_h=yes
ac_cv_header_rose_h=no
ac_cv_header_stdc=yes
ac_cv_header_stdint_h=yes
ac_cv_header_stdlib_h=yes
ac_cv_header_string_h=yes
ac_cv_header_strings_h=yes
ac_cv_header_sys_stat_h=yes
ac_cv_header_sys_types_h=yes
ac_cv_header_unistd_h=yes
ac_cv_lib_ortools___include__linear_solver_linear_solver_h___include__string__=yes
ac_cv_objext=o
ac_cv_path_EGREP='/bin/grep -E'
ac_cv_path_GREP=/bin/grep
ac_cv_prog_CXXCPP='g++ -std=c++11 -E'
ac_cv_prog_ac_ct_CXX=g++
ac_cv_prog_cxx_g=yes
ac_cv_search_isl_version=-lisl
ax_cv_cxx_compile_cxx11=no
ax_cv_cxx_compile_cxx11__std_cpp11=yes

## ----------------- ##
## Output variables. ##
## ----------------- ##

CPPFLAGS=''
CXX='g++ -std=c++11'
CXXCPP='g++ -std=c++11 -E'
CXXFLAGS='-fPIC -Wall -Wno-deprecated -Wextra -O3  -DUSE_CBC'
DEFS=''
ECHO_C=''
ECHO_N='-n'
ECHO_T=''
EGREP='/bin/grep -E'
EXEEXT=''
GREP='/bin/grep'
HAVE_CXX11='1'
LDFLAGS=''
LIBOBJS=''
LIBS='-lortools -lisl '
LTLIBOBJS=''
OBJEXT='o'
PACKAGE_BUGREPORT=''
PACKAGE_NAME='project'
PACKAGE_STRING='project version-0.1'
PACKAGE_TARNAME='project'
PACKAGE_URL=''
PACKAGE_VERSION='version-0.1'
PATH_SEPARATOR=':'
PYTHON=''
SHELL='/bin/bash'
UNZIP=''
_PYPY_maybe=''
_PYTHON2_maybe=''
_PYTHON_maybe=''
_UNZIP_maybe=''
ac_ct_CXX='g++'
bindir='${exec_prefix}/bin'
build_alias=''
datadir='${datarootdir}'
datarootdir='${prefix}/share'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
dvidir='${docdir}'
exec_prefix='NONE'
host_alias=''
htmldir='${docdir}'
includedir='${prefix}/include'
infodir='${datarootdir}/info'
libdir='${exec_prefix}/lib'
libexecdir='${exec_prefix}/libexec'
localedir='${datarootdir}/locale'
localstatedir='${prefix}/var'
mandir='${datarootdir}/man'
oldincludedir='/usr/include'
pdfdir='${docdir}'
prefix='NONE'
program_transform_name='s,x,x,'
psdir='${docdir}'
runstatedir='${localstatedir}/run'
sbindir='${exec_prefix}/sbin'
sharedstatedir='${prefix}/com'
sysconfdir='${prefix}/etc'
target_alias=''

## ----------- ##
## confdefs.h. ##
## ----------- ##

/* confdefs.h */
#define PACKAGE_NAME "project"
#define PACKAGE_TARNAME "project"
#define PACKAGE_VERSION "version-0.1"
#define PACKAGE_STRING "project version-0.1"
#define PACKAGE_BUGREPORT ""
#define PACKAGE_URL ""
#define HAVE_CXX11 1
#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_ISL_VERSION_H 1
#define HAVE_LINEAR_SOLVER_LINEAR_SOLVER_H 1
#define HAVE_LIBORTOOLS 1

configure: exit 1

AC_CHECK_HEADER 之前调用宏 AC_SYS_LARGEFILE 可能会解决潜在的问题。

rose.h header 似乎定义了 LFS 参数,但是 不应该 在 header 中完成,因为不同的翻译单元同一个二进制文件不应该使用不同的 LFS 设置(因为它们会使用不同的 ABI),而 header 这样做的风险就是如此。

无论如何,使用 AC_SYS_LARGEFILE 可确保在包含任何内容之前为大文件设置正确的 LFS 参数,然后 #error 将不会触发。

更仔细地阅读 AC_CHECK_HEADERS documentation,我想出了一个稍微 hacky 的方法来使它对我有用。 AC_CHECK_HEADERS 宏有一个可选的 include 参数,您可以在其中编写代码(我假设通常是 include 指令),这些代码会插入到您的测试的 include 指令之前。

这里你可以写很多"fun"东西,比如一个#undef指令来取消定义HAVE_SYS_STAT_H符号,它保护sys/stat.h的包含,然后包含默认包含 AC_INCLUDES_DEFAULT

AC_CHECK_HEADERS(
  [rose.h],
  [],
  [AC_MSG_ERROR(A Working Rose installation is required. (Missing rose.h.))],
  [
    [ #undef HAVE_SYS_STAT_H ]
    AC_INCLUDES_DEFAULT
  ]
)

根据您希望的 correct/realistic 支票方式,这可能不适合您。我碰巧知道 sys/stat.h 稍后包含在 rose.h 中,并找到这个解决方案以一种现实的方式 很好地解决了我的特定问题。

但是,此 hack 也可用于重新排序包含。从广义上讲,您可以在所有默认值包含之前包含测试 header:

AC_CHECK_HEADERS(
  [rose.h],
  [],
  [AC_MSG_ERROR(A Working Rose installation is required. (Missing rose.h.))],
  [
    [ 
    #include <rose.h> 
    ]
    AC_INCLUDES_DEFAULT
  ]
)

或屏蔽掉有问题的包括:

AC_CHECK_HEADERS(
  [rose.h],
  [],
  [AC_MSG_ERROR(A Working Rose installation is required. (Missing rose.h.))],
  [
    [
    #ifdef HAVE_SYS_STAT_H
    # define REDEF_HAVE_SYS_STAT_H
    # undef HAVE_SYS_STAT_H
    #endif
    ]

    AC_INCLUDES_DEFAULT

    [
    #include <rose.h>

    #ifdef REDEF_HAVE_SYS_STAT_H
    # define HAVE_SYS_STAT_H
    #endif
    ]

    AC_INCLUDES_DEFAULT
  ]
)

或手动订购您认为有必要的所有内容:

AC_CHECK_HEADERS(
  [rose.h],
  [],
  [AC_MSG_ERROR(A Working Rose installation is required. (Missing rose.h.))],
  [
    [
    #include <stdio.h>
    #ifdef HAVE_SYS_TYPES_H
    # include <sys/types.h>
    #endif

    #include <rose.h>

    #ifdef HAVE_SYS_STAT_H
    # include <sys/stat.h>
    #endif
    #ifdef STDC_HEADERS
    # include <stdlib.h>
    # include <stddef.h>
    #else
    # ifdef HAVE_STDLIB_H
    #  include <stdlib.h>
    # endif
    #endif
    #ifdef HAVE_STRING_H
    # if !defined STDC_HEADERS && defined HAVE_MEMORY_H
    #  include <memory.h>
    # endif
    # include <string.h>
    #endif
    #ifdef HAVE_STRINGS_H
    # include <strings.h>
    #endif
    #ifdef HAVE_INTTYPES_H
    # include <inttypes.h>
    #endif
    #ifdef HAVE_STDINT_H
    # include <stdint.h>
    #endif
    #ifdef HAVE_UNISTD_H
    # include <unistd.h>
    #endif
    ]
  ]
)