Meson
Meson is an open source build system for C, C++, Rust, Fortran, and other compiled languages, designed to be fast and pleasant to use. You describe targets in a declarative meson.build file; Meson configures the project in a separate build directory and generates files for a backend — almost always Ninja — that performs the actual compilation.
Meson's language is deliberately not Turing-complete: no user-defined functions, no arbitrary file manipulation in the configuration step. That restriction keeps builds readable and reliable. GNOME, systemd, Mesa, GStreamer, QEMU, and PostgreSQL (as an alternative to its traditional build) use Meson, and meson-python has made it a common backend for Python packages with compiled extensions such as NumPy and SciPy.
TL;DR
- Describe targets in
meson.buildwith functions such asproject(),executable(),library(),dependency(), andtest(). - Configure into an out-of-source build directory with
meson setup; build withmeson compile(Ninja underneath). - Find dependencies with pkg-config, CMake, or system lookups, and fall back to WrapDB subprojects when they are missing.
- Control configuration with build options, build types, and per-project default options.
- Run tests with
meson test; cross-compile with cross files. - Package Python extensions with meson-python.
Quick Example
A meson.build for a small C program with a library, an external dependency, a fallback subproject, and a test:
Configuring, building, testing, and installing:
Core Concepts
The Build Definition
Variables, arrays, dictionaries, if, and foreach are available, but there are no user-defined functions, which keeps every build file understandable without tracing abstractions.
Build Directories and Backends
Meson never builds in the source tree. Each meson setup <dir> creates an independent configuration — debug, release, sanitizer, or cross builds side by side. The default backend generates Ninja files; Visual Studio and Xcode backends exist for IDE workflows. Reconfiguration happens automatically when build files change, and meson configure <dir> shows or changes options.
Dependencies
dependency() tries pkg-config, CMake package files, and built-in system lookups. When a dependency is missing, subprojects provide it: wrap files in subprojects/ describe how to download and build another project, and WrapDB hosts maintained wraps for many common libraries. Control fallback behavior with --wrap-mode (for example nofallback for distribution packaging, forcefallback for fully vendored builds).
Options and Build Types
Project-specific options live in meson.options (or the older meson_options.txt) and are read with get_option(). Built-in options include buildtype (debug, debugoptimized, release, minsize), b_sanitize, b_lto, warning_level, and werror:
Testing
meson test runs registered tests in parallel with timeouts, supports test suites, repeats (--repeat), and wrappers such as Valgrind (--wrapper), and writes JUnit-compatible logs for CI. meson test --gdb runs a failing test under a debugger.
Cross-Compilation
A cross file describes the target machine and toolchain:
Meson distinguishes the build machine (where compilation runs) from the host machine (where the result runs), so code generators that must run during the build are compiled natively with native : true.
Packaging and Distribution
meson installwith--destdirstages files for packaging; targets opt in withinstall : true.meson distcreates a release tarball from the Git tree and verifies that it builds and tests.- pkg-config files for your libraries are generated with the
pkgconfigmodule. - meson-python builds Python wheels with compiled extensions from a
pyproject.tomlthat declaresbuild-backend = "mesonpy". See Python Packaging.
Best Practices
Keep Build Logic Declarative
Use the built-in functions and modules instead of shelling out to scripts; Meson's restrictions exist to keep builds predictable.
Use Separate Build Directories per Configuration
Keep debug, release, sanitizer, and cross builds in different directories instead of reconfiguring one back and forth.
Prefer System Dependencies, With Wrap Fallbacks
Find dependencies through pkg-config first and use WrapDB fallbacks for developers and CI, while letting distributions disable fallbacks.
Run Tests and Sanitizers in CI
Build a sanitizer configuration and run meson test in CI to catch memory errors early.
Common Mistakes
Hard-Coding Compiler Flags
Manually Listing Include and Link Flags
Rebuilding One Directory for Every Configuration
FAQ
What is Meson?
An open source build system for compiled languages that uses a declarative, non-Turing-complete configuration language and generates build files for Ninja or IDE backends.
How is Meson different from CMake?
Both generate builds for backends such as Ninja. Meson has a smaller, stricter language with built-in conventions and focuses on simplicity; CMake has a larger ecosystem, broader IDE integration, and more flexibility. See CMake.
Does Meson replace Ninja?
No. Meson configures the project and generates Ninja build files; Ninja executes the build. See Ninja.
How do I handle missing dependencies?
Declare a fallback subproject using a wrap file, often installed from WrapDB with meson wrap install, so Meson can build the dependency when it is not available on the system.
Can Meson build Python packages?
Yes. The meson-python build backend builds Python wheels that contain compiled extensions; projects such as NumPy and SciPy use it.
Related Topics
- Build Tools — Build systems and their tradeoffs
- CMake — The most widely used C and C++ build generator
- Ninja — The backend Meson generates builds for
- GNU Make — The classic Unix build tool
- C — A language Meson commonly builds
- Python Packaging — Building wheels with compiled extensions