编译时配置

库编译时配置

C++ 预处理器迭代器库可以通过在编译时指定不同的预处理器常量,来配置不同的附加功能。下表描述了可能的预处理器常量。

库配置可能的
预处理器常量摘要
BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE

支持 #warning 指令

BOOST_WAVE_SUPPORT_MS_EXTENSIONS

支持多种微软特有的语言扩展(即__int8等等)

BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY

启用对 #error#warning 指令消息体的预处理。

BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES

如果已定义,则 #pragma 指令将作为记号序列(token sequence)返回给调用者;如果未定义,则跳过整个 #pragma 指令。

BOOST_WAVE_PREPROCESS_PRAGMA_BODY

启用对所有 #pragma 指令体的预处理。
但请注意,operator _Pragma()的主体始终会被预处理,因为这是 C99 标准 [2] 的要求。

BOOST_WAVE_ENABLE_COMMANDLINE_MACROS

启用使用命令行语法(-DMACRO(x)=definition)定义宏所需的功能

BOOST_WAVE_STRINGTYPE

Wave库生成的记号(token)包含记号数据以及在输入流中发现该记号的文件位置。
该常量可用于重新定义用于保存记号数据和相应文件名的参数类型。如果未定义,则默认为 std::string。(此处定义的数据类型应与 std::string 类型兼容)

BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS

如果已定义,则预处理器库支持变长参数(variadics)和占位符(placemarkers)。注意,为了支持 C99 模式,也必须定义此常量。

BOOST_WAVE_SUPPORT_CPP0X

如果已定义,则预处理器库支持 C++0x 关键字和 C++0x 特有功能,如变长参数、占位符、扩展字符和字符串字面量。这隐含了对 BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS 常量的定义。

BOOST_WAVE_SUPPORT_CPP1Z

如果已定义,则预处理器库支持 C++17 关键字——目前仅为 __has_include。它隐含了 BOOST_WAVE_SUPPORT_CPP0X

BOOST_WAVE_SUPPORT_CPP2A

如果已定义,则预处理器库支持 C++20 关键字,特别是 __VA_OPT__。它隐含了 BOOST_WAVE_SUPPORT_CPP1Z

BOOST_WAVE_MAX_INCLUDE_LEVEL_DEPTH

如果已定义,它将确定支持的初始最大可能包含文件嵌套深度。默认值为 1024。

BOOST_WAVE_SUPPORT_PRAGMA_ONCE

如果已定义,则支持 #pragma once 指令,由Wave提供。这指定了该 pragma 所在的文件在一次构建中只能被编译器包含(打开)一次。

BOOST_WAVE_SUPPORT_PRAGMA_MESSAGE

如果已定义,则支持 #pragma message("") 指令,由Wave提供。该 pragma 仅生成包含消息文本的备注。只要同时定义了 BOOST_WAVE_PREPROCESS_PRAGMA_BODY 常量,就会对 #pragma message 的主体进行预处理。

BOOST_WAVE_SUPPORT_INCLUDE_NEXT

如果已定义,则支持 #include_next 指令,由Wave提供。这在语法上等同于 #include 指令,但可用于继承头文件(即包含一个与当前包含 #include_next 的文件同名的文件)。

BOOST_WAVE_USE_STRICT_LEXER

如果将其定义为非 0 值,则 C/C++ 词法分析器将识别严格的 C99/C++ 基本源字符集。如果未定义或定义为零,则词法分析器会将 '$' 字符识别为标识符的一部分。

BOOST_WAVE_PRAGMA_KEYWORD

如果将其定义为字符串字面量,它将用作库识别为特定 Wave pragma 的 pragma 关键字。此常量默认为 "wave",即库识别所有 #pragma wave option [(argument)] 指令,并将处理调度给 interpret_pragma() 预处理钩子函数(见:Preprocessing Hooks)。pragma 的参数部分是可选的。

BOOST_WAVE_SUPPORT_LONGLONG_INTEGER_LITERALS

C++ 标准要求预处理器对整数字面量使用以下类型之一:longunsigned long,具体取决于可选后缀('u''l''ul''lu')。有时需要预处理比这更大的整数字面量(即 long longunsigned long long)。定义此预处理器常量可启用对 long long 整数的识别,即使它们没有 'll' 后缀。

仅当您的目标平台支持 long long 整数(定义了 BOOST_HAS_LONG_LONG)时,此预处理器常量才有效。请注意,此设置与 Wave 支持选项 support_option_long_long 无关,后者仅启用对 'll' 后缀的识别。

BOOST_WAVE_SUPPORT_THREADING

此预处理器常量允许配置 Wave 库在构建时是否启用多线程支持。如果需要禁用多线程,应将此值(如果已定义)设置为零 ('0');如果要显式启用多线程,应将其设置为不等于零的数值。

如果未定义此常量,Wave 库将使用从 Boost 构建环境中提取的多线程设置进行构建(参见 Boost 配置文档中的 BOOST_HAS_THREADS)。

在 Wave 中使用不同的记号类型或词法分析器类型

可以在使用您自己的记号和/或词法分析器类型的同时使用Wave库。这可以通过在实例化boost::wave::context<>对象时提供您的词法分析器类型作为第二个模板参数来实现。库使用的记号类型派生自定义的公共类型定义由词法分析器类型提供的 typedef。如果您只想提供自己的记号类型,可以使用boost::wave::lex_iterator<>库中包含的类型。该类型需要以要使用的记号类型作为参数。

Wave库包含几个说明这些可能性的示例。cpp_tokens示例展示了自定义词法分析器和自定义记号类型的用法。所使用的词法分析器类型在功能上完全兼容于默认使用的基于re2c [3] 的词法分析器。它是基于由 Dan Nuffer 编写的SLex [5] 词法分析器示例实现的。其中使用的记号类型在功能上等同于默认记号类型,只是增加了一个额外的operator<<用于转储记号携带的信息。

分离式和包含式编译模型

WaveC++ 预处理器迭代器库几乎完全作为仅头文件库构建(除了基于 re2c 的词法分析器)。如果您尝试一次性包含所有必需的文件,您会发现生成的编译时间非常长(取决于您的系统配置,可能长达一小时)。这种直接的方法我们称之为包含编译模型。如果您不关心编译时间,这就是可行的方法,不需要特殊处理。

如果您有兴趣缩短编译时间,则应使用以下方法。我们将其称为分离编译模型。诀窍是将不同的对象分开,使它们可以分别编译。将实例化相关模板对象的函数分解出来,使其定义仅对一个编译单元可见。为了进一步简化,此创建函数被包装在一个小的生成器模板结构中。

实现了两个层次的分离:C++ 词法分析器编译的分离以及所使用的不同 Spirit 语法编译的分离。要使用这些分离,您必须在编译整个应用程序时定义两个预处理器常量,并且必须显式实例化一些辅助模板。下表详细列出了这些常量。

启用分离编译模型可能需要的
编译常量摘要
分离项

预处理器常量

C++ 词法分析器

BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION

Spirit 语法

BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION

下表显示了如果要使用分离编译模型所需的显式模板实例化。其中的TokenT占位符类型必须替换为您要使用的记号类型,而 LexIteratorT 占位符类型必须替换为您在实例化boost::wave::context<>对象时使用的词法迭代器类型。如果将这些分别放入单独的编译单元中,您将获得最佳效果。其中的IteratorT占位符应替换为用于实例化boost::wave::context<>对象中的边描述符。

使用分离编译模型时
所需的显式模板实例化摘要
分离项

需要显式实例化的模板

C++ 词法分析器 template cpplexer::re2clex::new_lexer_gen<IteratorT>;
Spirit 语法

template wave::grammars::expression_grammar_gen<TokenT>;
template wave::grammars::intlit_grammar_gen<TokenT>;
template wave::grammars::chlit_grammar_gen<TokenT>;
template wave::grammars::cpp_grammar_gen<LexIteratorT>;
template wave::grammars::predefined_macros_grammar_gen<LexIteratorT>;
template wave::grammars::defined_grammar_gen<LexIteratorT>;

要查看这方面的示例,您可以查看Wave作为 C++ 预处理器迭代器库附带示例包含的驱动程序。相应的文件命名显然为 "instantiate_...something.cpp",其中 '...somthing' 是一个提示,说明内部显式实例化了哪些语法。通过使用分离模型,构建Wave示例所需的编译时间减少了多达 90%。

编译器要求

从 1.77 版本开始,Wave 将要求使用 C++11 特性进行构建,并且将不再支持旧编译器。然而,Wave 将无限期地继续模拟旧预处理器的特性。