如何在 Meson 中执行 X?

此页面列出了常见任务的代码片段。这些代码片段主要使用 C 编译器编写,但相同的方法应该适用于几乎所有其他编译器。

设置编译器

首次运行 Meson 时,将其设置为环境变量。

$ CC=mycc meson <options>

请注意,在交叉编译中,像 CC 这样的环境变量只引用主机平台。也就是说,CC 指的是用于编译最终安装项目的机器上运行的程序的编译器。用于构建在构建机器上运行的程序的编译器可以使用 CC_FOR_BUILD 指定。你可以在交叉编译中使用它。

请注意,环境变量从来都不是使用 Meson 的习惯方式。最好使用本地文件和交叉文件。在交叉编译中,主机平台的工具只能用交叉文件指定。

这里有一个支持的所有环境变量的表格 在这里

设置链接器

新功能:0.53.0

与编译器类似,链接器是通过 <compiler variable>_LD 环境变量或通过本地文件或交叉文件中的 <compiler entry>_ld 条目来选择的。你必须注意你是使用一个自己调用链接器的编译器(大多数编译器,包括 GCC 和 Clang),还是一个直接调用的链接器(在使用 MSVC 或像 MSVC 那样的编译器(包括 Clang-Cl)时)。对于前者,c_ldCC_LD 应该是传递给编译器特殊参数的值(比如 clang 和 gcc 中的 -fuse-ld),而对于后者,它应该是一个可执行文件,比如 lld-link.exe

注意 在 Meson 0.53.0 中,交叉/本地文件中的 ld 条目和 LD 环境变量被使用,这导致了大量的回归,并在 0.53.1 中更改为 <lang>_ld<comp variable>_LD

$ CC=clang CC_LD=lld meson <options>

或者

$ CC=clang-cl CC_LD=link meson <options>

或在交叉文件或本地文件中

[binaries]
c = 'clang'
c_ld = 'lld'

这里有一个支持的所有环境变量的表格 在这里

设置默认的 C/C++ 语言版本

project('myproj', 'c', 'cpp',
        default_options : ['c_std=c11', 'cpp_std=c++11'])

语言版本也可以在每个目标的基础上设置。

executable(..., override_options : ['c_std=c11'])

启用线程

很多人似乎通过 cc.find_library('pthread') 或类似的方法手动执行此操作。不要这样做。它不可移植。相反,请这样做。

thread_dep = dependency('threads')
executable(..., dependencies : thread_dep)

从外部设置额外的编译器和链接器标志(例如,在构建发行版包时)

该行为与其他构建系统相同,在第一次调用时使用环境变量。当你需要重新构建源代码时,不要使用它们。

$ CFLAGS=-fsomething LDFLAGS=-Wl,--linker-flag meson <options>

仅对特定编译器使用参数

首先检查要使用的参数。

if meson.get_compiler('c').get_id() == 'clang'
  extra_args = ['-fclang-flag']
else
  extra_args = []
endif

然后在目标中使用它。

executable(..., c_args : extra_args)

如果你想在所有目标上使用这些参数,那么请这样做。

if meson.get_compiler('c').get_id() == 'clang'
  add_global_arguments('-fclang-flag', language : 'c')
endif

将命令的输出设置为配置

txt = run_command('script', 'argument', check: true).stdout().strip()
cdata = configuration_data()
cdata.set('SOMETHING', txt)
configure_file(...)

从文件生成配置数据

fs 模块 提供了 read 函数,它支持将任意文件的内容添加到配置数据(以及其他用途)

fs = import('fs')
cdata = configuration_data()
copyright = fs.read('LICENSE')
cdata.set('COPYRIGHT', copyright)
if build_machine.system() == 'linux'
    os_release = fs.read('/etc/os-release')
    cdata.set('LINUX_BUILDER', os_release)
endif
configure_file(...)

使用 configure_file 生成可运行的脚本

configure_file 保留元数据,因此,如果你的模板文件具有执行权限,则生成的也将具有执行权限。

生成覆盖率报告

首先使用以下命令初始化构建目录。

$ meson setup <other flags> -Db_coverage=true

然后发出以下命令。

$ meson compile
$ meson test
$ ninja coverage-html (or coverage-xml)

覆盖率报告可以在 meson-logs 子目录中找到。

新功能:0.55.0 llvm-cov 支持与 clang 一起使用

在调试版本中添加一些优化

默认情况下,调试版本不使用任何优化。这通常是理想的方法。但是,某些项目从启用一些次要优化中受益。GCC 甚至为此有一个特定的编译器标志 -Og。要启用其使用,只需发出以下命令。

$ meson configure -Dc_args=-Og

这会导致所有后续构建都使用此命令行参数。

使用地址清理器

Clang 和 gcc 附带了一系列分析工具,比如 地址清理器。Meson 通过 b_sanitize 选项原生支持这些工具。

$ meson setup <other options> -Db_sanitize=address

之后,只需编译代码并运行测试套件。地址清理器将中止具有错误的可执行文件,因此它们会显示为测试失败。

使用 Clang 静态分析器

安装 scan-build 程序,然后执行以下操作

$ meson setup builddir
$ ninja -C builddir scan-build

你可以使用 SCANBUILD 环境变量来选择 scan-build 可执行文件。

$ SCANBUILD=<your exe> ninja -C builddir scan-build

你可以通过创建一个脚本(例如)来使用它传递参数给 scan-build 程序

#!/bin/sh
scan-build -v --status-bugs "$@"

然后通过变量传递它(记住使用绝对路径)

$ SCANBUILD=$(pwd)/my-scan-build.sh ninja -C builddir scan-build

使用配置文件引导的优化

使用 GCC 进行配置文件引导的优化是一个两阶段操作。首先,我们使用启用了配置文件测量功能的项目设置来编译它。

$ meson setup <Meson options, such as --buildtype=debugoptimized> -Db_pgo=generate
$ meson compile -C builddir

然后,我们需要使用一些具有代表性的输入来运行程序。此步骤取决于你的项目。

完成后,我们更改编译器标志以使用生成的信息并重新构建。

$ meson configure -Db_pgo=use
$ meson compile

经过这些步骤后,生成的二进制文件将得到完全优化。

添加数学库 (-lm) 可移植性

某些平台(例如 Linux)具有独立的数学库。其他平台(几乎所有其他平台)都没有。如何指定 m 仅在需要时使用?

cc = meson.get_compiler('c')
m_dep = cc.find_library('m', required : false)
executable(..., dependencies : m_dep)

将可执行文件安装到 libexecdir

executable(..., install : true, install_dir : get_option('libexecdir'))

使用现有的 Find<name>.cmake 文件

如果安装了 CMake,Meson 可以使用 CMake 的 find_package() 生态系统。要使用自定义 Find<name>.cmake 查找依赖项,请将 cmake_module_path 属性设置为项目中存储 CMake 脚本的路径。

cmake 子目录中 FindCmakeOnlyDep.cmake 的示例

cm_dep = dependency('CmakeOnlyDep', cmake_module_path : 'cmake')

cmake_module_path 属性仅适用于自定义 CMake 脚本。系统范围内的 CMake 脚本会自动被找到。

更多信息可以在这里找到 这里

获取默认的未找到依赖项?

null_dep = dependency('', required : false)

这可以在你想要默认值但可能稍后覆盖它的情况下使用。

# Not needed on Windows!
my_dep = dependency('', required : false)
if host_machine.system() in ['freebsd', 'netbsd', 'openbsd', 'dragonfly']
  my_dep = dependency('some dep', required : false)
elif host_machine.system() == 'linux'
  my_dep = dependency('some other dep', required : false)
endif

executable(
  'myexe',
  my_sources,
  deps : [my_dep]
)

从 unity 构建中排除文件

如果你的项目支持 unity 构建,你应该修复在源文件连接在一起时出现的任何错误。但是,有时这是不可能的,例如,如果源文件是生成的。

在这种情况下,你可以将它们放在一个单独的静态库构建目标中,并覆盖 unity 设置。

generated_files = ...
unityproof_lib = static_library('unityproof', generated_files,
  override_options : ['unity=off'])

main_exe = executable('main', main_sources, link_with : unityproof_lib)

要将静态库链接到另一个库目标,你可能需要使用 link_whole 而不是 link_with

搜索结果为