确保 config.h 包含一次

ensure config.h is included once

我有一个库项目,我正在努力移植到 Linux 中使用 autotools 套件。我对 autotools 很陌生(本周)。我已经了解了其操作的基础知识。我有一个关于如何防止 config.h 的内容被重新定义的问题。

我很惊讶地发现生成的 config.h 文件也没有,1) 将每个宏包装在 #ifndef 中,或者 2) 整个文件没有包装在标准 #ifndef CONFIG_H.

正如我所暗示的,这段代码是建立在 Windows 和 Linux 之上的。因此宏有多种用途,_linux(我并不是说这是最好的名字,但它在任何地方都在使用)将仅存在于 Linux 中的元素引入 类 .因此,这将发生

header.h

#ifndef HEADER1_H
#define HEADER1_H

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#endif

source.cxx

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "header.h"  // oops, preprocessor gets excited because of redefs

一个简单的解决方案是在生成文件后在 config.h.in 中进行标准的唯一换行。但是,我想知道,有没有更好的方法来处理这个问题?我不是第一个遇到这个问题的人,在 configure.ac 中甚至可能有处理它的方法,但作为这方面的新手,我什至不知道要搜索什么。

我这样做的方法确实是创建一个包装文件(我通常称之为 global.h),内容如下。

#ifndef MY_PROJECT_GLOBAL_H
#define MY_PROJECT_GLOBAL_H

#include <config.h>

/* Maybe other global definitions… */

#endif

请注意,#include config.h 文件的 recommended 方式是通过 <config.h> 而不是 "config.h",因此它与 VPATH 一起使用效果更好构建。

然后,我项目中的所有 source 文件 #include 这个 global.h header 作为它们的第一个 #include 和不关心 config.hheader 文件不应该 #include config.h 因为这会导致错误的名称冲突。实际上,如果你坚持这个准则,你的代码也应该在配置 header.

中没有 #include 守卫的情况下工作

关于 OP 评论的更新

或者:如何在header秒内使用配置结果?

如果您的 header 需要根据 configure 脚本的结果声明不同的内容,您有多种选择,其中 none 是完美的。

对于内部headers,没有问题。他们只是依赖于 #defined 而没有 #includeing 任何东西的宏。如果——按照建议——所有源文件#include(可能如上所示间接)config.hbefore任何其他header.

如果要 public 只安装 header,这不是一个很好的解决方案。对于那些使用 Autoconf 的用户来说,这并没有那么糟糕,尽管即使是那些用户也必须记住要在他们的 configure.ac 文件中放置什么检查。对于不使用 Autoconf 的用户来说,这将是非常糟糕的。如果您只有几个开关(例如 Glibc's fature test macros),可以在 #include 使用您的 header 之前要求您的用户 #define 它们,但是如果您需要很多, 这不是一个真正的选择。更不用说您将以这种方式向用户公开大量实施细节。

如果您需要做的只是根据您正在构建的平台进行分支,您可以探测一些 pre-defined 宏,例如 __linux_WIN32Boost.Predef 库旨在通过提供 higher-level 抽象来使这些检查更加方便。该库适用于 C 和 C++,当然,它会为您的项目增加额外的依赖性。

最后,您可以制作一个使用特定于您的项目的宏前缀的 config.h 版本。 Autoconf 宏存档中有 a contribution 可以为您做这些。一个最小的例子看起来像这样。

AC_PREREQ([2.69])
AC_INIT([example-project], [1.0], [bugs@example.org])
AC_CONFIG_SRCDIR([example.c])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
AX_PREFIX_CONFIG_H([public_config.h], [EXAMPLE_PROJECT], [config.h])
AC_PROG_CC
AC_OUTPUT

将其保存为 configure.acdownload ax_prefix_config_h.m4 from the Autoconf macro archive 并将其放入 sub-directory m4 然后 运行 autoreconf && ./configure。它将创建正常的 config.h 和另外的 public_config.h,在后一个文件中,所有宏都以 EXAMPLE_PROJECT_ 为前缀。如果需要,可以安装文件 public_config.h(顺便说一句,它也有 #include 守卫)并 #included 在项目的 public header 文件中。

使用 autoheader,您可以将 header 和拖车样板代码添加到 config.h

https://www.gnu.org/software/autoconf/manual/autoconf-2.60/html_node/Autoheader-Macros.html

例如,将以下内容添加到您的 configure.ac

#
# Add include guards to config.h
#
AH_TOP([
#ifndef __CONFIG_H_INCLUDE_GUARD
#define __CONFIG_H_INCLUDE_GUARD
])

AH_BOTTOM([
#endif
])