第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的强项。它支持三种方式:

  1. 系统依赖——通过pkg-config查找
  2. Wrap依赖——从WrapDB下载源码编译
  3. 子项目——直接引用本地子项目

举个例子:

# 方式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。我保证,你会爱上它的简洁。

Meson构建系统核心知识体系 Meson构建系统 简介与特点 安装(pip/apt/brew) meson.build语法 跨平台 速度快 语法简洁 project() executable() dependency() 依赖管理 系统依赖(pkg-config) Wrap依赖(WrapDB) 子项目(subproject) 与CMake对比

可可精品资料库