
Meson
- 331 installs
- 155 repo stars
- Updated June 27, 2026
- mohitmishra786/low-level-dev-skills
Configure Meson and Ninja builds for native libraries, cross-compiled firmware, and multi-language repos that need reproducible compile and test pipelines.
About
Teaches Meson project layout, dependency declarations, generator expressions, cross-compilation files, subproject wraps, and Ninja invocation. Useful when replacing hand-rolled Makefiles with portable builds for C, C++, and Rust-adjacent native code in CI and embedded firmware workflows.
- meson.build and meson_options.txt structure
- Cross files for embedded and multi-arch
- Subprojects and wrap dependency vendoring
- Ninja backend and install rules
- CTest and sanitizer flag injection
Meson by the numbers
- 331 all-time installs (skills.sh)
- +21 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #323 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill mesonAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 331 |
|---|---|
| repo stars | ★ 155 |
| Last updated | June 27, 2026 |
| Repository | mohitmishra786/low-level-dev-skills ↗ |
What it does
Configure Meson and Ninja builds for native libraries, cross-compiled firmware, and multi-language repos that need reproducible compile and test pipelines.
Files
Meson
Purpose
Guide agents through Meson project setup, build configuration, the wrap dependency system, and cross-compilation — covering the build system used by GLib, systemd, GStreamer, Mesa, and many major C/C++ projects.
Triggers
- "How do I set up a Meson build?"
- "How do I add a dependency in Meson?"
- "How do I cross-compile with Meson?"
- "Meson wrap isn't finding my dependency"
- "How do I configure build options in Meson?"
- "How do I migrate from CMake/Autotools to Meson?"
Workflow
1. Project setup
# Configure (source-dir, build-dir are positional)
meson setup builddir
# With options
meson setup builddir \
--buildtype=release \
--prefix=/usr/local \
-Db_lto=true \
-Db_sanitize=address
# Reconfigure (change options on existing builddir)
meson configure builddir -Dbuildtype=debug
# Show all available options
meson configure builddir--buildtype | Equivalent flags |
|---|---|
debug (default) | -O0 -g |
debugoptimized | -O2 -g |
release | -O3 -DNDEBUG |
minsize | -Os -DNDEBUG |
plain | No flags added |
2. Build and test
# Build (from source directory)
meson compile -C builddir
# Or enter builddir and use ninja directly
cd builddir && ninja
# Run tests
meson test -C builddir
meson test -C builddir --verbose # show test output
meson test -C builddir -t 5 # 5x timeout multiplier
meson test -C builddir --suite unit # run only 'unit' suite
# Install
meson install -C builddir
# Dry run
meson install -C builddir --dry-run3. meson.build structure
project('myapp', 'c', 'cpp',
version : '1.0.0',
default_options : [
'c_std=c11',
'cpp_std=c++17',
'warning_level=2',
]
)
# Find system dependencies
glib_dep = dependency('glib-2.0', version : '>=2.68')
threads_dep = dependency('threads')
# Include directories
inc = include_directories('include')
# Library
mylib = static_library('mylib',
sources : ['src/lib.c', 'src/util.c'],
include_directories : inc,
)
# Executable
executable('myapp',
sources : ['src/main.c'],
include_directories : inc,
link_with : mylib,
dependencies : [glib_dep, threads_dep],
install : true,
)
# Tests
test('basic', executable('test_basic',
sources : ['tests/test_basic.c'],
link_with : mylib,
))4. Dependency management with wrap
# Search for a wrap
meson wrap search zlib
# Install a wrap (downloads .wrap file from wrapdb)
meson wrap install zlib
meson wrap install gtest
# List installed wraps
meson wrap list
# Update all wraps
meson wrap updateIn meson.build:
# Use wrap as fallback if system lib not found
zlib_dep = dependency('zlib',
fallback : ['zlib', 'zlib_dep'], # [wrap_name, dep_variable]
)
# Force wrap (for reproducible builds)
zlib_dep = dependency('zlib',
fallback : ['zlib', 'zlib_dep'],
default_options : ['default_library=static'],
)subprojects/zlib.wrap structure:
[wrap-file]
directory = zlib-1.3
source_url = https://zlib.net/zlib-1.3.tar.gz
source_hash = <sha256>
[provide]
zlib = zlib_dep5. Build options
Define in meson_options.txt (or meson.options in Meson ≥1.1):
option('with_tests', type : 'boolean', value : true,
description : 'Build unit tests')
option('backend', type : 'combo',
choices : ['opengl', 'vulkan', 'software'],
value : 'opengl',
description : 'Rendering backend')
option('max_connections', type : 'integer',
min : 1, max : 1024, value : 64)Use in meson.build:
if get_option('with_tests')
subdir('tests')
endif6. Cross-compilation
Create a cross file (cross/arm-linux.ini):
[binaries]
c = 'arm-linux-gnueabihf-gcc'
cpp = 'arm-linux-gnueabihf-g++'
ar = 'arm-linux-gnueabihf-ar'
strip = 'arm-linux-gnueabihf-strip'
pkgconfig = 'arm-linux-gnueabihf-pkg-config'
[properties]
sys_root = '/path/to/sysroot'
[host_machine]
system = 'linux'
cpu_family = 'arm'
cpu = 'cortex-a9'
endian = 'little'meson setup builddir-arm --cross-file cross/arm-linux.ini
meson compile -C builddir-arm7. CMake migration cheatsheet
| CMake | Meson equivalent |
|---|---|
add_executable | executable() |
add_library | library() / static_library() / shared_library() |
target_include_directories | include_directories arg in target |
target_link_libraries | dependencies / link_with |
find_package | dependency() |
option() | option() in meson_options.txt |
add_subdirectory | subdir() |
install(TARGETS ...) | install : true in target |
For wrap patterns and subproject configuration, see references/meson-wrap.md.
Related skills
- Use
skills/build-systems/cmakewhen CMake is required or preferred - Use
skills/build-systems/ninja— Meson uses Ninja as its backend - Use
skills/compilers/cross-gccfor cross-compiler toolchain setup - Use
skills/compilers/gccorskills/compilers/clangfor compiler flag context
Meson Wrap Reference
Wrap File Types
wrap-file (archive download)
[wrap-file]
directory = libfoo-1.2.3
source_url = https://example.com/libfoo-1.2.3.tar.gz
source_hash = abc123...sha256...
[provide]
libfoo = libfoo_depwrap-git (git clone)
[wrap-git]
url = https://github.com/example/libfoo.git
revision = v1.2.3
depth = 1
[provide]
libfoo = libfoo_depwrap-redirect (alias to another wrap)
[wrap-redirect]
filename = subprojects/packagefiles/libfoo/meson.buildWrapdb Popular Packages
# View available packages
meson wrap search ""
# Common packages
meson wrap install zlib
meson wrap install openssl
meson wrap install sqlite3
meson wrap install gtest
meson wrap install benchmark # Google Benchmark
meson wrap install nlohmann_json
meson wrap install fmt
meson wrap install spdlog
meson wrap install libuv
meson wrap install expatSubproject Without wrapdb
Place source in subprojects/libfoo/:
subprojects/
└── libfoo/
├── meson.build # Must define libfoo_dep
└── src/
└── ...Reference in main meson.build:
libfoo_proj = subproject('libfoo')
libfoo_dep = libfoo_proj.get_variable('libfoo_dep')Patching Wrapped Projects
subprojects/
├── zlib.wrap
└── packagefiles/
└── zlib/
└── meson.build # Provides Meson build for non-Meson projectIn .wrap:
[wrap-file]
directory = zlib-1.3
source_url = https://zlib.net/zlib-1.3.tar.gz
source_hash = ...
patch_directory = zlib # Merges subprojects/packagefiles/zlib/ into sourceDependency Fallback Patterns
# Pattern 1: system-first, wrap fallback
zlib_dep = dependency('zlib', fallback : ['zlib', 'zlib_dep'])
# Pattern 2: wrap-only (reproducible builds)
zlib_dep = dependency('zlib',
fallback : ['zlib', 'zlib_dep'],
allow_fallback : true,
)
# Pattern 3: required=false, manual check
zlib_dep = dependency('zlib', required : false)
if not zlib_dep.found()
zlib_dep = subproject('zlib').get_variable('zlib_dep')
endif
# Pattern 4: force static from wrap
gtest_dep = dependency('gtest',
fallback : ['gtest', 'gtest_dep'],
default_options : ['default_library=static'],
)Common meson.build Patterns
Conditional compilation
conf = configuration_data()
conf.set('VERSION', meson.project_version())
conf.set10('HAVE_FEATURE', cc.has_function('feature_func'))
configure_file(input : 'config.h.in', output : 'config.h',
configuration : conf)Compiler checks
cc = meson.get_compiler('c')
# Check for function
have_mmap = cc.has_function('mmap', prefix : '#include <sys/mman.h>')
# Check for header
have_sys_epoll = cc.has_header('sys/epoll.h')
# Check for type
have_int128 = cc.has_type('__int128')
# Compile check
have_atomics = cc.compiles('''
#include <stdatomic.h>
int main() { atomic_int x = 0; return atomic_load(&x); }
''', name : 'C11 atomics')Install targets
executable('myapp', ..., install : true)
install_headers('include/mylib.h', subdir : 'mylib')
install_data('data/config.json', install_dir : get_option('datadir') / 'myapp')
install_man('doc/myapp.1')