Monday, December 12, 2016

The Meson Build System

1 はじめに

Meson というビルドシステムをご存知でしょうか? Jussi Pakkanen が作成したビルドシステムで、最近 GNOME 界隈で人気です。 Meson 自体は、 GNU Make の様に実際に build せず、 ビルド自体は Chrome Project で作られた Ninja を使います。 つまり Meson は GYP や CMake と同じ立ち位置です。

GYP → Make から GYP → Ninja 、Meson → Ninja と感じでしょうか。

Ninja は、 build system の高速 assembler を目指して作られただけあって、いろいろな Generator が生まれました。 その1つが Meson です。

2 Hello World

まず最初は、C の Hello World でどのように Mesonを記述するのか見てみましょう。

C のコードはいたってふつうの Hello World です。

#include <stdio.h>

int main()
{
        printf("Hello, World!\n");
        return 0;
}

このコードをコンパイルできるようにする Meson のコードは、次の2行です。これを meson.build というファイルに記載します。

project('helloworld', 'c')
executable('hello', 'hello.c')

project() でプロジェクト名と言語を、 executable() で実行ファイル名とソースファイル名を記述します。

Meson は In-Tree ビルドに対応していません。かならず Out-of-Tree ビルドになります。 Meson を実行するには、

meson [source dir] [build dir]

と、します。hello.c が置いてあるディレクトリで実行するなら、次のようになります。

$ ls
hello.c  meson.build
$ meson . build
The Meson build system
Version: 0.36.0
Source dir: /tmp/meson
Build dir: /tmp/meson/build
Build type: native build
Project name: helloworld
Native c compiler: ccache cc (gcc 6.2.1)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Build targets in project: 1

Meson がファイルを生成し終ったら Ninja を使ってビルドします。

$ ninja -C build
ninja: Entering directory `build'
[2/2] Linking target hello

無事、 build/hello が生成されました。

$ build/hello
Hello, World!

3 Build Application against GStreamer with Meson

ということで、次は GStreamer を使ったアプリを Meson でビルドしてみます。こちらもとてもシンプルなコード で試してみます。

#include <gst/gst.h>

int main(int argc, char *argv[])
{
        GMainLoop *mainloop;
        GstElement *pipeline;
        GError *error = NULL;

        gst_init(&argc, &argv);

        mainloop = g_main_loop_new(NULL, FALSE);
        pipeline = gst_parse_launch("videotestsrc ! autovideosink", &error);

        gst_element_set_state(pipeline, GST_STATE_PLAYING);
        g_main_loop_run(mainloop);

        return 0;
}

このコードを、先程と同じ meson.build を使ってビルドすると

[1/2] Compiling c object 'hellogst@exe/hellogst.c.o'
FAILED: hellogst@exe/hellogst.c.o
ccache cc  '-Ihellogst@exe' '-fdiagnostics-color=always' '-I.' '-I..' '-pipe' '-Wall' '-Winvalid-pch' '-O0' '-g' '-MMD' '-MQ' 'hellogst@exe/hellogst.c.o' '-MF' 'hellogst@exe/hellogst.c.o.d' -o 'hellogst@exe/hellogst.c.o' -c ../hellogst.c
../hellogst.c:1:21: fatal error: gst/gst.h: No such file or directory
 #include <gst/gst.h>
                     ^
compilation terminated.
ninja: build stopped: subcommand failed.

と、 gst/gst.h が見つからないと怒られてしまいます。それもそのはずで、ビルドシステムは GStreamer のヘッダーに関してなにも知りません。そこで、このアプリは GStreamer 1.0 に依存していることを教えてあげます。

project('hello-gst', 'c')

gst_dep = dependency('gstreamer-1.0', version : '>=1.0')

executable('hellogst', 'hellogst.c', dependencies : gst_dep)

dependency() が、依存関係の記述です。 gstreamer-1.0 に依存し、バージョンは 1.0以上 という風に指定しました。この記述、実は pkg-config のモジュールの書き方と一緒です。 Meson は実行されているシステムでどのように依存関係を解決すべきか知っています。 Linux 上では pkg-config を使って解決してくれます。 もちろん Meson は Multi Platform 対応なので Windows 上でも MacOS 上でも、同じ書き方で GStreamer の依存関係を解決してくれます。

依存関係を追記したら、 build ディレクトリを消して試してみましょう。 (正確には Meson は一度実行された後は、自動で設定が変った後に自分自身を再度実行します。そのため削除する必要はありません。ここでは、あえて GStreamer 1.0 を見つけるログを表示するために削除しています。)

$ rm -r build
$ meson . build
The Meson build system
Version: 0.36.0
Source dir: /tmp/hello-gst
Build dir: /tmp/hello-gst/build
Build type: native build
Project name: hello-gst
Native c compiler: ccache cc (gcc 6.2.1)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Found pkg-config: /usr/bin/pkg-config (0.29)
Native dependency gstreamer-1.0 found: YES 1.10.2  ← GStreamer を見つけました
Build targets in project: 1

続いて ninja でビルドします。

$ ninja -C build
[0/1] Regenerating build files
The Meson build system
Version: 0.36.0
Source dir: /tmp/hello-gst
Build dir: /tmp/hello-gst/build
Build type: native build
Project name: hello-gst
Native c compiler: ccache cc (gcc 6.2.1)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Build targets in project: 1
[2/2] Linking target hellogst
$ cd build
$ ls
build.ninja            hellogst      meson-logs
compile_commands.json  hellogst@exe  meson-private

hellogst が生成されました。

他にも、いろいろな中間ファイルが生成されています。

$ tree
.
├── build.ninja
├── compile_commands.json
├── hellogst
├── hellogst@exe
│   └── hellogst.c.o
├── meson-logs
│   └── meson-log.txt
└── meson-private
    ├── build.dat
    ├── coredata.dat
    ├── install.dat
    ├── meson_benchmark_setup.dat
    ├── meson_test_setup.dat
    ├── sanitycheckc.c
    └── sanitycheckc.exe

3 directories, 12 files

4 Build GStreamer Plugin with Meson

さて、やっと本題です。 GStreamer の Plugin を Meson でビルドしてみます。次の空っぽの Plugin をビルドします。

#include <gst/gst.h>
#include "config.h"

static gboolean
plugin_init (GstPlugin * plugin)
{
        return TRUE;
}


GST_PLUGIN_DEFINE (
        GST_VERSION_MAJOR,
        GST_VERSION_MINOR,
        gsttext,
        "Text Plugins for GStreamer",
        plugin_init,
        PACKAGE_VERSION,
        "LGPL",
        "GStreamer Text Package",
        "https://github/yashi/gst-plugins-text")

Meson.build は次のようになります。

project('gst-plugins-text', 'c', version : '0.1.0')

src = ['src/gsttext.c']

gst_dep = dependency('gstreamer-1.0', version : '>1.0')

cdata = configuration_data()
cdata.set_quoted('PACKAGE', meson.project_name())
cdata.set_quoted('PACKAGE_VERSION', meson.project_version())

configure_file(output : 'config.h', configuration : cdata)

gsttext = library('gsttext', src, dependencies : gst_dep)
project()
新しく version を追加しています。それ以外は、名前が異なるだけで同じ内容です
src
executable() に直接指定していたソースコードを変数に外出ししました。ファイルのリストなので [ ] で括っています
configuration_data()

設定を記載するためのデーターを作成します。最初はからっぽ。言語で C を選択していると #define が記述されたファイルが生成されます

/*
 * Autogenerated by the Meson build system.
 * Do not edit, your changes will be lost.
 */

#pragma once

#define PACKAGE "gst-plugins-text"

#define PACKAGE_VERSION "0.1.0"
cdata.set_quoted()
設定を追加します。設定値を " " で括りたいので _quoted を使っています。括らないなら set() が使えます
configure_file()
設定ができあがったら、ファイルに書き出します。ここでは autotools の名残りで config.h にしてみました
library()
実行ファイルではなくライブラリを作成したいので、 executable() ではなく library() を使います。ファイル名と、ソースコード、そして依存を記載します
$ meson . build
The Meson build system
Version: 0.36.0
Source dir: /home/yashi/src/gst/gst-plugins-text
Build dir: /home/yashi/src/gst/gst-plugins-text/build
Build type: native build
Project name: gst-plugins-text
Native c compiler: ccache cc (gcc 6.2.1)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Found pkg-config: /usr/bin/pkg-config (0.29)
Native dependency gstreamer-1.0 found: YES 1.10.2
Build targets in project: 1
ninja -C build
ninja: Entering directory `build'
[2/2] Linking target libgsttext.so
GST_PLUGIN_PATH=`pwd`/build gst-inspect-1.0 gsttext
Plugin Details:
  Name                     gsttext
  Description              Text Plugins for GStreamer
  Filename                 /home/yashi/src/gst/gst-plugins-text/build/libgsttext.so
  Version                  0.1.0
  License                  LGPL
  Source module            gst-plugins-text
  Binary package           GStreamer Text Package
  Origin URL               https://github/yashi/gst-plugins-text


  0 features:

5 おわりに

いかがだったでしょうか? ビルドスクリプトは頻繁に更新するものではないので、Autotools の書き方を毎回忘れてしまうという人でも Meson だったら簡単じゃないでしょうか? Linux でも Windows でも MacOS でも使えるという利点や、依存関係が Python と ninja だけになるという点も嬉しいです。しかし、プログラマーにとって一番嬉しいのは、ビルド時間が劇的に早くなることによって、コンパイルによって集中が途切れず、開発効率が改善されることじゃないでしょうか。え? コンパイル中に休憩 できなくなって困るなんてことはないですよね?

No comments:

Post a Comment