如何在包含中使用预处理器宏?

How do I use a preprocessor macro inside an include?

我正在尝试使用我自己的构建系统构建 freetype2(我不想使用 Jam,我准备花时间弄清楚它)。我在 headers 中发现了一些奇怪的东西。 Freetype 定义宏是这样的:

#define FT_CID_H  <freetype/ftcid.h>

然后像这样使用它们:

#include FT_CID_H 

我不认为这是可能的,事实上 Clang 3.9.1 抱怨:

error: expected "FILENAME" or <FILENAME>
#include FT_CID_H

这与 有关,但有所不同,因为这里的问题是关于编译 freetype,而不是编写新代码。

我会不按顺序回答你的三个问题。

Question 2

Is this valid C/C++?

是的,这确实有效。宏扩展可用于生成 #include 指令的最终版本。引用 C++14 (N4140) [cpp.include] 16.2/4:

A preprocessing directive of the form

# include pp-tokens new-line

(that does not match one of the two previous forms) is permitted. The preprocessing tokens after include in the directive are processed just as in normal text (i.e., each identifier currently defined as a macro name is replaced by its replacement list of preprocessing tokens). If the directive resulting after all replacements does not match one of the two previous forms, the behavior is undefined.

提到的"previous forms"是#include "..."#include <...>。所以是的,使用扩展到 header/file 的宏是合法的。

Question 1

What is the rationale behind these macros?

我不知道,因为我从未使用过 freetype2 库。这个问题最好由其支持渠道或社区来回答。

Question 3

How can I convince Clang to parse these headers?

由于这是合法的 C++,因此您无需执行任何操作。事实上,用户@Fanael demonstrated 认为 Clang 能够解析此类代码。一定是你的设置有问题,或者你没有显示的其他问题。

Is this valid C/C++?

该用法在 C 中有效,前提是宏定义在 #include 指令出现的范围内。具体来说,paragraph 6.10.2/4 of C11

A preprocessing directive of the form

# include pp-tokens new-line

(that does not match one of the two previous forms) is permitted. The preprocessing tokens after include in the directive are processed just as in normal text. (Each identifier currently defined as a macro name is replaced by its replacement list of preprocessing tokens.) The directive resulting after all replacements shall match one of the two previous forms.

(强调已添加。)由于预处理器在 C++ 中与在 C 中具有相同的语义,据我所知,该用法在 C++ 中也有效。

What is the rationale behind these macros?

我认为它旨在提供 header 名称或位置的间接访问(通过提供宏的替代定义)。

How can I convince Clang to parse these headers?

再次假设宏定义在 #include 指令出现的范围内,您不必执行任何操作。如果确实如此,那么 Clang 在这方面是有问题的。在那种情况下,在提交错误报告后(如果这个问题还不知道),您可能需要手动扩展麻烦的宏引用。

但在执行此操作之前,请确保宏定义确实在范围内。特别是,它们可能受到条件编译指令的保护——在这种情况下,最好的做法可能是提供满足条件所需的任何宏定义(通过编译器命令行)。如果您希望手动执行此操作,那么构建文档肯定会讨论它。阅读构建说明。