编译器属性

并非所有编译器和平台都相同。因此,Meson 提供了在配置时检测系统属性的工具。要获取大部分信息,您首先需要从主 meson 变量中提取编译器对象

compiler = meson.get_compiler('c')

这里我们提取了 C 编译器。我们也可以使用 cpp 参数获取 C++ 编译器,使用 objc 获取 Objective C 编译器,等等。该调用对 project 声明中指定的所有语言都有效。尝试获取其他编译器将导致不可恢复的错误。

系统信息

这有点复杂,在有关交叉编译的页面上有更详细的解释。但是,如果您只是想知道代码将运行的操作系统,请发出以下命令

host_machine.system()

编译器 ID

编译器对象方法 compiler.get_id() 返回一个描述编译器“家族”的小写字符串。自 0.53.0 版本起,compiler.get_linker_id() 返回一个包含链接器名称的小写字符串。由于编译器通常可以根据操作系统从多个链接器中进行选择,因此 get_linker_id 对处理或减轻特定链接器影响很有用。

编译器对象还具有一个方法 compiler.get_argument_syntax(),它返回一个 gccmsvc 或其他未定义的字符串值的小写字符串;标识编译器参数是否使用与 gccmsvc 相同的语法,或者其参数与两者都不一样。这仅应用于选择参数的语法,例如那些使用 compiler.has_argument() 测试的参数。

有关支持的编译器 ID 及其参数类型的列表,请参见参考表

代码是否编译?

有时测试系统的唯一方法是尝试编译一些示例代码,看看它是否有效。例如,这可以测试“C++17”编译器是否真正支持特定的 C++17 功能,而无需依赖于维护功能列表与编译器供应商、编译器版本和操作系统的对应关系。测试代码片段是否运行是一个两阶段操作。首先,我们使用多行字符串运算符定义一些代码

code = '''#include<stdio.h>
void func() { printf("Compile me.\n"); }
'''

然后我们可以运行测试。

result = compiler.compiles(code, name : 'basic check')

现在,result 变量将包含 truefalse,具体取决于编译是否成功。关键字参数 name 是可选的。如果指定了它,Meson 将将其检查结果写入其日志。

有时有必要检查某些代码片段不仅编译成功,而且链接成功,例如,检查某个符号是否确实存在于库中。这可以使用 compiler.links() 方法完成,如下所示

code = '''#include<stdio.h>
void func() { printf("Compile me.\n"); }
'''

然后我们可以运行测试。

result = compiler.links(code, args : '-lfoo', name : 'link check')

现在,result 变量将包含 truefalse,具体取决于编译和链接是否成功。关键字参数 name 是可选的。如果指定了它,Meson 将将其检查结果写入其日志。

编译并运行测试应用程序

以下是如何编译和运行小型测试应用程序。测试代码片段是否运行,而不是仅仅测试它是否链接,这对于某些依赖项(如 MPI)尤为重要。

code = '''#include<stdio.h>
int main(int argc, char **argv) {
  printf("%s\n", "stdout");
  fprintf(stderr, "%s\n", "stderr");
  return 0;
}
'''
result = compiler.run(code, name : 'basic check')

result 变量封装了测试的状态,可以使用以下方法提取。name 关键字参数的作用与 compiles 相同。

方法 返回值
compiled 如果编译成功,则为 True。如果为 false,则所有其他方法返回未定义的值。
returncode 应用程序的返回代码(整数)
stdout 程序的标准输出(文本)。
stderr 程序的标准错误(文本)。

以下是一个使用示例

if result.stdout().strip() == 'some_value'
  # do something
endif

头文件是否存在?

不同平台提供的头文件差异很大。Meson 具有检测系统上是否存在给定头文件的功能。测试是通过尝试编译一个包含指定头文件的简单测试程序来完成的。以下代码段描述了如何使用此功能。

if compiler.has_header('sys/fstat.h')
  # header exists, do something
endif

表达式大小

通常您需要确定特定元素的大小(例如 intwchar_tchar*)。使用上面提到的 compiler 变量,可以使用以下方法进行检查。

wcharsize = compiler.sizeof('wchar_t', prefix : '#include<wchar.h>')

这将把 sizeof 报告的 wchar_t 大小放入 wcharsize 变量中。关键字参数 prefix 是可选的。如果指定了它,其内容将放在源文件顶部。此参数通常用于在配置文件中设置 #include 指令。

在旧版本(<= 0.30)中,如果无法确定大小,Meson 会出错。从 0.31 版本开始,如果无法确定大小,它会返回 -1。

函数是否存在?

仅仅存在头文件并不能说明其内容。有时您需要显式检查某个函数是否存在。以下是检查头文件 stdio.h 中是否包含函数 open_memstream 的方法

if compiler.has_function('open_memstream', prefix : '#include <stdio.h>')
  # function exists, do whatever is required.
endif

请注意,在 macOS 上,程序可以编译为针对比编译程序的 macOS 版本更旧的 macOS 版本。不能假设编译所在的操作系统版本与二进制文件将运行的操作系统版本相同。

因此,在使用 compiler.has_function() 检测函数可用性时,务必在 prefix 参数中指定正确头文件。

在上面的示例中,检测到了函数 open_memstream,该函数是在 macOS 10.13 中引入的。当用户在 macOS 10.13 上构建,但目标为 macOS 10.11(-mmacosx-version-min=10.11)时,这将正确报告该函数不存在。但是,如果没有头文件,它将缺乏必要的可用性信息,并错误地报告该函数可用。

结构体是否包含成员?

一些平台具有不同的标准结构体。以下是检查头文件 myheader.h 中名为 mystruct 的结构体是否包含名为 some_member 的成员的方法。

if compiler.has_member('struct mystruct', 'some_member', prefix : '#include<myheader.h>')
  # member exists, do whatever is required
endif

类型对齐

大多数平台不能在任何地址访问某些数据类型。例如,通常情况下,char 可以位于任何地址,但 32 位整数只能位于可被 4 整除的地址处。确定数据类型的对齐方式很简单。

int_alignment = compiler.alignment('int') # Will most likely contain the value 4.

是否有参数

此方法测试编译器是否支持给定的命令行参数。这是通过使用给定参数编译一个小文件来实现的。

has_special_flags = compiler.has_argument('-Wspecialthing')

注意:一些编译器会静默地忽略它们不理解的命令行参数。因此,此测试无法做到 100% 可靠。

搜索结果为