The Meson build system

The main design point of Meson is that every moment a developer spends writing or debugging build definitions is a second wasted. So is every second spent waiting for the build system to actually start compiling code. - Meson

Prefer latest version >= 0.59 rather than prepackaged distrib version

Compiling a Meson project

The only thing to note is that you need to create a separate build directory. Meson will not allow you to build source code inside your source tree. All build artifacts are stored in the build directory.

meson.build file

$ mkdir new_project && cd new_project
$ meson init               # for creating project from scratch 
$ meson build && cd build
$ meson compile
$ meson test
project('tutorial', 'cpp')
gtkdep = dependency('gtk+-3.0')
executable('demo', 'main.cc', dependencies : gtkdep)

Optimized build

$ meson --reconfigure --buildtype=debugoptimized # or debug or release

Include directories

incdir = include_directories('include')
executable('someprog', 'someprog.c', include_directories : incdir)

Subprojects

Meson allows you to take any other Meson project and make it a part of your build without (in the best case) any changes to its Meson setup. It becomes a transparent part of the project.

All subprojects must be inside subprojects directory inside your project folder.

$ mkdir subprojects

see also

CMake based subprojects are also supported but not guaranteed to work.

# Configure the CMake project
cmake = import('cmake')

## folly CMake require https://github.com/fmtlib/fmt.git to be installed
libfolly = cmake.subproject('libfolly')

Wrap file tells Meson how to download it for you. If you then use this subproject in your build, Meson will automatically download and extract it during build. This makes subproject embedding extremely easy.

see Wrap DB/2, to automatically get them for known libs. For eg:

# get already existing wrap for imgui (which include the required patch to make it work with meson build system)
$ meson wrap install imgui

# use wrap to retrieve the dependancy and launch build
$ meson build .

Otherwise, they can be written manually. For eg: having in ./subprojects/libfolly.wrap, will have meson automatically get folly from git repos at url with proper revision.

[wrap-git]
url = https://github.com/facebook/folly.git
revision = v2021.06.14.00

.gitignore Meson subprojects - For Meson subprojects, using the negate .gitignore syntax Git will ignore subdirectories but track the subprojects/*.wrap files, by including in the project top-level .gitignore:

/subprojects/*
!/subprojects/*.wrap

Using pkg-config

Meson provides the dependency() abstraction for working with pkg-config, cmake, various *-config tools, and a few built in dependencies that Meson has to save everyone reimplementing them, you would simply write:

dep_gstreamer = dependency('gstreamer-1.0')
dep_gsreamer_video = dependency('gstreamer-video-1.0')
# note that each dependency call finds 1 dependency

then you’d pass them to your targets:

build_target(
  'name',
  sources,
  dependencies : [dep_gstreamer, dep_gstreamer_video]
)

Generating pkg-config

Meson can also generate pkg info when compiling libs.

Native config files

Meson has separation between project build descriptions in meson.build, and compilation environment / toolchain descriptions in native/cross files.

Native files (–native-file) are the counterpart to cross files (–cross-file), and allow specifying information about the build machine, both when cross compiling and when not.

# ~/.local/share/meson/cross/codingame
# meson builddir/ --native-file codingame
[binaries]               
cpp = 'g++-9'

Cross compilation

Meson requires you to write a cross build definition file. It defines various properties of the cross build environment. The cross file consists of different sections.

Let’s suppose you are on a 64 bit OSX machine and you are cross compiling a binary that will run on a 32 bit ARM Linux board. In this case your build machine is 64 bit OSX, your host machine is 32 bit ARM Linux and your target machine is irrelevant (but defaults to the same value as the host machine).

ARM Cross compilation

your host_machine is ARM Linux

# ~/.local/share/meson/cross/remarkable
# meson builddir/ --cross-file remarkable
[host_machine]               
system = 'linux'             
cpu_family = 'arm'           
cpu = 'armv7l'            
endian = 'little'

Meson vs X / SO

Why I’d choose Meson+Doctest tech stack to create a new C++ project with a reusable and easy-to-run example - Choosing a Modern C++ stack / The Rise of Meson

Typical build

$ meson build .  (1)
$ cd build
$ ninja build    (2)
$ ninja test     (3)
  1. First time you configure the project
  2. Each time you build it
  3. Each time you run tests

Install !!

Due to our frequent release cycle and development speed, distro packaged software may quickly become outdated.

To install with sudo ninja install you need to have meson & ninja available for root user. And you need root meson in the same version as the one having build the project.

# sudo -i   # for root install
$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ python3 get-pip.py
$ python3 -m pip install meson

VSCode

Features

  • multiplatform support for Linux, macOS, Windows, GCC, Clang, Visual Studio and others
  • supported languages include C, C++, D, Fortran, Java, Rust
  • build definitions in a very readable and user friendly non-Turing complete DSL
  • cross compilation for many operating systems as well as bare metal optimized for extremely fast full and incremental builds without sacrificing correctness
  • built-in multiplatform dependency provider that works together with distro packages

FAQ

Written on August 12, 2020, Last update on October 17, 2024
build-system turing-complete dlang c++ vscode