How do I do X in Meson?
This page lists code snippets for common tasks. These are written mostly using the C compiler, but the same approach should work on almost all other compilers.
Set compiler
When first running Meson, set it in an environment variable.
$ CC=mycc meson <options>
Note that environment variables like CC
only refer to the host
platform in cross builds. That is, CC
refers to the compiler used to
compile programs that run on the machine we will eventually install the
project on. The compiler used to build things that run on the machine we
do the building can be specified with CC_FOR_BUILD
. You can use it in
cross builds.
Note that environment variables are never the idiomatic way to do anything with Meson, however. It is better to use the native and cross files. And the tools for the host platform in cross builds can only be specified with a cross file.
There is a table of all environment variables supported Here
Set linker
New in 0.53.0
Like the compiler, the linker is selected via the <compiler variable>_LD
environment variable, or through the <compiler entry>_ld
entry in a native or cross file. You must be aware of
whether you're using a compiler that invokes the linker itself (most
compilers including GCC and Clang) or a linker that is invoked
directly (when using MSVC or compilers that act like it, including
Clang-Cl). With the former c_ld
or CC_LD
should be the value to
pass to the compiler's special argument (such as -fuse-ld
with clang
and gcc), with the latter it should be an executable, such as
lld-link.exe
.
NOTE In Meson 0.53.0 the ld
entry in the cross/native file and the
LD
environment variable were used, this resulted in a large number
of regressions and was changed in 0.53.1 to <lang>_ld
and <comp variable>_LD
.
$ CC=clang CC_LD=lld meson <options>
or
$ CC=clang-cl CC_LD=link meson <options>
or in a cross or native file:
[binaries]
c = 'clang'
c_ld = 'lld'
There is a table of all environment variables supported Here
Set default C/C++ language version
project('myproj', 'c', 'cpp',
default_options : ['c_std=c11', 'cpp_std=c++11'])
The language version can also be set on a per-target basis.
executable(..., override_options : ['c_std=c11'])
Enable threads
Lots of people seem to do this manually with cc.find_library('pthread')
or something similar. Do not do that. It is not portable. Instead do
this.
thread_dep = dependency('threads')
executable(..., dependencies : thread_dep)
Set extra compiler and linker flags from the outside (when e.g. building distro packages)
The behavior is the same as with other build systems, with environment variables during first invocation. Do not use these when you need to rebuild the source
$ CFLAGS=-fsomething LDFLAGS=-Wl,--linker-flag meson <options>
Use an argument only with a specific compiler
First check which arguments to use.
if meson.get_compiler('c').get_id() == 'clang'
extra_args = ['-fclang-flag']
else
extra_args = []
endif
Then use it in a target.
executable(..., c_args : extra_args)
If you want to use the arguments on all targets, then do this.
if meson.get_compiler('c').get_id() == 'clang'
add_global_arguments('-fclang-flag', language : 'c')
endif
Set a command's output to configuration
txt = run_command('script', 'argument', check: true).stdout().strip()
cdata = configuration_data()
cdata.set('SOMETHING', txt)
configure_file(...)
Generate configuration data from files
The fs module offers the read
function which enables adding
the contents of arbitrary files to configuration data (among other uses):
fs = import('fs')
cdata = configuration_data()
copyright = fs.read('LICENSE')
cdata.set('COPYRIGHT', copyright)
if build_machine.system() == 'linux'
os_release = fs.read('/etc/os-release')
cdata.set('LINUX_BUILDER', os_release)
endif
configure_file(...)
Generate a runnable script with configure_file
configure_file
preserves metadata so if your template file has
execute permissions, the generated file will have them too.
Producing a coverage report
First initialize the build directory with this command.
$ meson setup <other flags> -Db_coverage=true
Then issue the following commands.
$ meson compile
$ meson test
$ ninja coverage-html (or coverage-xml)
The coverage report can be found in the meson-logs subdirectory.
New in 0.55.0 llvm-cov support for use with clang
Add some optimization to debug builds
By default the debug build does not use any optimizations. This is the
desired approach most of the time. However some projects benefit from
having some minor optimizations enabled. GCC even has a specific
compiler flag -Og
for this. To enable its use, just issue the
following command.
$ meson configure -Dc_args=-Og
This causes all subsequent builds to use this command line argument.
Use address sanitizer
Clang and gcc come with a selection of analysis tools such as the address
sanitizer. Meson
has native support for these with the b_sanitize
option.
$ meson setup <other options> -Db_sanitize=address
After this you just compile your code and run the test suite. Address sanitizer will abort executables which have bugs so they show up as test failures.
Use Clang static analyzer
Install scan-build program, then do this:
$ meson setup builddir
$ ninja -C builddir scan-build
You can use the SCANBUILD
environment variable to choose the
scan-build executable.
$ SCANBUILD=<your exe> ninja -C builddir scan-build
You can use it for passing arguments to scan-build program by creating a script, for example:
#!/bin/sh
scan-build -v --status-bugs "$@"
And then pass it through the variable (remember to use absolute path):
$ SCANBUILD=$(pwd)/my-scan-build.sh ninja -C builddir scan-build
Use clippy
If your project includes Rust targets, you can invoke clippy like this:
$ meson setup builddir
$ ninja -C builddir clippy
Clippy will also obey the werror
builtin option.
By default Meson uses as many concurrent processes as there are cores
on the test machine. You can override this with the environment
variable MESON_NUM_PROCESSES
.
Meson will look for clippy-driver
in the same directory as rustc
,
or try to invoke it using rustup
if rustc
points to a rustup
binary. If clippy-driver
is not detected properly, you can add it to
a machine file.
Use profile guided optimization
Using profile guided optimization with GCC is a two phase operation. First we set up the project with profile measurements enabled and compile it.
$ meson setup <Meson options, such as --buildtype=debugoptimized> -Db_pgo=generate
$ meson compile -C builddir
Then we need to run the program with some representative input. This step depends on your project.
Once that is done we change the compiler flags to use the generated information and rebuild.
$ meson configure -Db_pgo=use
$ meson compile
After these steps the resulting binary is fully optimized.
Add math library (-lm
) portably
Some platforms (e.g. Linux) have a standalone math library. Other
platforms (pretty much everyone else) do not. How to specify that m
is used only when needed?
cc = meson.get_compiler('c')
m_dep = cc.find_library('m', required : false)
executable(..., dependencies : m_dep)
Install an executable to libexecdir
executable(..., install : true, install_dir : get_option('libexecdir'))
Use existing Find<name>.cmake
files
Meson can use the CMake find_package()
ecosystem if CMake is
installed. To find a dependency with custom Find<name>.cmake
, set
the cmake_module_path
property to the path in your project where the
CMake scripts are stored.
Example for a FindCmakeOnlyDep.cmake
in a cmake
subdirectory:
cm_dep = dependency('CmakeOnlyDep', cmake_module_path : 'cmake')
The cmake_module_path
property is only needed for custom CMake scripts. System
wide CMake scripts are found automatically.
More information can be found here
Get a default not-found dependency?
null_dep = dependency('', required : false)
This can be used in cases where you want a default value, but might override it later.
# Not needed on Windows!
my_dep = dependency('', required : false)
if host_machine.system() in ['freebsd', 'netbsd', 'openbsd', 'dragonfly']
my_dep = dependency('some dep', required : false)
elif host_machine.system() == 'linux'
my_dep = dependency('some other dep', required : false)
endif
executable(
'myexe',
my_sources,
deps : [my_dep]
)
Exclude a file from unity builds
If your project supports unity builds, you should fix any bugs that crop up when source files are concatenated together. Sometimes this isn't possible, though, for example if the source files are generated.
In this case, you can put them in a separate static library build target and override the unity setting.
generated_files = ...
unityproof_lib = static_library('unityproof', generated_files,
override_options : ['unity=off'])
main_exe = executable('main', main_sources, link_with : unityproof_lib)
To link the static library into another library target, you may need to use
link_whole
instead of link_with
.
The results of the search are