Meson 构建系统 – 迄今为止最友好的构建工具?

最近从 Pidgin 3 中发现了 Meson 构建系统。在一番学习后,我发现 Meson 是个非常友好的构建工具。

传统构建工具的弊端

Meson 的诞生少不了传统构建工具的推动,传统构建工具的最大弊端就是(非常烂)。传统构建工具工作简单,但会耗费开发者很多精力。简单说就是:开发者应该把更多的时间放在代码上,而不是其它的。

最经典的构建工具我想就是 make 了吧,要编译任何一个 C 项目基本都需要先敲这些:

CC = gcc
OBJS = a.o b.o ...
CFLAGS = ...
LIBS = ...

.DEFAULT_GOAL = exe

%.o: %.c
    $(CC) $(CFLAGS) -c -o $@ $^

exe: $(OBJS)
    $(CC) $(LIBS) -o $@ $^

clean:
    rm -rf $(OBJS) exe

看上去就很糟糕,对吧? Makefile 需要设置一系列变量来保证扩展性,比如 $CC 被用来指定编译器。另外,Makefile 里还有一堆让人眼花缭乱的特殊变量(比如 $DEFAULT_GOAL),这让 Makefile 的可读性也变的很差。最重要的是,Make 有多个变种,比如 GNU Make、BSD Make。如果你的没有注意你的语法而使用到了一些 Make 扩展,你的 Makefile 可能就没法被其它的 Make 构建。所以,Make 的可移植性也很差。

传统 + DLC(GNU 构建系统与 Cmake)

Cmake 一般都见过,那 GNU 构建系统呢?实际上你也用过,在构建软件时运行的 ./configure 就是 GNU 构建系统的一部分。

GNU 构建系统是用来构建大型软件的构建工具,其大部分基于 GNU m4 (很酷的宏处理器)和 make。而 Cmake 则用于构建跨版本的项目。两个构建系统都解决了传统工具在处理大型项目时的不足,而且改进了一点点的可读性。

Cmake 的可读性很难吐槽,直接上代码:

cmake_minimum_required(VERSION 3.13)  # CMake version check
project(simple_example)               # Create project "simple_example"
set(CMAKE_CXX_STANDARD 14)            # Enable c++14 standard

# Add main.cpp file of project root directory as source file
set(SOURCE_FILES main.cpp)

# Add executable target with source files listed in SOURCE_FILES variable
add_executable(simple_example ${SOURCE_FILES})

而 GNU 构建系统的配置则比这更混乱。另外,因为 GNU 构建系统的配置分布在各个文件里,所以贴不出来(

从零开始的友好的构建系统 —— Meson 构建系统

Meson 是一个开源构建系统,旨在极速,更重要的是,尽可能地对用户友好。

Meson 的主要设计点是,开发人员花在编写或调试构建定义上的每一刻都是浪费的。 等待构建系统真正开始编译代码的每一秒也是如此。

mesonbuild.com

Meson 构建系统的亮点是快速、对用户友好、跨平台、内嵌子项目和支持多语言。

你好世界!

让我们开始一个 Hello World 项目,看看 Meson 管不管用。

 $ cd hello # 进入项目
 $ meson init # 初始化项目
 $ meson setup build # 初始化构建目录
 $ cd build # 进入构建目录
 $ ninja # 构建
 $ ./hello

可以看到,这样就完成了一个 Hello World 项目。可以看到,源文件夹生成了一个 meson.build 文件。这是 meson 的配置文件,内容应该和下面的相似:

project('hello', 'c',  version : '0.1', 
  default_options : ['warning_level=3'])
exe = executable('hello', 'hello.c',
  install : true)
test('basic', exe)

第一行用来定义项目,项目名是 hello、语言是 C、版本是 0.1、默认参数是将警告等级设置为 3。第二行设置一个 exe 变量、内容是一个名为 hello 的可执行文件、源文件是 hello.c、且会被安装到系统中。第三行对 exe 进行基本测试。可以看到,配置对开发者来说一目了然。

引入依赖

要引入依赖十分简单,我会在下面引入 glib-2.0:

project('hello', 'c',
  version : '0.1',
  default_options : ['warning_level=3'])

glib = dependency('glib-2.0')
exe = executable('hello', 'hello.c',
  install : true, dependencies : glib)

test('basic', exe)

哈!前后差别只有两行,Meson 会自动在 pkg-config 中搜索依赖并链接到最终的二进制。

多个源文件

使用多个源文件也很简单,只需要用一个列表来替代 hello.c。代码如下:

exe = executable('hello', ['hello.c', 'b.c'],
  install : true, dependencies : glib)

强大的测试功能

Meson 可以自动执行项目的测试,这在 C 项目中不多见。它的使用也十分简单,我在这里创建一个简单测试:

/* plus.c */
#include <assert.h>
int main (void) {
    assert (2+2 == 4);
}
# meson.build
plus = executable('plus-test', 'plus.c')
test('2+2 Plus', plus)

大功告成!现在你应该能运行 ninja test 来进行单元测试。

对了,ninja 实际上就是 make 的 meson 版。

这篇简单的 Meson 构建系统的介绍到这里就结束了。文章中展示的 Meson 功能其实只是冰山一角,更多信息可以前往 mesonbuild.com 获取。Happy Hacking!