oss

Meson 迁移要到安装树一致才算完成,首次快速构建还不算

13 条来源 10 条一手来源 已翻译 2026年8月10号

正文
Meson 创建者 Jussi Pakkanen 在柏林举行的 All Systems Go! 2017 大会上坐在笔记本电脑后回答提问。

Meson 创建者 Jussi Pakkanen 在柏林 All Systems Go! 2017 大会关于 Linux 构建格局变化的演讲结束后回答提问。画面截取自 media.ccc.de 发布的大会官方录像。[13]

成熟 Autotools 项目的工作远超过把 C 或 C++ 变成二进制文件。它的 configure.acMakefile.am 文件与 Libtool 规则共同规定功能选择:哪些依赖属于可选项,config.h 中会出现哪些预处理器符号,哪些测试允许跳过。它们还决定哪些头文件与库进入暂存根目录,以及下游 pkg-config 用户会看到什么;共享库名称与发布 tarball 的内容也由这些文件和规则确定。

Meson 可以用少得多的繁复配置描述同一产品,迁移工作的重点仍然超出语法转换。一份新的 meson.build 能够运行到 meson compile -C build,只证明某一台机器可以生成若干目标。迁移完成的标准是:相同的功能选择对应相同的公共制品、测试、安装布局、发布归档与交叉构建行为,下游打包维护者也能够解释每一处有意保留的差异。

因此,速度适合放在迁移论证接近末尾的位置。早期有人在 Nexus 4 上试验 Meson,对 GLib 做了部分移植:配置耗时约 20 秒,Autotools 约为 220 秒;空操作检查约为 0.25 秒,Autotools 则为 14 秒。Meson 自己的报告明确说明,两套构建尚未完全等价。[12] 这些数字显出了机会,等价性仍需由后续工作建立。

配图说明:封面画面记录了 Meson 创建者 Jussi Pakkanen 在 2017 年 All Systems Go! 大会演讲后回答提问;那场演讲讨论了项目逐步离开旧式构建系统的趋势。构建系统迁移归根结底要处理维护者与下游之间的协同,速度更快的本地命令只覆盖其中一小部分,因此这张照片与本文主题相合。[13]

从产品着手,再看构建文件

添加 meson.build 之前,先从一次干净的 Autotools 发布构建中整理迁移台账。保存 ./configure --help、每个受支持软件包所用的准确 configure 命令、生成的 config.h、测试清单与结果,以及详细的编译器和链接器命令。把安装暂存到一个空目录,并记录路径、文件模式、符号链接、公共头文件、手册页、本地化数据、插件、静态归档、共享库名称和每个 .pc 文件。

开发者默认配置之外也要留下同样记录。至少应覆盖一个关闭可选集成的 minimal 构建,一个把所有承诺依赖设为必需项的 full 构建,以及每种受支持的共享库/静态库组合。可移植库还应保留一个已知可用的交叉构建。假如 ./configure 接受 24 个开关,CI 只检验其中 3 个,其余 21 个不会自动成为需求,它们代表尚未厘清的承诺。进入转换工作前,逐项归类为保留、改名、弃用或移除。

暂存安装是最有用的基线,因为它描述用户实际收到的产品,而没有停留在维护者的生成过程上。它还会显出一些不显眼的契约,例如兼容性头文件、带版本号的符号链接、位于 libdir 的插件,或单元测试从未提及的 Requires.private 行。正因如此,Meson 自己的移植指南同时列出配置头文件、依赖发现、生成源码、库、已安装头文件、测试、内省数据、设置 schema 与翻译文件;构建图覆盖的范围远超编译。[1]

回滚也要落到可复现的操作上。在 Meson 软件包通过下游测试之前,保持最后一版 Autotools 发布配方、由它生成的 tarball 以及对应打包补丁都能重现。“旧文件还在 Git 里”本身无法构成回滚;一旦已经没有人能重建当初让这些文件生效的发布环境,回滚条件也就消失了。

把决策译入 Meson,略去 M4 外壳

顶层 Meson 文件首先声明项目,以及维护者实际测试的最低 Meson 版本:

project(
  'libsample', 'c',
  version: '2.4.0',
  meson_version: '>=1.4.0',
  default_options: ['warning_level=2'],
)

从这里开始,要把每项 Autotools 决策对应到 Meson 概念,舍弃 shell 层面的机械做法。AC_CONFIG_HEADERS 对应一个 configuration_data() 对象和 configure_file()PKG_CHECK_MODULES 的结果对应一个通过 dependencies: 传入的 dependency() 对象;生成文件成为 custom_target() 的输出,再由目标明确消费;安装头文件使用 install_headers()。库目标应有意设定 versionsoversion,避免无意间沿用 Libtool 的版本算术。[1]

可选依赖需要格外仔细。Meson 的 feature 选项有三种状态:enableddisabledauto。把它传给 dependency(..., required: get_option('feature_name')) 后,三种状态分别表示“缺少时失败”“跳过探测”和“找到就使用”。打包维护者还可以通过 auto_features 强制开启或关闭其余所有自动功能。[2]

# meson.options
option('tls', type: 'feature', value: 'auto', description: 'TLS support')

# meson.build
tls_dep = dependency('openssl', required: get_option('tls'))
conf.set10('HAVE_TLS', tls_dep.found())

这段配置的意义超过语法便利。它能防止一种常见的打包故障:某个构建环境恰好装着一项可选库,产品内容便在没有提示的情况下扩大。CI 应运行 -Dauto_features=enabled,验证完整依赖契约;同时运行 -Dauto_features=disabled,验证最小契约。凡是已经承诺的功能,它的“enabled”通道在依赖缺失时必须明确失败。

手写编译器探测代码历史悠久,并不足以构成保留理由。确实需要检测某项能力时,使用 cc.has_header()cc.has_function()cc.links() 之类的编译器对象;成熟的平台契约则交给 Meson 的依赖对象。项目 FAQ 特别提醒开发者避开手工查找 libpthread,改用 dependency('threads'),因为线程标志在跨平台环境中有许多边缘情形。[1]

两套流程并行验证,并为重叠期设定截止日

Meson 尚未完备时,继续以 Autotools 为权威;随后让两套系统针对同一 commit 与同一功能矩阵运行。典型的 Meson 通道有意保持朴素:

meson setup build-meson \
  --prefix=/usr \
  --buildtype=debugoptimized \
  -Dauto_features=enabled
meson compile -C build-meson
meson test -C build-meson --print-errorlogs
meson install -C build-meson --destdir "$PWD/stage-meson"

比较时间或输出之前,先对齐编译器、优化设置、调试信息、依赖版本与生成输入。缺失功能、不同编译器标志或较少的测试也会制造出“Meson 改进”的表象。

双轨维护只用于验证,必须有终点。GLib 在 2018 年公布了一段有期限的安排:先发布一个默认采用 Meson、同时保留 Autotools 的版本,请发行版和较少见工具链的用户参与测试,随后在下一个开发周期移除 Autotools。[9] GStreamer 更早的实验性推广同样以 Autotools 为主,同时逐步补齐 Linux、Windows、GCC、Clang 与 MSVC 覆盖。其维护者报告,在那位开发者的机器上,一个小型示例用 Meson 完成配置、构建和安装不到 4 秒;Autotools 的配置约需 17 秒,构建还需 10 秒。[11]

这些带有年代背景的计时数据服务于同一做法:明确重叠期需要发现什么,并约定项目何时切换或放弃尝试。LWN 对 Mesa 讨论过程的记录,从另一侧呈现了同样的压力。开发者希望构建更快、更简单,发行版与非 Linux 流程也属于决策的一部分;当时提出的方案是让一个发布版本同时携带两套系统,随后作出明确选择,避免无限期重复维护。[10]

比较暂存安装树,绿色编译日志还不够

把两套构建分别安装到空根目录:

make DESTDIR="$PWD/stage-auto" install
meson install -C build-meson --destdir "$PWD/stage-meson"
diff -ruN stage-auto stage-meson

对比重点应放在产品层;嵌入的构建路径、时间戳或调试段会让逐字节一致失去意义。检查每个文件的路径和模式、库符号链接与 SONAME、导出符号、公共头文件内容、插件发现、本地化文件位置、手册页,以及下游的编译和链接行为。Meson 只有在目标或文件被标记为安装项时才会安装它,而 DESTDIR 支持本来就是为软件包暂存设计的。[3]

使用 meson introspect build-meson --install-plan 检查计划中的安装内容,再用 --buildoptions--dependencies--targets--tests 让机器与人都能审查新的构建图。[4] 对于库,应先生成并检查 .pc 文件,不能直接假定 pkg.generate() 已推导出预期的公共/私有划分。requiresrequires_privatelibrarieslibraries_private 字段对动态链接和静态链接使用者的影响各不相同。[8]

共享库需要 ABI 门禁,单看文件名覆盖不了这项检查。对比 SONAME 与导出符号集合,再使用暂存头文件和库编译一个很小的下游使用程序。如果项目使用符号版本脚本、Darwin 兼容版本或 Windows 导出定义,就在各自原生平台上检验。Meson 构建即使生成了 libsample.so,一旦同时改变 libsample.so.2、丢掉某个导出符号,或遗漏静态链接所需的私有依赖,就没有达到软件包对等。

保留测试套件原有的含义

Meson 默认并发运行测试。旧测试套件若共享固定 socket、数据库、临时文件名或 D-Bus 名称,即使每项测试都曾在串行 Automake harness 下正常工作,也会因此变得不稳定。用 is_parallel: false 标记确实需要独占资源的测试;等到各自状态已经隔离,再移除这项限制。[5]

还要比较各类结果,最终退出状态只覆盖一部分信息。Meson 把退出码 77 识别为跳过,把 99 识别为严重的设置错误;超时、预期失败、测试 wrapper、环境变量与 suite 归属仍需明确映射。[5] 针对每个功能通道,记录测试总数、通过数、跳过数与预期失败数。某个交叉构建若因所有需要运行程序的测试都被跳过而显示“通过”,它提供的证据弱于只出现一次失败的原生构建。

测试应使用 Meson 当次构建的产物,避免误取系统已经安装的副本。找出误报成功的移植,最快的办法是把测试放进干净的容器或 chroot,其中唯一的项目文件来自当前构建与暂存根目录。

交叉构建会暴露用错机器的错误

Autotools 项目经常把多年积累的 build/host 知识藏在三元组(triplet)、环境变量和自定义宏中。Meson 把这些知识移入交叉编译文件(cross file):[binaries] 下列出编译器与 binutils,另有 sysroot、目标平台的 pkg-config 搜索路径、可选的 exe_wrapper,以及 [host_machine] 下的系统、CPU family 和字节序。设置时通过 meson setup --cross-file ... 选择这个文件。[7]

风险最高之处在生成代码。编译后要在构建期间运行的程序需要设为 native: true;最终交付的库或程序使用 host 工具链。混淆这两类角色后,原生构建依旧能通过,首次 ARM、Windows 或嵌入式构建却会尝试在构建机上运行目标平台二进制文件。cross file 中缺少 exe_wrapper 时,Meson 会跳过那些需要运行 host 二进制文件的测试,因此验收记录必须包含跳过数。[7]

对于由两个人维护、只面向 Linux 的命令行工具,一个原生 GCC 通道和一个 Clang 通道可以构成与风险相称的门槛。发行版使用的可移植库需要覆盖更多内容:至少一个真实 cross file、条件允许时的原生或模拟执行、下游打包,以及针对构建期生成程序的明确测试。验收矩阵应由实际运维成熟度决定,流行度不能替代证据。

发布归档通过验收,切换才有依据

meson dist -C build-meson 会打包版本控制中的最新 commit,移除仓库元数据,再用生成的归档执行一次编译、测试和安装周期,最后创建 SHA-256 文件。这与 Autotools 面向源码树的 dist 不同:尚未提交的生成文件不会悄然进入 Meson 归档。[6]

在离线的干净环境中构建 tarball。检查生成手册、语言绑定、翻译产物与版本文件,确认其中哪些过去由 Autotools 随包提供,让终端用户可以免装维护工具。若发布包必须包含 subprojects,应明确 --include-subprojects 是否属于契约。[6] 从 Git checkout 构建与从已发布 tarball 构建,是两项独立的验收测试。

工具链最低要求也会在这里落实。Meson 需要 Python,常用的 Ninja backend 又增加了一项 bootstrap 依赖。项目若必须在旧式 Unix 系统上构建,而这些系统没有可支持的 Python/Meson 方案,继续采用 Autotools 是合理选择。稳定库若面对的下游打包维护者尚且无法复现它的平台探测或 ABI,也可以作出同样决定。迁移属于运维决策,语法是否清爽不能代替这项权衡。

删除前的六道门槛

以下六项全部成立后,才能移除 Autotools:

  1. 每个保留的 configure 功能都有明确的 Meson 选项,minimal 与 full 矩阵的行为均与文档一致。
  2. 原生构建编译相同目标,编译器与链接器差异均已审查。
  3. 测试清单、通过数、跳过数与预期失败数一致,或每一项差异都有各方接受的理由。
  4. 暂存安装在路径、模式、符号链接、元数据、ABI 与下游使用行为上保持一致。
  5. 受支持的交叉构建把 build-machine 工具与 host 制品分开,意外跳过均已排除。
  6. 发布归档能够在干净的离线环境中完成构建、测试与安装,并且至少有一位下游打包维护者成功复现。

反证条件也很清楚:若 Meson 流程反复需要项目专用衔接代码,而且它比被替换的 Autotools 逻辑更难解释,或者受支持的下游环境无法复现同一产品,维护成本降低这一承诺就尚未兑现。可以保留实验、补齐缺口,也可以中止迁移。迁移决定不能靠删除已知可行的流程来迫使各方接受。

六道门槛通过后,应及时删除 Autotools。两份构建描述会让新增源文件、选项、测试或安装制品多出一倍的漂移位置。第一次亚秒级空操作构建只是早期信号;真正值得庆祝的时刻,要等到首个发布版本让维护者、CI 与打包维护者都使用同一张清晰可读的构建图,并由安装树交付他们早已了解且信任的同一产品。

来源

  1. Meson 文档,“Porting from Autotools”——涵盖配置头文件、依赖、生成源码、库、已安装数据、测试和 GNOME 专用构建产物之间的对应关系。
  2. Meson 文档,“Build options”——介绍 meson.options、三态 feature 选项,以及面向打包维护者的 auto_features 覆盖设置。
  3. Meson 文档,“Installing”——介绍安装声明、标准安装目录、自定义脚本,以及通过 DESTDIR 暂存软件包的行为。
  4. Meson 文档,“Command-line commands”——介绍 setup、configure、compile、install,以及针对选项、依赖、目标、测试和安装计划的 JSON 内省。
  5. Meson 文档,“Unit tests”——介绍并行执行、测试环境、日志、跳过与严重错误退出码、suites 和 wrappers。
  6. Meson 文档,“Creating releases”——介绍基于 VCS 的 meson dist、归档的编译/测试/安装验证、校验和,以及捆绑 subproject 的行为。
  7. Meson 文档,“Cross compilation”——介绍 cross files、build/host/target 术语、程序 wrapper、sysroot、目标平台 pkg-config 路径与原生构建期生成程序。
  8. Meson 文档,“Pkgconfig module”——介绍生成的 .pc 文件、公共/私有 requirements 与 libraries、安装位置和未安装元数据。
  9. Emmanuele Bassi,“News from GLib 2.58”,GTK Development Blog,2018 年 7 月 11 日——介绍项目以一个发布版本为期、默认采用 Meson 的重叠安排,面向发行版的测试请求,以及移除 Autotools 的计划。
  10. Jonathan Corbet,“Moving Mesa to Meson”,LWN.net,2017 年 3 月 29 日——独立报道迁移收益、发行版顾虑,以及为双构建发布设定明确期限的理由。
  11. Tim Müller,“Experimental build using the Meson build system”,GStreamer-devel,2016 年 9 月 2 日——对分阶段推广、平台与工具链目标、已知缺口和本地计时比较的第一手记录。
  12. Meson 项目,“Arm performance test”——记录 Nexus 4 上 GLib 实验的年代、配置与空操作测量结果,以及两套构建尚不等价的明确说明。
  13. media.ccc.de,“Meson and the changing Linux build landscape”,All Systems Go! 2017——本文封面截图所取自的官方存档录像及活动出处。
Previous 相同的内核 oops 揭露了 Debian 四台服务器入侵事件

Recommended In oss

Matched by subject and format