第4章:Meson构建系统——从入门到实战
说实话,我第一次接触Meson是在一个跨平台项目上。当时CMake的配置已经变得臃肿不堪,我正愁怎么优化。团队里一个小伙子说:「要不试试Meson?」我一开始是拒绝的——毕竟CMake用了这么多年。但试了之后,嗯,真香。
4.1 Meson简介
Meson是一个开源的构建系统,2013年诞生。它的设计目标很明确:快、简单、跨平台。
我个人的理解是,Meson想解决CMake的几个痛点:
- 速度慢——CMake在大型项目上配置时间很长
- 语法复杂——CMake的语法说实话有点反人类
- 调试困难——CMake报错信息经常让人摸不着头脑
Meson用Python-like的DSL(领域特定语言),比CMake的语法直观得多。而且它底层用Ninja作为构建后端,编译速度杠杠的。
核心特点:
- 原生支持C、C++、C#、D、Fortran、Java、Rust等语言
- 内置依赖管理,支持pkg-config、Wrap等
- 跨平台:Linux、macOS、Windows、Android、iOS
- 自动检测编译器、链接器、工具链
4.2 安装Meson
安装方式很简单,我一般用pip:
# 使用pip安装(推荐)
pip install meson ninja
# 验证安装
meson --version
ninja --version
在Ubuntu上也可以用apt:
sudo apt install meson ninja-build
macOS用户:
brew install meson ninja
小提示:我建议用pip安装,版本更新快。apt源里的版本经常落后一两个大版本。
4.3 meson.build语法入门
Meson的配置文件叫meson.build。语法很简洁,我直接上例子:
# 最简单的项目
project('my_project', 'cpp',
version : '1.0.0',
default_options : ['cpp_std=c++17'])
# 添加可执行文件
executable('my_app',
'main.cpp',
'utils.cpp',
dependencies : [],
install : true)
你看,是不是比CMake清爽多了?
常用的函数:
project()——定义项目名称、语言、版本executable()——生成可执行文件library()——生成库文件(静态/动态)dependency()——声明依赖subdir()——包含子目录
来个复杂点的例子:
project('cross_platform_app', ['c', 'cpp'],
version : '2.0.0',
meson_version : '>=0.60.0')
# 条件编译
if host_machine.system() == 'windows'
add_project_arguments('-DWIN32', language : 'cpp')
elif host_machine.system() == 'linux'
add_project_arguments('-DLINUX', language : 'cpp')
endif
# 添加静态库
my_lib = static_library('core',
'src/core.cpp',
'src/math.cpp',
include_directories : include_directories('include'))
# 链接库
executable('main_app',
'src/main.cpp',
link_with : my_lib,
install : true)
注意:Meson的变量作用域和Python不同。在if块里定义的变量,外面是访问不到的。我曾经因为这个bug排查了半天……
4.4 依赖管理
依赖管理是Meson的强项。它支持三种方式:
- 系统依赖——通过pkg-config查找
- Wrap依赖——从WrapDB下载源码编译
- 子项目——直接引用本地子项目
举个例子:
# 方式1:系统依赖
glib_dep = dependency('glib-2.0', version : '>=2.50')
# 方式2:Wrap依赖(自动下载)
fmt_dep = dependency('fmt', fallback : ['fmt', 'fmt_dep'])
# 方式3:子项目
subproject('mylib')
mylib_dep = subproject('mylib').get_variable('mylib_dep')
executable('my_app',
'main.cpp',
dependencies : [glib_dep, fmt_dep, mylib_dep])
我个人最喜欢Wrap方式。你想想看,以前用CMake时,要手动下载第三方库、配置路径,烦不烦?Meson的WrapDB就像一个包管理器,meson wrap install fmt就搞定了。
避坑指南:我曾经在Windows上遇到pkg-config找不到库的问题。解决方案是安装pkg-config-lite,或者直接用Wrap方式。嗯,后来我基本都改用Wrap了,省心。
4.5 与CMake的对比
很多同学问我:「到底该学Meson还是CMake?」我的回答是:都学,但优先学Meson。
直接上对比表:
| 特性 | Meson | CMake |
|---|---|---|
| 语法复杂度 | 低(Python-like) | 高(自定义语法) |
| 配置速度 | 快(增量配置) | 慢(全量配置) |
| 构建速度 | 快(Ninja后端) | 中等(Make/Ninja) |
| 依赖管理 | 内置(WrapDB) | 需手动或FetchContent |
| 跨平台支持 | 优秀 | 优秀 |
| 生态成熟度 | 中等(增长中) | 成熟(业界标准) |
| 调试友好度 | 高(报错清晰) | 低(报错晦涩) |
说白了,CMake是「老大哥」,生态完善,几乎所有C++项目都用它。但Meson是「后起之秀」,设计更现代,用起来更舒服。
我个人的建议:
- 新项目——用Meson,开发效率高
- 已有CMake项目——别急着迁移,除非你受够了CMake
- 开源项目——看社区习惯,Qt、GNOME等用Meson
4.6 实战:一个跨平台项目
最后,我分享一个实际项目的meson.build结构:
project('cross_platform_tool', 'cpp',
version : '1.0.0',
default_options : [
'cpp_std=c++17',
'buildtype=release',
'warning_level=3'
])
# 第三方依赖
thread_dep = dependency('threads')
fmt_dep = dependency('fmt', fallback : ['fmt', 'fmt_dep'])
# 平台特定代码
if host_machine.system() == 'windows'
winsock_dep = meson.get_compiler('cpp').find_library('ws2_32')
platform_src = ['src/win_platform.cpp']
platform_dep = winsock_dep
else
platform_src = ['src/unix_platform.cpp']
platform_dep = []
endif
# 核心库
core_lib = static_library('core',
'src/core.cpp',
'src/network.cpp',
platform_src,
dependencies : [thread_dep, fmt_dep, platform_dep],
include_directories : include_directories('include'))
# 测试
test_exe = executable('test_core',
'test/test_main.cpp',
link_with : core_lib)
test('core_test', test_exe)
# 主程序
executable('main_tool',
'src/main.cpp',
link_with : core_lib,
install : true)
这个结构我用了好几年,在Windows、Linux、macOS上都没出过问题。你想想看,一个构建文件搞定三个平台,是不是很爽?
总结一下:Meson不是要取代CMake,而是给你多一个选择。如果你厌倦了CMake的繁琐,不妨试试Meson。我保证,你会爱上它的简洁。
可可精品资料库