确保 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.h
。 header 文件不应该 #include
config.h
因为这会导致错误的名称冲突。实际上,如果你坚持这个准则,你的代码也应该在配置 header.
中没有 #include
守卫的情况下工作
关于 OP 评论的更新
或者:如何在header秒内使用配置结果?
如果您的 header 需要根据 configure
脚本的结果声明不同的内容,您有多种选择,其中 none 是完美的。
对于内部headers,没有问题。他们只是依赖于 #define
d 而没有 #include
ing 任何东西的宏。如果——按照建议——所有源文件#include
(可能如上所示间接)config.h
before任何其他header.
如果要 public 只安装 header,这不是一个很好的解决方案。对于那些使用 Autoconf 的用户来说,这并没有那么糟糕,尽管即使是那些用户也必须记住要在他们的 configure.ac
文件中放置什么检查。对于不使用 Autoconf 的用户来说,这将是非常糟糕的。如果您只有几个开关(例如 Glibc's fature test macros),可以在 #include
使用您的 header 之前要求您的用户 #define
它们,但是如果您需要很多, 这不是一个真正的选择。更不用说您将以这种方式向用户公开大量实施细节。
如果您需要做的只是根据您正在构建的平台进行分支,您可以探测一些 pre-defined 宏,例如 __linux
或 _WIN32
。 Boost.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.ac
、download 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
守卫)并 #include
d 在项目的 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
])
我有一个库项目,我正在努力移植到 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.h
。 header 文件不应该 #include
config.h
因为这会导致错误的名称冲突。实际上,如果你坚持这个准则,你的代码也应该在配置 header.
#include
守卫的情况下工作
关于 OP 评论的更新
或者:如何在header秒内使用配置结果?
如果您的 header 需要根据 configure
脚本的结果声明不同的内容,您有多种选择,其中 none 是完美的。
对于内部headers,没有问题。他们只是依赖于 #define
d 而没有 #include
ing 任何东西的宏。如果——按照建议——所有源文件#include
(可能如上所示间接)config.h
before任何其他header.
如果要 public 只安装 header,这不是一个很好的解决方案。对于那些使用 Autoconf 的用户来说,这并没有那么糟糕,尽管即使是那些用户也必须记住要在他们的 configure.ac
文件中放置什么检查。对于不使用 Autoconf 的用户来说,这将是非常糟糕的。如果您只有几个开关(例如 Glibc's fature test macros),可以在 #include
使用您的 header 之前要求您的用户 #define
它们,但是如果您需要很多, 这不是一个真正的选择。更不用说您将以这种方式向用户公开大量实施细节。
如果您需要做的只是根据您正在构建的平台进行分支,您可以探测一些 pre-defined 宏,例如 __linux
或 _WIN32
。 Boost.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.ac
、download 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
守卫)并 #include
d 在项目的 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
])