☰
Meson 0.40.0 版本新特性全解析:从 VS2017 支持到依赖获取方法定制
2026/10/8 7:54:50 网站建设 项目流程
  • 构建工具

【免费下载链接】meson

The Meson Build System

项目地址:https://gitcode.com/gh_mirrors/me/meson
点击查看免费下载

导读

本文基于 Meson 构建系统 0.40.0 版本的官方发布说明(docs/markdown/Release-notes-for-0.40.0.md),系统梳理该版本引入的核心新特性,并结合当前仓库源码逐一验证底层实现。阅读本文后,你将掌握:如何在 Visual Studio 后端使用生成器输出、用compute_int与get_define在配置期求值、用wrap-mode控制依赖下载、用override_options按目标覆盖全局选项、用link_whole整库链接、按输出分别指定安装目录,以及如何为依赖显式指定获取方法等实战能力。


一、生成器输出可用于 VS 后端的 custom target

在 Ninja 后端中,生成器(generator)产生的输出早已可以作为自定义目标(custom target)的输入使用。0.40.0 将这一能力扩展到了 Visual Studio 后端,现在两种后端行为一致。这意味着使用--backend=vs2017、--backend=vs2019等 VS 系列后端构建项目时,custom_target()可以放心地引用generator.process()生成的中间文件,不再受后端差异限制。

从源码结构看,各 VS 后端统一继承自 vs2010backend.py 中的Vs2010Backend基类,后续的 VS2012/2013/2015/2017/2019/2022/2026 后端(见该文件 L47-L70)都复用同一套生成器与自定义目标处理逻辑,因此该特性对所有 VS 版本后端同时生效。

二、编译器对象的compute_int方法

0.40.0 为编译器对象新增了compute_int()方法,用于在配置期直接计算一个 C/C++(或 Fortran)表达式的整数值:

cc = meson.get_compiler('c') two = cc.compute_int('1 + 1') # A very slow way of adding two numbers.

底层实现原理

从源码看,该方法的基类声明位于 mesonbuild/compilers/compilers.py,而 C 系编译器的实际实现在 mesonbuild/compilers/mixins/clike.py:Meson 会生成一段包含<stddef.h>与<stdio.h>的 C 测试程序,用printf("%ld\n", (long)(<expression>))输出表达式求值结果,再解析程序输出得到整数值。Fortran 编译器(mesonbuild/compilers/fortran.py)则生成program test并用print '(i0)', <expression>输出。因此compute_int实际执行的是"编译并运行一小段代码",而非纯语法解析——这正是文档注释中"一种非常慢的加法"的由来。

该方法常用于在配置期推导平台相关的常量,例如cc.compute_int('sizeof(void*)')或架构位宽判断。

三、Visual Studio 2017 支持与通用 VS 后端

0.40.0 带来了两项后端能力:

  • 专门的--backend=vs2017;
  • 通用的--backend=vs,自动探测当前环境中激活的 VS 版本。

通用后端的版本分派逻辑体现在 vs2010backend.py:依次尝试导入Vs2012Backend、Vs2013Backend、Vs2015Backend、Vs2017Backend、Vs2019Backend、Vs2022Backend、Vs2026Backend,并返回首个可用的后端类。这使得用户无需关心本机安装的具体 VS 版本,一条命令即可完成工程文件生成。

四、git submodule 子项目的自动初始化

如果subprojects/目录下的某个子目录是 git submodule,且构建文件引用了它,Meson 会自动初始化该 submodule——无需提供 wrap 文件,因为 git 本身已包含全部所需信息。

源码级验证

该逻辑实现在 mesonbuild/wrap/wrap.py 的resolve_git_submodule()中,具体判断流程为:

  1. 检查 git 是否安装(GIT变量),并确认目录存在;
  2. 通过git rev-parse确认处于 git 仓库中;
  3. 用git submodule status .查询 submodule 状态:
    • 前缀+:submodule 可能已过期(输出警告但仍继续);
    • 前缀U:存在合并冲突,直接抛出异常;
    • 前缀-:未初始化,自动执行git submodule update --init .;
    • 前缀 :已初始化但内容可能不完整,执行git submodule update .与git checkout .补齐;
    • 空输出:普通目录而非 submodule,返回 false。

该机制由WrapResolver在解析子项目时自动调用(见 wrap.py),对用户完全透明。

五、Wrap 的"禁止下载"模式(wrap-mode)

对于发行版打包者和需要严格禁止配置/构建期间联网的场景,0.40.0 新增了wrap-mode选项:

meson setup builddir --wrap-mode=nodownload

当设置为nodownload后,任何尝试下载依赖项目的操作都会直接报错。

全部取值与语义

从 mesonbuild/wrap/init.py 中WrapMode枚举及其注释可以看到完整的模式语义:

取值含义
default默认行为:允许下载
nofallback禁止为dependency(..., fallback: ...)下载 wrap(不执行回退下载)
nodownload禁止所有subproject()调用的下载,包括 fallback(即既不下载也不回退)
forcefallback忽略系统提供的依赖,强制使用 fallback
nopromote不自动提升子项目为 copylib

注释还给出了选型建议:从 release 源码包构建时,上游通常已附带全部源码,可安全使用nodownload;从 git 仓库构建时则建议使用nofallback,以便 copylib 类 wrap 仍能按需下载。执行层面,wrap.py 在WrapMode.nodownload下直接抛出"Automatic wrap-based subproject downloading is disabled"错误。另外注意:wrap-mode不影响 git submodule 形式的子项目——注释明确说明这些 submodule 仅在 git 仓库中可用,几乎总是应当被下载(相关判断见 mesonbuild/wrap/wrap.py 上方逻辑)。

六、按目标覆盖选项:override_options

构建目标新增了override_options关键字参数,允许针对单个目标覆盖 Meson 内置选项。例如某个目标已知无法在-Werror下编译,可以这样做:

executable('foo', 'foo.c', override_options : ['werror=false'])

需要特别注意的是:它只影响来自 Meson 自身的选项(语言标准、unity 构建等),不影响项目自定义选项(即在meson_options.txt中定义的 option)。

从实现看,override_options贯穿解释层与后端:其类型定义与校验位于 mesonbuild/interpreter/type_checking.py 与 mesonbuild/interpreter/kwargs.py,目标对象在 mesonbuild/build.py 中保存覆盖值,而后端在展开编译参数时(例如 mesonbuild/backend/backends.py 的选项读取路径)会优先采用目标级覆盖结果,从而实现"全局配置 + 目标级豁免"的灵活组合。

七、编译器对象get_define方法

get_define()返回指定预处理宏的字符串值:

cc = meson.get_compiler('c') one = cc.get_define('__linux__') # 在 Linux 主机上返回 '1'

如果宏未定义,则返回None。该方法对跨平台特性探测非常实用——例如在配置期区分_WIN32、__APPLE__等平台宏。

实现细节

实现在 mesonbuild/compilers/mixins/clike.py:Meson 生成如下预处理代码,用两个特殊分隔符夹住目标宏:

#define MESON_GET_DEFINE_DELIMITER_START #ifdef __linux__ # define __linux__ MESON_GET_DEFINE_UNDEFINED_SENTINEL #endif "MESON_GET_DEFINE_DELIMITER_START"__linux__"MESON_GET_DEFINE_DELIMITER_END"

以CompileCheckMode.PREPROCESS模式交给编译器预处理,再解析分隔符之间的文本即为宏值。注意代码中先用#ifndef ... #define <dname> MESON_GET_DEFINE_UNDEFINED_SENTINEL兜底,未定义宏会落入哨兵值并被识别为None。同时该方法支持结果缓存(disable_cache参数)与extra_args/dependencies参数,保证与其他编译器检测函数一致的接口风格。基类声明见 mesonbuild/compilers/compilers.py。

八、Cygwin 支持

0.40.0 起 Meson 可在 Cygwin 环境下正常工作,并已加入 CI 测试矩阵(见仓库 ci 目录下的持续集成配置)。这意味着在 Windows 上通过 Cygwin 使用 POSIX 风格工具链的开发者,可以直接用 Meson 构建项目。

九、多个安装目录:按输出分别指定

此前 custom target 的多个输出只能安装到同一目录。0.40.0 起,可以为每个输出分别指定安装目录:

custom_target('two_out', output : ['diff.h', 'diff.sh'], command : [creator, '@OUTDIR@'], install : true, install_dir : ['dir1', 'dir2'])
  • 输出列表与install_dir列表按位置一一对应;
  • 为了向后兼容与简洁,若只指定一个目录,则所有输出都安装到该目录;
  • 该特性在源码中以FeatureNew标注自 0.40.0 引入,见 mesonbuild/interpreter/interpreter.py。

Vala 目标的扩展用法

同一能力也适用于 Vala 构建目标。例如把 valac 构建的共享库、生成的头文件和生成的 VAPI 分别安装到默认位置:

shared_library('valalib', 'mylib.vala', install : true, install_dir : [true, true, true])

规则为:true表示安装到该类型的默认目录,字符串表示安装到自定义目录,false表示不安装。三个元素分别对应共享库、生成头文件与生成 VAPI。若像旧版那样只传一个字符串,则只会安装库本身——这是一个完全向后兼容的变更。

十、显式指定依赖获取方法(method关键字)

某些依赖有多种提供方式,例如 Qt 既可以通过pkg-config检测,也可以通过qmake检测。此前 Meson 依靠启发式算法选择,偶尔会选错。0.40.0 起可用method关键字显式指定:

qt5_dep = dependency('qt5', modules : 'core', method : 'qmake')

method的取值由DependencyMethods枚举定义(如auto、pkgconfig、qmake、system、config-tool等),默认值为AUTO,相关解析逻辑见 mesonbuild/dependencies/base.py 与 mesonbuild/dependencies/detect.py。以 Qt 为例,mesonbuild/dependencies/qt.py 中会按指定的qmake路径执行检测,从而精确控制依赖的来源,避免启发式误判。

十一、整库链接:link_whole

静态库的默认链接行为会丢弃未被直接引用的符号,这可能丢失导出符号。多数编译器支持"whole archive"链接,把静态库的全部符号与代码都纳入最终产物。0.40.0 通过link_whole关键字暴露该能力:

shared_library('foo', 'foo.c', link_whole : some_static_library)
  • 可用于将静态库整体并入共享库或可执行文件,典型场景是确保插件/导出符号不丢失;
  • 注意:Visual Studio 编译器仅在 VS2015 及更新版本支持该功能。

后端实现佐证

后端在生成链接命令时专门处理link_whole_targets:

  • Ninja 后端在 mesonbuild/backend/ninjabackend.py 的get_link_whole_args()中收集目标的link_whole_targets,并通过linker.get_link_whole_for()生成平台相关的整库链接参数(例如 GCC/Clang 的-Wl,--whole-archive ... -Wl,--no-whole-archive,MSVC 的/WHOLEARCHIVE);
  • VS 后端在 mesonbuild/backend/vs2010backend.py 中同样将link_whole_targets中的静态库标记为整库链接。

十二、Unity 构建仅用于子项目

此前 unity 构建要么对所有目标生效、要么全部关闭。0.40.0 起可将unity选项设为subprojects,让更新频率低的子项目启用 unity 合并编译,而频繁改动的主项目保持普通编译,从而在享受 unity 构建加速的同时减少主项目变更引发的整体重编译:

meson setup builddir -Dunity=subprojects

该选项的类型定义见 mesonbuild/options.py:UserComboOption('unity', 'Unity build', 'off', choices=['on', 'off', 'subprojects'])。解释器在判断某目标是否采用 unity 编译时,会依据unity == 'subprojects'且目标属于子项目(tobj.subproject != '')来判定,见 mesonbuild/interpreter/interpreterobjects.py。

十三、脚本可用的MESONINTROSPECT环境变量

Meson 运行脚本时,除了设置MESON_SOURCE_ROOT等变量外,现在还会设置MESONINTROSPECT环境变量,保证它指向正确的mesonintrospect脚本——这对于从 git 未安装状态运行 Meson,或PATH配置不正确的情况尤为重要。

具体地,以下 Meson 函数会设置该变量:

  • meson.add_install_script()
  • meson.add_postconf_script()
  • run_command()
  • run_target()

从源码看,该变量在多个执行路径中被注入环境:

  • 后端在生成运行目标命令时设置'MESONINTROSPECT': self.get_introspect_command()(mesonbuild/backend/backends.py);
  • 解释器层在构造脚本执行环境时以shlex.quote转义后写入(mesonbuild/interpreter/interpreterobjects.py);
  • 安装阶段(mesonbuild/minstall.py)同样在meson.add_install_script()执行环境中设置该变量。

因此,自定义脚本内部可以放心地通过os.environ['MESONINTROSPECT']调用 introspection 接口,获取目标的源文件、编译参数等构建信息。


小结

Meson 0.40.0 是一个面向后端完善与配置灵活性的版本:Visual Studio 生态获得了 VS2017 支持、通用vs后端与生成器输出的一致处理;配置期编程能力通过compute_int、get_define得到增强;依赖管理在wrap-mode、method与 git submodule 自动初始化三个维度上更加可控;构建目标层面新增override_options、link_whole、多安装目录与unity=subprojects等实用特性;同时补齐了 Cygwin 支持与MESONINTROSPECT环境变量。上述全部特性在当前仓库源码中均有对应实现可查证,相关代码路径已在各小节中给出,便于读者深入研读。

  • 构建工具

【免费下载链接】meson

The Meson Build System

项目地址:https://gitcode.com/gh_mirrors/me/meson
点击查看免费下载

相关推荐

上一篇:3分钟上手:Webhook.site让HTTP测试变得如此简单
下一篇:RxJavaSample项目实战:如何用响应式编程实现高效的图片加载与处理

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询