meson

GitHub

The Meson Build System

6,500 stars Python Markdown Skills CodeWiki
AI Prompts & Endpoints
Agent Skills View CodeWiki Knowledge Base

README

Meson Documentation

Build dependencies

Meson uses itself and hotdoc for generating documentation.

Minimum required version of hotdoc is 0.8.9.

Instructions on how to install hotdoc are here.

Our custom hotdoc extensions require:
- chevron
- strictyaml

Building the documentation

From the Meson repository root dir:

text
$ cd docs/
$ meson setup built_docs/
$ ninja -C built_docs/

Now you should be able to open the documentation locally
text
built_docs/Meson documentation-doc/html/index.html

Upload

Meson uses the git-upload hotdoc plugin which basically
removes the html pages and replaces with the new content.

You can simply run:

text
$ ninja -C built_docs/ upload

---

Markdown/Snippets/Fix Intro Target Dependencies

Target introspection reports all direct target dependencies

The depends entry in intro-targets.json now reports direct target
dependencies from target inputs, generated sources, extracted objects,
internal linking, and explicit depends arguments. Previously it only
reported the dependencies attribute used by alias and run targets, so most
build target and custom target dependencies were omitted.

---

Markdown/Snippets/Rosetta Can Run Host Binaries

meson.can_run_host_binaries() now accounts for Rosetta 2 on Apple Silicon

Previously, when cross-compiling for x86_64 on an aarch64 Mac,
[[meson.can_run_host_binaries]] (and the underlying needs_exe_wrapper
logic) always returned false, even though Rosetta 2 lets these Macs
execute x86_64 binaries directly. Meson now detects whether Rosetta 2
is installed and, if so, reports that x86_64 host binaries can run
natively without requiring an exe_wrapper.

---

Markdown/Snippets/Subproject Lang Args

Per-subproject language arguments are now applied

Compiler and linker arguments set for a specific subproject, for example
-Dsub:c_args=-DFOO on the command line or c_args in the
default_options of a subproject() call, are now added to the compile
and link commands of that subproject's targets. Previously such values
were accepted and stored but silently ignored.

Similarly, <lang>_args and <lang>_link_args entries in a target's
override_options now take effect.

In all cases the per-subproject or per-target value replaces the global
value (including flags coming from environment variables such as
CFLAGS), it is not appended to it. This matches what
get_option('c_args') already returned inside a subproject.

---

Markdown/Snippets/Wild Linker

Wild linker is now supported on Linux

When CC_LD environment variables is set to wild, Meson will configure GCC 16+ or Clang
to use Wild as the linker on Linux. You should expect to see line like this in the output:
C linker for the host machine: cc ld.wild 0.10.0 confirming that Wild was picked up.

---

Markdown/ Include Qt Base

compile_resources

New in 0.59.0

Compiles Qt's resources collection files (.qrc) into c++ files for compilation.

It takes no positional arguments, and the following keyword arguments:
- name (string | empty): if provided a single .cpp file will be generated,
and the output of all qrc files will be combined in this file, otherwise
each qrc file be written to its own cpp file.
- sources (File | string | custom_target | custom_target index | generator_output)[]:
A list of sources to be transpiled. Required, must have at least one source
New in 0.60.0: support for custom_target, custom_target_index, and generator_output.
- extra_args string[]: Extra arguments to pass directly to qt-rcc
- method string: The method to use to detect Qt, see dependency() for more
information.

compile_ui

New in 0.59.0

Compiles Qt's ui files (.ui) into header files.

It takes no positional arguments, and the following keyword arguments:
- sources (File | string | custom_target | custom_target index | generator_output)[]:
A list of sources to be transpiled. Required, must have at least one source
New in 0.60.0: support for custom_target, custom_target_index, and generator_output.
- extra_args string[]: Extra arguments to pass directly to qt-uic
- method string: The method to use to detect Qt, see dependency() for more
information.
- preserve_paths bool: Since 1.4.0. If true, specifies that the output
files need to maintain their directory structure inside the target temporary
directory. For instance, when a file called subdir/one.input is processed
it generates a file {target private directory}/subdir/one.out when true,
and {target private directory}/one.out when false (default).

compile_moc

New in 0.59.0

Compiles Qt's moc files (.moc) into header and/or source files. At least one of
the keyword arguments headers and sources must be provided.

It takes no positional arguments, and the following keyword arguments:
- sources (File | string | custom_target | custom_target index | generator_output)[]:
A list of sources to be transpiled into .moc files for manual inclusion.
New in 0.60.0: support for custom_target, custom_target_index, and generator_output.
- headers (File | string | custom_target | custom_target index | generator_output)[]:
A list of headers to be transpiled into .cpp files
New in 0.60.0: support for custom_target, custom_target_index, and generator_output.
- extra_args string[]: Extra arguments to pass directly to qt-moc
- method string: The method to use to detect Qt, see dependency() for more
information.
- dependencies: dependency objects whose include directories are used by moc.
- include_directories (string | IncludeDirectory)[]: A list of include_directory()
objects used when transpiling the .moc files
- preserve_paths bool: New in 1.4.0. If true, specifies that the output
files need to maintain their directory structure inside the target temporary
directory. For instance, when a file called subdir/one.input is processed
it generates a file {target private directory}/subdir/one.out when true,
and {target private directory}/one.out when false (default).

preprocess

Consider using compile_resources, compile_ui, and compile_moc instead.

Takes sources for moc, uic, and rcc, and converts them into c++ files for
compilation.

Has the following signature: qt.preprocess(name: str | None, *sources: str)

If the name parameter is passed then all of the rcc files will be written to a single output file

The variadic sources arguments have been deprecated since Meson 0.59.0, as has the sources keyword argument. These passed files unmodified through the preprocessor, don't do this, just add the output of the generator to another sources list:

meson
sources = files('a.cpp', 'main.cpp', 'bar.c')
sources += qt.preprocess(qresources : ['resources'])

This method takes the following keyword arguments:
- qresources (string | File)[]: Passed to the RCC compiler
- ui_files: (string | File | CustomTarget)[]: Passed the uic compiler
- moc_sources: (string | File | CustomTarget)[]: Passed the moc compiler. These are converted into .moc files meant to be #includeed
- moc_headers: (string | File | CustomTarget)[]: Passed the moc compiler. These will be converted into .cpp files
- include_directories (IncludeDirectories | string)[], the directories to add to header search path for moc
- moc_extra_arguments string[]: any additional arguments to moc. Since v0.44.0.
- uic_extra_arguments string[]: any additional arguments to uic. Since v0.49.0.
- rcc_extra_arguments string[]: any additional arguments to rcc. Since v0.49.0.
- dependencies Dependency[]: dependency objects needed by moc. Available since v0.48.0.
- sources: a list of extra sources, which are added to the output unchanged. Deprecated in 0.59.0.
- preserve_paths bool: New in 1.4.0. If true, specifies that the output
files need to maintain their directory structure inside the target temporary
directory. For instance, when a file called subdir/one.input is processed
it generates a file {target private directory}/subdir/one.out when true,
and {target private directory}/one.out when false (default).

It returns an array of targets and sources to pass to a compilation target.

compile_translations

since 0.44.0

This method generates the necessary targets to build translation files with
lrelease, it takes no positional arguments, and the following keyword arguments:

- ts_files (File | string | custom_target | custom_target index | generator_output)[]:
the list of input translation files produced by Qt's lupdate tool.
New in 0.60.0: support for custom_target, custom_target_index, and generator_output.
- install bool: when true, this target is installed during the install step (optional).
- install_dir string: directory to install to (optional).
- build_by_default bool: when set to true, to have this target be built by
default, that is, when invoking meson compile; the default value is false
(optional).
- qresource string: rcc source file to extract ts_files from; cannot be used
with ts_files kwarg. Available since v0.56.0.
- rcc_extra_arguments string[]: any additional arguments to rcc (optional),
when used with qresource. Available since v0.56.0.

Returns either: a list of custom targets for the compiled
translations, or, if using a
qresource file, a single custom target
containing the processed source file, which should be passed to a main
build target.

has_tools

since 0.54.0

This method returns true if all tools used by this module are found,
false otherwise.

It should be used to compile optional Qt code:

meson
qt5 = import('qt5')
if qt5.has_tools(required: get_option('qt_feature'))
moc_files = qt5.preprocess(...)
...
endif

This method takes the following keyword arguments:
-
required bool | FeatureOption: by default, required is set to false. If required is set to
true or an enabled feature and some tools are
missing Meson will abort.
-
method string: method used to find the Qt dependency (auto by default).
-
version str | array[str]: Since 1.11.0. Specifies the required version,
a string containing a comparison operator followed by the version string.

Dependencies

See Qt dependencies

The 'modules' argument is used to include Qt modules in the project.
See the Qt documentation for the list of
modules
.

The 'private_headers' argument allows usage of Qt's modules private
headers. (since v0.47.0)

Example


A simple example would look like this:

meson
qt5 = import('qt5')
qt5_dep = dependency('qt5', modules: ['Core', 'Gui'])
inc = include_directories('includes')
moc_files = qt5.compile_moc(headers : 'myclass.h',
extra_args: ['-DMAKES_MY_MOC_HEADER_COMPILE'],
include_directories: inc,
dependencies: qt5_dep)
translations = qt5.compile_translations(ts_files : 'myTranslation_fr.ts', build_by_default : true)
executable('myprog', 'main.cpp', 'myclass.cpp', moc_files,
include_directories: inc,
dependencies : qt5_dep)

Sometimes, translations are embedded inside the binary using qresource
files. In this case the ts files do not need to be explicitly listed,
but will be inferred from the built qm files listed in the qresource
file. For example:

meson
qt5 = import('qt5')
qt5_dep = dependency('qt5', modules: ['Core', 'Gui'])
lang_cpp = qt5.compile_translations(qresource: 'lang.qrc')
executable('myprog', 'main.cpp', lang_cpp,
dependencies: qt5_dep)

---

Markdown/ Sidebar

Quick References

* Functions
* Options
* Configuration
* Dependencies
* Tests
* Syntax

Modules

* codegen
* gnome
* i18n
* pkgconfig
* rust
* wayland

---

Markdown/Adding Arguments

---
short-description: Adding compiler arguments
...

Adding arguments

Often you need to specify extra compiler arguments. Meson provides two
different ways to achieve this: global arguments and per-target
arguments.

Global arguments
--

Global compiler arguments are set with the following command. As an
example you could do this.

meson
add_global_arguments('-DFOO=bar', language : 'c')

This makes Meson add the define to all C compilations. Usually you
would use this setting for flags for global settings. Note that for
setting the C/C++ language standard (the
-std=c99 argument in GCC),
you would probably want to use a default option of the [[project]]
function. For details see the reference manual.

Global arguments have certain limitations. They all have to be defined
before any build targets are specified. This ensures that the global
flags are the same for every single source file built in the entire
project with one exception. Compilation tests that are run as part of
your project configuration do not use these flags. The reason for that
is that you may need to run a test compile with and without a given
flag to determine your build setup. For this reason tests do not use
these global arguments.

You should set only the most essential flags with this setting, you
should not set debug or optimization flags. Instead they should be
specified by selecting an appropriate build type.

Project arguments
--

Project arguments work similar to global arguments except that they
are valid only within the current subproject. The usage is simple:

meson
add_project_arguments('-DMYPROJ=projname', language : 'c')

This would add the compiler flags to all C sources in the current
project.

Per target arguments
--

Per target arguments are just as simple to define.

meson
executable('prog', 'prog.cc', cpp_args : '-DCPPTHING')

Here we create a C++ executable with an extra argument that is used
during compilation but not for linking.

You can find the parameter name for other languages in the reference
tables
.

Specifying extra linker arguments is done in the same way:

meson
executable('prog', 'prog.cc', link_args : '-Wl,--linker-option')

---

Markdown/Adding New Projects To Wrapdb

Adding new projects to WrapDB


How it works

New wraps must be submitted as a working subproject to the wrapdb
repository
.

There are two types of wraps on WrapDB - regular wraps and wraps with
Meson build definition patches.

Wraps with Meson build definition patches work in much the same way as
Debian: we take the unaltered upstream source package and add a new
build system to it as a patch. These build systems are stored as a
subdirectory of subprojects/packagefiles/. They only contain build
definition files. You may also think of them as an overlay to upstream
source.

Wraps without Meson build definition patches only contain the wrap
metadata describing how to fetch the project

Whenever a new release is pushed into the wrapdb, a new tag is
generated with an incremented version number, and a new release is
added to the wrapdb API listing. All the old releases remain
unaltered. New commits are always done via GitHub merge requests and
must be reviewed by someone other than the submitter.

Note that your Git repo with wrap must not contain the subdirectory of
the source release. That gets added automatically by the service. You
also must not commit any source code from the original tarball into
the wrap repository.

Choosing the wrap name

Wrapped subprojects are used much like external dependencies. Thus
they should have the same name as the upstream projects.

NOTE: Wrap names must fully match this regexp: [a-z0-9._]+.

If the project provides a pkg-config file, then the wrap name
should be the same as the pkg-config name. Usually this is the name of
the project, such as
libpng. Sometimes it is slightly different,
however. As an example the libogg project's chosen pkg-config name is
ogg instead of libogg, which is the reason why the wrap is
named plain
ogg.

If there is no pkg-config file, the name the project uses/promotes
should be used, lowercase only (Catch2 -> catch2).

If the project name is too generic or ambiguous (e.g. benchmark),
consider using
organization-project naming format (e.g.
google-benchmark).

Overriding dependencies in the submitted project

Ideally the project you submit should make a call to meson.override_dependency
for each dependency you would like to expose, with the first argument
matching the pkg-config file name. This abstracts away the
need to know and keep track of the variable names downstream.

For instance, the Apache Arrow project exposes multiple dependencies like
its base
arrow library, along with an arrow-compute library. The
project generates
arrow.pc and arrow-compute.pc files for pkg-config
respectively, so internally the project also calls:

meson
arrow_dep = declare_dependency(...)
meson.override_dependency('arrow', arrow_dep)

arrow_compute_dep = declare_dependency(...)
meson.override_dependency('arrow-compute', arrow_compute_dep)

How to contribute a new wrap

If the project already uses Meson build system, then only a wrap file
project.wrap should be provided. In other case a Meson build
definition patch - a set of
meson.build files - should also be
provided.

Creating the wrap contents

New release branches require a project.wrap file, so create one if
needed.

text
${EDITOR} upstream.wrap

The file format is simple, see any existing wrapdb subproject for the
content. The checksum is SHA-256 and can be calculated with the
following command on most unix-like operating systems:

text
sha256sum path/to/libfoo-1.0.0.tar.gz

Under macOS the command is the following:

text
shasum -a 256 path/to/libfoo-1.0.0.tar.gz

Next you need to add the entries that define what dependencies the
current project provides. This is important, as it is what makes
Meson's automatic dependency resolver work.

Assuming the project that you are creating
a wrap file for has called
meson.override_dependency, then you
can declare those overridden dependencies in the
provide section
of the wrap file:

ini
[provide]
dependency_names = arrow, arrow_compute

In the case that you do not control the upstream Meson configuration
and it does not already make a call to
meson.override_dependency,
then you can still expose dependency variables in the wrap file, using
a syntax like:

ini
[provide]
arrow = arrow_dep
arrow_compute = arrow_compute_dep

The arrow and arrow_compute parts on the left refer to the dependency
names, which should be the same as their Pkg-Config name.
arrow_dep and
arrow_compute_dep on the right refer to the variables in the build
definition that provide the dependencies. Most commonly, they hold the
result of a
declare_dependency call. If a variable of that name is
not defined, Meson will exit with a hard error. For further details see
the main Wrap manual.

However, it is strongly advised in such cases to request that the upstream
repository use
meson.override_dependency for its next release, so that
the variable names chosen in the upstream configuration file can be
decoupled from the wrap file contents.

Now you can create the build files, if the upstream project does not
contain any, and work on them until the project builds correctly.
Remember that all files go in the directory
subprojects/packagefiles/<project-name>.

text
${EDITOR} meson.build meson_options.txt

In order to apply the locally added build files to the upstream
release tarball, the
wrap-file section must contain a
patch_directory property naming the subdirectory in
subprojects/packagefiles/ with the build files inside, as this is
central to the way the wrapdb works. It will be used by the wrapdb
meson.build, and when a release is created, the files from this
directory will be converted into an archive and a patch_url will be
added to the wrap file.

When you are satisfied with the results, add the build files to Git, update
releases.json as described in
README.md, and push the result
to GitHub.

text
<verify that your project builds and runs>
git add releases.json subprojects/project.wrap subprojects/packagefiles/project/
git commit -a -m 'Add wrap files for libfoo-1.0.0'
git push -u origin libfoo

Now you should create a pull request on GitHub.

If packaging review requires you to do changes, use the --amend
argument to
commit so that your branch will have only one commit.

text
${EDITOR} meson.build
git commit -u --amend
git push --force

Changes to original source

The point of a wrap is to provide the upstream project with as few
changes as possible. Most projects should not contain anything more
than a few Meson definition files. Sometimes it may be necessary to
add a template header file or something similar. These should be held
at a minimum.

It should especially be noted that there must not be any patches
to functionality. All such changes must be submitted to upstream. You
may also host your own Git repo with the changes if you wish. The Wrap
system has native support for Git subprojects.

Passing automatic validation

Every submitted wrap goes through an automated correctness review and
passing it is a requirement for merging. Therefore it is highly
recommended that you run the validation checks yourself so you can fix
any issues faster.

You can test the wrap itself with the following commands:

meson subprojects purge --confirm
tools/sanity_checks.py

The first command is to ensure the wrap is correctly fetched from the
latest packagefiles. The second command builds the project and runs tests.

If you want to manually build the project without running the full test
suite, you can:

meson setup builddir/ -Dwraps=<project-name>

The GitHub project contains automatic CI on pushing to run the project
and check the metadata for obvious mistakes. This can be checked from
your fork before submitting a PR.

---

Markdown/Additional

---
short-description: Misc documentation
...

Additional documentation

This section references documents miscellaneous design, benchmarks, or
basically anything concerning Meson.

---

Markdown/ARM Performance Test

Arm performance test

Performance differences in build systems become more apparent on
slower platforms. To examine this difference we compared the
performance of Meson with GNU Autotools. We took the GLib software
project and rewrote its build setup with Meson. GLib was chosen
because it is a relatively large C code base which requires lots of
low level configuration.

The Meson version of the build system is not fully equivalent to the
original Autotools one. It does not do all the same configuration
steps and does not build all the same targets. The biggest missing
piece being internationalisation support with Gettext. However it does
configure the system enough to build all C source and run all unit
tests.

All measurements were done on a Nexus 4 smart phone running the latest
Ubuntu touch image (updated on September 9th 2013).

Measurements
------

The first thing we measured was the time it took to run the configure step.

Meson takes roughly 20 seconds whereas Autotools takes 220. This is a
difference of one order of magnitude. Autotools' time contains both
autogen and configure. Again it should be remembered that Meson does
not do all the configure steps that Autotools does. It does do about
90% of them and it takes just 10% of the time to do it.

Then we measured the build times. Two parallel compilation processes
were used for both systems.

On desktop machines Ninja based build systems are 10-20% faster than
Make based ones. On this platform the difference grows to 50%. The
difference is probably caused by Make's inefficient disk access
patterns. Ninja is better at keeping both cores running all the time
which yields impressive performance improvements.

Next we measured the "empty build" case. That is, how long does it
take for the build system to detect that no changes need to be
made. This is one of the most important metrics of build systems
because it places a hard limit on how fast you can iterate on your
code. Autotools takes 14 seconds to determine that no work needs to be
done. Meson (or, rather, Ninja) takes just one quarter of a second.

One step which takes quite a lot of time is linking. A common case is
that you are working on a library and there are tens of small test
executables that link to it. Even if the compilation step would be
fast, relinking all of the test executables takes time. It is common
for people to manually compile only one test application with a
command such as
make sometest rather than rebuild everything.

Meson has an optimization for this case. Whenever a library is
rebuilt, Meson inspects the ABI it exports. If it has not changed,
Meson will skip all relinking steps as unnecessary. The difference
this makes can be clearly seen in the chart above. In that test the
source was fully built, then the file
glib/gbytes.c was touched to
force the rebuild of the base glib shared library. As can be seen,
Autotools then relinks all test executables that link with glib. Since
Meson can detect that the ABI is the same it can skip those steps. The
end result being that Meson is almost one hundred times faster on this
very common use case.

Conclusions
-----

One of the main drawbacks of C and C++ compared to languages such as
Java are long compilation times. However at least some of the blame
can be found in the build tools used rather than the languages
themselves or their compilers. Choosing proper tools can bring C and
C++ compilation very close to instantaneous rebuilds. This has a
direct impact on programmer productivity.

---

Markdown/Build Options

---
short-description: Build options to configure project properties
...

Build options

Most non-trivial builds require user-settable options. As an example a
program may have two different data backends that are selectable at
build time. Meson provides for this by having an option definition
file. Its name is
meson.options and it is placed at the root of
your source tree. For versions of meson before 1.1, this file was called
meson_options.txt.

Here is a simple option file.

meson
option('someoption', type : 'string', value : 'optval', description : 'An option')
option('other_one', type : 'boolean', value : false)
option('combo_opt', type : 'combo', choices : ['one', 'two', 'three'], value : 'three')
option('integer_opt', type : 'integer', min : 0, max : 5, value : 3) # Since 0.45.0
option('free_array_opt', type : 'array', value : ['one', 'two']) # Since 0.44.0
option('array_opt', type : 'array', choices : ['one', 'two', 'three'], value : ['one', 'two'])
option('some_feature', type : 'feature', value : 'enabled') # Since 0.47.0
option('long_desc', type : 'string', value : 'optval',
description : 'An option with a very long description' +
'that does something in a specific context') # Since 0.55.0

For built-in options, see [Built-in options][builtin_opts].

Build option types

All types allow a description value to be set describing the option,
if no description is set then the name of the option will be used instead.

Strings

The string type is a free form string. If the default value is not set
then an empty string will be used as the default.

Booleans

Booleans may have values of either true or false. If no default
value is supplied then
true will be used as the default.

Combos

A combo allows any one of the values in the choices parameter to be
selected. If no default value is set then the first value will be the
default.

Integers

An integer option contains a single integer with optional upper and
lower values that are specified with the
min and max keyword
arguments.

This type is available since Meson version 0.45.0.

Arrays

Arrays represent an array of strings. By default the array can contain
arbitrary strings. To limit the possible values that can be used set the
choices parameter. Meson will then only allow the value array to
contain strings that are in the given list. The array may be
empty. The
value parameter specifies the default value of the option
and if it is unset then the values of
choices will be used as the
default.

As of 0.47.0 -Dopt= and -Dopt=[] both pass an empty list, before this
-Dopt= would pass a list with an empty string.

This type is available since version 0.44.0

Features

A feature option has three states: enabled, disabled or auto.
It is intended to be passed as a value for the
required keyword
argument of most functions. Currently supported in
[[add_languages]],
[[compiler.find_library]],
[[compiler.has_header]],
[[dependency]],
[[find_program]],
[[import]] and
[[subproject]]
functions.

- enabled is the same as passing required : true.
-
auto is the same as passing required : false.
-
disabled do not look for the dependency and always return 'not-found'.

When getting the value of this type of option using [[get_option]], a
special [[@feature]] object is returned instead
of the string representation of the option's value. This object can be
passed to
required:

meson
d = dependency('foo', required : get_option('myfeature'))
if d.found()
app = executable('myapp', 'main.c', dependencies : [d])
endif

To check the value of the feature, the object has three methods
returning a boolean and taking no argument:

- .enabled()
-
.disabled()
-
.auto()

This is useful for custom code depending on the feature:

meson
if get_option('myfeature').enabled()
# ...
endif

If the value of a feature option is set to auto, that value is
overridden by the global
auto_features option (which defaults to
auto). This is intended to be used by packagers who want to have
full control on which dependencies are required and which are
disabled, and not rely on build-deps being installed (at the right
version) to get a feature enabled. They could set
auto_features=enabled to enable all features and disable explicitly
only the few they don't want, if any.

This type is available since version 0.47.0

Deprecated options

Since 0.60.0

Project options can be marked as deprecated and Meson will warn when user sets a
value to it. It is also possible to deprecate only some of the choices, and map
deprecated values to a new value.

meson

Option fully deprecated, it warns when any value is set.


option('o1', type: 'boolean', deprecated: true)

One of the choices is deprecated, it warns only when 'a' is in the list of values.


option('o2', type: 'array', choices: ['a', 'b'], deprecated: ['a'])

One of the choices is deprecated, it warns only when 'a' is in the list of values


and replace it by 'c'.


option('o3', type: 'array', choices: ['a', 'b', 'c'], deprecated: {'a': 'c'})

A boolean option has been replaced by a feature, old true/false values are remapped.


option('o4', type: 'feature', deprecated: {'true': 'enabled', 'false': 'disabled'})

A feature option has been replaced by a boolean, enabled/disabled/auto values are remapped.


option('o5', type: 'boolean', deprecated: {'enabled': 'true', 'disabled': 'false', 'auto': 'false'})

Since 0.63.0 the deprecated keyword argument can take the name of a new option
that replaces this option. In that case, setting a value on the deprecated option
will set the value on both the old and new names, assuming they accept the same
values.

meson

A boolean option has been replaced by a feature with another name, old true/false values


are accepted by the new option for backward compatibility.


option('o6', type: 'boolean', value: 'true', deprecated: 'o7')
option('o7', type: 'feature', value: 'enabled', deprecated: {'true': 'enabled', 'false': 'disabled'})

A project option is replaced by a module option


option('o8', type: 'string', value: '', deprecated: 'python.platlibdir')

Using build options

meson
optval = get_option('opt_name')

This function also allows you to query the value of Meson's built-in
project options. For example, to get the installation prefix you would
issue the following command:

meson
prefix = get_option('prefix')

It should be noted that you cannot set option values in your Meson
scripts. They have to be set externally with the
meson configure
command line tool. Running
meson configure without arguments in a
build dir shows you all options you can set.

To change their values use the -D
option:

console
$ meson configure -Doption=newvalue

Setting the value of arrays is a bit special. If you only pass a
single string, then it is considered to have all values separated by
commas. Thus invoking the following command:

console
$ meson configure -Darray_opt=foo,bar

would set the value to an array of two elements, foo and bar.

If you need to have commas in your string values, then you need to
pass the value with proper shell quoting like this:

console
$ meson configure "-Doption=['a,b', 'c,d']"

The inner values must always be single quotes and the outer ones
double quotes.

To change values in subprojects prepend the name of the subproject and
a colon:

console
$ meson configure -Dsubproject:option=newvalue

NOTE: If you cannot call meson configure you likely have an old
version of Meson. In that case you can call
mesonconf instead, but
that is deprecated in newer versions

Yielding to superproject option

Suppose you have a master project and a subproject. In some cases it
might be useful to have an option that has the same value in both of
them. This can be achieved with the
yield keyword. Suppose you have
an option definition like this:

meson
option('some_option', type : 'string', value : 'value', yield : true)

If you build this project on its own, this option behaves like
usual. However if you build this project as a subproject of another
project which also has an option called
some_option, then calling
get_option returns the value of the superproject. If the value of
yield is false, get_option returns the value of the subproject's
option.

Since 1.8.0 -Dsub:some_option=anothervalue, when used with a
yielding option, sets the value separately from the option
it yields to.


Built-in build options

There are a number of [built-in options][builtin_opts]. To get the
current list execute
meson configure in the build directory.

[builtin_opts]: https://mesonbuild.com/Builtin-options.html

Visual Studio

#### Startup project

The backend_startup_project option can be set to define the default
project that will be executed with the "Start debugging F5" action in
visual studio. It should be the same name as an executable target
name.

meson
project('my_project', 'c', default_options: ['backend_startup_project=my_exe'])
executable('my_exe', ...)

Ninja

#### Max links

The backend_max_links can be set to limit the number of processes
that ninja will use to link.

---

Markdown/Build System Converters

---
short-description: Converting other build systems to Meson
...

Build system converters

Moving from one build system into another includes a fair bit of
work. To make things easier, Meson provides scripts to convert other
build systems into Meson. At the time of writing, scripts for CMake
and autotools exist. It can be found in the
tools subdirectory in
Meson's source tree.

The scripts do not try to do a perfect conversion. This would be
extremely difficult because the data models of other build systems are
very different. The goal of the converter script is to convert as much
of the low level drudgery as possible. Using the scripts is
straightforward. We'll use the CMake one as an example but the
Autotools one works exactly the same way.

cmake2meson.py path/to/CMake/project/root

This command generates a skeleton Meson project definition that tries
to mirror CMake's setup as close as possible. Once this is done, you
need to go through these files manually and finalize the
conversion. To make this task as simple as possible, the converter
script will transfer all comments from the CMake definition into Meson
definition.

---

Markdown/Build Targets

---
short-description: Definition of build targets
...

Build targets

Meson provides four kinds of build targets: executables, libraries
(which can be set to be built as static or shared or both of them at
the build configuration time), static libraries, and shared libraries.
They are created with the commands
executable, library,
static_library and shared_library, respectively. All objects created
in this way are immutable. That is, you cannot change any aspect of
them after they have been constructed. This ensures that all information
pertaining to a given build target is specified in one well defined
place.

Libraries and executables
--

As an example, here is how you would build a library.

meson
project('shared lib', 'c')
library('mylib', 'source.c')

It is generally preferred to use the library command instead of
shared_library and static_library and then configure which
libraries (static or shared or both of them) will be built at the
build configuration time using the
default_library
built-in option.

In Unix-like operating systems, shared libraries can be
versioned. Meson supports this with keyword arguments, which will be
ignored if the library is configured as static at the compile time.

meson
project('shared lib', 'c')
library('mylib', 'source.c', version : '1.2.3', soversion : '1')

It is common to build a library and then an executable that links
against it. This is supported as well.

meson
project('shared lib', 'c')
lib = library('mylib', 'source.c')
executable('program', 'prog.c', link_with : lib)

Meson sets things up so that the resulting executable can be run
directly from the build directory. There is no need to write shell
scripts or set environment variables.

One target can have multiple language source files.

meson
project('multilang', 'c', 'cpp')
executable('multiexe', 'file.c', 'file2.cc')

Object files
--

Sometimes you can't build files from sources but need to utilize an
existing object file. A typical case is using an object file provided
by a third party. Object files can be specified just like sources.

meson
exe = executable('myexe', 'source.cpp', objects : 'third_party_object.o')

A different case is when you want to use object files built in one
target directly in another. A typical case is when you build a shared
library and it has an internal class that is not exported in the
ABI. This means you can't access it even if you link against the
library. Typical workarounds for this include building both a shared
and static version of the library or putting the source file in the
test executable's source list. Both of these approaches cause the
source to be built twice, which is slow.

In Meson you can extract object files from targets and use them as-is
on other targets. This is the syntax for it.

meson
lib = shared_library('somelib', 'internalclass.cc', 'file.cc', ...)
eo = lib.extract_objects('internalclass.cc')
executable('classtest', 'classtest.cpp', objects : eo)

Here we take the internal class object and use it directly in the
test. The source file is only compiled once.

Note that careless use of this feature may cause strange bugs. As an
example trying to use objects of an executable or static library in a
shared library will not work because shared library objects require
special compiler flags. Getting this right is the user's
responsibility. For this reason it is strongly recommended that you
only use this feature for generating unit test executables in the
manner described above.

---

Markdown/Builtin Options

---
short-description: Built-in options to configure project properties
...

Built-in options

Meson provides two kinds of options: build options provided by the
build files
and built-in options that are either
universal options, base options, compiler options.

Universal options

All these can be set by passing -Doption=value to meson (aka meson
setup), or by setting them inside default_options of [[project]] in your
meson.build. Some options can also be set by --option=value, or --option
value -- a list is shown by running meson setup --help.

For legacy reasons --warnlevel is the cli argument for the
warning_level option.

They can also be edited after setup using meson configure
-Doption=value.

Installation options are usually relative to the prefix but it should
not be relied on, since they can be absolute paths in the following cases:

* When the prefix is /usr: sysconfdir defaults to /etc,
localstatedir defaults to /var, and sharedstatedir defaults to
/var/lib
* When the prefix is
/usr/local: localstatedir defaults
to
/var/local, and sharedstatedir defaults to /var/local/lib
* When an absolute path outside of prefix is provided by the user/distributor.

Directories

| Option | Default value | Description |
| ------ | ------------- | ----------- |
| prefix | see below | Installation prefix |
| bindir | bin | Executable directory |
| datadir | share | Data file directory |
| includedir | include | Header file directory |
| infodir | share/info | Info page directory |
| libdir | see below | Library directory |
| licensedir | see below | Licenses directory (since 1.1.0)|
| libexecdir | libexec | Library executable directory |
| localedir | share/locale | Locale data directory |
| localstatedir | var | Localstate data directory |
| mandir | share/man | Manual page directory |
| sbindir | sbin | System executable directory |
| sharedstatedir | com | Architecture-independent data directory |
| sysconfdir | etc | Sysconf data directory |


prefix defaults to C:/ on Windows, and /usr/local otherwise. You
should always override this value.

libdir is automatically detected based on your platform, it should
be correct when doing "native" (build machine == host machine)
compilation. For cross compiles Meson will try to guess the correct
libdir, but it may not be accurate, especially on Linux where
different distributions have different defaults. Using a cross
file
, particularly the
paths section may be necessary.

licensedir is empty by default. If set, it defines the default location
to install a dependency manifest and project licenses. For more details,
see [[meson.install_dependency_manifest]].

Core options

Options that are labeled "per machine" in the table are set per
machine. See the specifying options per
machine
section for details.

| Option | Default value | Description | Is per machine | Per subproject (since) |
| -------------------------------------- | ------------- | ----------- | -------------- | ---------------------- |
| auto_features {enabled, disabled, auto} | auto | Override value of all 'auto' features | no | no |
| backend {ninja, vs,<br>vs2010, vs2012, vs2013, vs2015, vs2017, vs2019, vs2022, xcode, none} | ninja | Backend to use | no | no |
| genvslite {vs2022} | vs2022 | Setup multi-buildtype ninja build directories and Visual Studio solution | no | no |
| buildtype {plain, debug,<br>debugoptimized, release, minsize, custom} | debug | Build type to use | no | 1.8.0 |
| debug | true | Enable debug symbols and other information | no | 1.8.0 |
| default_both_libraries {shared, static, auto} | shared | Default library type for both_libraries | no | 1.8.0 |
| default_library {shared, static, both} | shared | Default library type | no | 0.54.0 |
| errorlogs | true | Whether to print the logs from failing tests. | no | no |
| install_umask {preserve, 0000-0777} | 022 | Default umask to apply on permissions of installed files | no | no |
| layout {mirror,flat} | mirror | Build directory layout | no | no |
| namingscheme {platform, classic} | classic | Library naming scheme to use | no | 1.10.0 |
| optimization {plain, 0, g, 1, 2, 3, s} | 0 | Optimization level | no | 1.8.0 |
| pkg_config_path {OS separated path} | '' | Additional paths for pkg-config to search before builtin paths | yes | no |
| prefer_static | false | Whether to try static linking before shared linking | no | no |
| cmake_prefix_path | [] | Additional prefixes for cmake to search before builtin paths | yes | no |
| stdsplit | true | Split stdout and stderr in test logs | no | no |
| strip | false | Strip targets on install | no | 1.8.0 |
| unity {on, off, subprojects} | off | Unity build | no | 1.8.0 |
| unity_size {>=2} | 4 | Unity file block size | no | 1.8.0 |
| warning_level {0, 1, 2, 3, everything} | 1 | Set the warning level. From 0 = compiler default to everything = highest | no | 0.56.0 |
| werror | false | Treat warnings as errors | no | 0.54.0 |
| wrap_mode {default, nofallback,<br>nodownload, forcefallback, nopromote} | default | Wrap mode to use | no | no |
| force_fallback_for | [] | Force fallback for those dependencies | no | no |
| vsenv | false | Activate Visual Studio environment | no | no |
| os2_emxomf | false | Use OMF format on OS/2 | no | no |

(For the Rust language only, warning_level=0 disables all warnings).

#### Details for backend

Several build file formats are supported as command runners to build the
configured project. Meson prefers ninja by default, but platform-specific
backends are also available for better IDE integration with native tooling:
Visual Studio for Windows, and xcode for macOS. It is also possible to
configure with no backend at all, which is an error if you have targets to
build, but for projects that need configuration + testing + installation allows
for a lighter automated build pipeline.

#### Details for genvslite

Setup multiple buildtype-suffixed, ninja-backend build directories (e.g.
[builddir]_[debug/release/etc.]) and generate [builddir]_vs containing a Visual
Studio solution with multiple configurations that invoke a meson compile of the
setup build directories, as appropriate for the current configuration (buildtype).

This has the effect of a simple setup macro of multiple 'meson setup ...'
invocations with a set of different buildtype values. E.g.
meson setup ... --genvslite vs2022 somebuilddir does the following -

text
meson setup ... --backend ninja --buildtype debug somebuilddir_debug
meson setup ... --backend ninja --buildtype debugoptimized somebuilddir_debugoptimized
meson setup ... --backend ninja --buildtype release somebuilddir_release

and additionally creates another 'somebuilddir_vs' directory that contains
a generated multi-configuration visual studio solution and project(s) that are
set to build/compile with the somebuilddir_[...] that's appropriate for the
solution's selected buildtype configuration.

#### Details for buildtype

<a name="build-type-options"></a> For setting optimization levels and
toggling debug, you can either set the
buildtype option, or you can
set the
optimization and debug options which give finer control
over the same. Whichever you decide to use, the other will be deduced
from it. For example,
-Dbuildtype=debugoptimized is the same as
-Ddebug=true -Doptimization=2 and vice-versa. This table documents
the two-way mapping:

| buildtype | debug | optimization |
| --------- | ----- | ------------ |
| plain | false | plain |
| debug | true | 0 |
| debugoptimized | true | 2 |
| release | false | 3 |
| minsize | true | s |

All other combinations of debug and optimization set buildtype to 'custom'.

Note that -Ddebug=false does not cause the compiler preprocessor macro
NDEBUG to be defined.
The macro can be defined using the base option
b_ndebug, described below.

#### Details for warning_level

Exact flags per warning level is compiler specific, but there is an approximate
table for most common compilers.

| Warning level | GCC/Clang | MSVC |
| ------------- | --- | ---- |
| 0 | | |
| 1 | -Wall | /W2 |
| 2 | -Wall -Wextra | /W3 |
| 3 | -Wall -Wextra -Wpedantic | /W4 |
| everything | -Weverything | /Wall |

Clang's -Weverything is emulated on GCC by passing all known warning flags.

#### Details for vsenv

The --vsenv argument is supported since 0.60.0, -Dvsenv=true syntax is supported
since
1.1.0.

Since 0.59.0, meson automatically activates a Visual Studio environment on Windows
for all its subcommands, but only if no other compilers (e.g.
gcc or clang)
are found, and silently continues if Visual Studio activation fails.

Setting the vsenv option to true forces Visual Studio activation even when other
compilers are found. It also make Meson abort with an error message when activation
fails.

vsenv is true by default when using the vs backend.


#### Details for
default_both_libraries

Since 1.6.0, you can specify the default type of library selected when using a
both_libraries object with default_both_libraries. Note that, unlike
default_library, this option does not affect how the library artifacts are
built, but how they are internally linked to the dependent targets within the
same project.

The possible values of this option are 'shared' (default value, compatible with
previous meson versions), 'static', and 'auto'. With auto, the value from the
default_library option is used, unless it is 'both', in which case 'shared' is
used instead.

When default_both_libraries is 'auto', passing a [[@both_libs]] dependency
in [[both_libraries]] will link the static dependency with the static lib,
and the shared dependency with the shared lib.

#### Details for os2_emxomf

The --os2-emxomf argument is supported since 1.10.0, -Dos2_emxomf=true
syntax is supported since
1.10.0.

Setting the os2_emxomf option to true forces to use emxomf toolchains in
order to generate OMF files instead of aout toolchains.

os2_emxomf is false by default.

Base options

These are set in the same way as universal options, either by
-Doption=value, or by setting them inside default_options of
[[project]] in your
meson.build. However, they cannot be shown in
the output of
meson setup --help because they depend on both the current
platform and the compiler that will be selected. The only way to see
them is to setup a builddir and then run
meson configure on it with
no options.

The following options are available. Note that they may not be
available on all platforms or with all compilers:

| Option | Default value | Possible values | Description |
|---------------------|----------------------|---------------------------------------------------------------|--------------------------------------------------------------------------------|
| b_asneeded | true | true, false | Use -Wl,--as-needed when linking |
| b_bitcode | false | true, false | Embed Apple bitcode, see below |
| b_colorout | always | auto, always, never | Use colored output |
| b_coverage | false | true, false | Enable coverage tracking |
| b_lundef | true | true, false | Don't allow undefined symbols when linking |
| b_lto | false | true, false | Use link time optimization |
| b_lto_threads | 0 | Any integer | Use multiple threads for lto. (Added in 0.57.0)* |
| b_lto_mode | default | default, thin | Select between lto modes, thin and default. (Added in 0.57.0) |
| b_thinlto_cache | false | true, false | Enable LLVM's ThinLTO cache for faster incremental builds. (Added in 0.64.0) |
| b_thinlto_cache_dir | (Internal build dir) | true, false | Specify where to store ThinLTO cache objects. (Added in 0.64.0) |
| b_ndebug | false | true, false, if-release | Disable asserts |
| b_pch | true | true, false | Use precompiled headers |
| b_pgo | off | off, generate, use | Use profile guided optimization |
| b_sanitize | none | see below | Code sanitizer to use |
| b_staticpic | true | true, false | Build static libraries as position independent |
| b_pie | false | true, false | Build position-independent executables (since 0.49.0) |
| b_vscrt | from_buildtype | none, md, mdd, mt, mtd, from_buildtype, static_from_buildtype | VS runtime library to use (since 0.48.0) (static_from_buildtype since 0.56.0) |

The default and possible values of sanitizers changed in 1.8. Before 1.8 they
were string values, and restricted to a specific subset of values:
none,
address, thread, undefined, memory, leak, or address,undefined. In
1.8 it was changed to a free form array of sanitizers, which are checked by a
compiler and linker check. For backwards compatibility reasons
get_option('b_sanitize') continues to return a string with the array values
separated by a comma. Furthermore:

- If the b_sanitize option is empty, the 'none' string is returned.

- If it contains only the values 'address' and 'undefined', they are
always returned as the
'address,undefined' string, in this order.

- Otherwise, the array elements are returned in undefined order.

Be aware that b_lundef is true by default, which is incompatible with the
address sanitizer when building shared libraries with clang, as documented
by clang
(
b_lundef makes meson use -Wl,--no-undefined, which is an alias for -Wl,-z,defs).

\* < 0 means disable, == 0 means automatic selection, > 0 sets a specific number to use

LLVM supports thin lto, for more discussion see LLVM's documentation

<a name="b_vscrt-from_buildtype"></a>
The default value of
b_vscrt is from_buildtype. The following table is
used internally to pick the CRT compiler arguments for
from_buildtype or
static_from_buildtype (since 0.56) based on the value of the buildtype
option:

| buildtype | from_buildtype | static_from_buildtype |
| -------- | -------------- | --------------------- |
| debug |
/MDd | /MTd |
| debugoptimized |
/MD | /MT |
| release |
/MD | /MT |
| minsize |
/MD | /MT |
| custom | error! | error! |

Notes about Apple Bitcode support

b_bitcode will pass -fembed-bitcode while compiling and will pass
-Wl,-bitcode_bundle while linking. These options are incompatible
with
b_asneeded, so that option will be silently disabled.

[[shared_module]]s will not have
bitcode embedded because
-Wl,-bitcode_bundle is incompatible with
-Wl,-undefined,dynamic_lookup which is necessary for shared modules to work.

Compiler options

Same caveats as base options above.

The following options are available. They can be set by passing
-Doption=value to meson. Note that both the options themselves and
the possible values they can take will depend on the target platform
or compiler being used:

| Option | Default value | Possible values | Description |
| ------ | ------------- | --------------- | ----------- |
| c_args | | free-form comma-separated list | C compile arguments to use |
| c_link_args | | free-form comma-separated list | C link arguments to use |
| c_std | none | none, c89, c99, c11, c17, c18, c2x, c23, c2y, gnu89, gnu99, gnu11, gnu17, gnu18, gnu2x, gnu23, gnu2y | C language standard to use |
| c_winlibs | see below | free-form comma-separated list | Standard Windows libs to link against |
| c_thread_count | 4 | integer value ≥ 0 | Number of threads to use with emcc when using threads |
| cpp_args | | free-form comma-separated list | C++ compile arguments to use |
| cpp_link_args | | free-form comma-separated list | C++ link arguments to use |
| cpp_std | none | none, c++98, c++03, c++11, c++14, c++17, c++20 <br/>c++2a, c++1z, gnu++03, gnu++11, gnu++14, gnu++17, gnu++1z, <br/> gnu++2a, gnu++20, vc++14, vc++17, vc++20, vc++latest | C++ language standard to use |
| cpp_debugstl | false | true, false | C++ STL debug mode |
| cpp_eh | default | none, default, a, s, sc | C++ exception handling type |
| cpp_rtti | true | true, false | Whether to enable RTTI (runtime type identification) |
| cpp_thread_count | 4 | integer value ≥ 0 | Number of threads to use with emcc when using threads |
| cpp_winlibs | see below | free-form comma-separated list | Standard Windows libs to link against |
| cpp_importstd | false | true or false | Whether to use
import std |
| fortran_std | none | [none, legacy, f95, f2003, f2008, f2018] | Fortran language standard to use |
| rust_dynamic_std | false | true, false | Whether to link dynamically to the Rust standard library (Added in 1.9.0) |
| rust_nightly | auto | enabled, disabled, auto | Nightly Rust compiler (enabled=required, disabled=don't use nightly feature, auto=use nightly feature if available) (Added in 1.10.0) |
| cuda_ccbindir | | filesystem path | CUDA non-default toolchain directory to use (-ccbin) (Added in 0.57.1) |

The default values of c_winlibs and cpp_winlibs are in
compiler-specific argument forms, but the libraries are: kernel32,
user32, gdi32, winspool, shell32, ole32, oleaut32, uuid, comdlg32,
advapi32.

All these <lang>_* options are specified per machine. See below in
the specifying options per machine
section on how to do this in cross builds.

When using MSVC, cpp_eh=[value] will result in /EH[value] being passed.
The magic value
none translates to s-c- to disable exceptions. *Since
0.51.0*
default translates to sc. When using gcc-style compilers, nothing
is passed (allowing exceptions to work), while
cpp_eh=none passes
-fno-exceptions.

Since 0.54.0 The <lang>_thread_count option can be used to control
the value passed to
-s PTHREAD_POOL_SIZE when using emcc. No other
c/c++ compiler supports this option.

Since 0.63.0 all compiler options can be set per subproject, see
here for details on how the default value
is inherited from the main project. This is useful, for example, when the main
project requires C++11, but a subproject requires C++14. The
cpp_std value
from the subproject's
default_options is now respected.

Since 1.3.0 c_std and cpp_std options now accept a list of values.
Projects that prefer GNU C, but can fallback to ISO C, can now set, for
example,
default_options: 'c_std=gnu11,c11', and it will use gnu11 when
available, but fallback to c11 otherwise. It is an error only if none of the
values are supported by the current compiler.
Likewise, a project that can take benefit of
c++17 but can still build with
c++11 can set default_options: 'cpp_std=c++17,c++11'.
This allows us to deprecate
gnuXX values from the MSVC compiler. That means
that
default_options: 'c_std=gnu11' will now print a warning with MSVC
but fallback to
c11. No warning is printed if at least one
of the values is valid, i.e.
default_options: 'c_std=gnu11,c11'.
In the future that deprecation warning will become an hard error because
c_std=gnu11 should mean GNU is required, for projects that cannot be
built with MSVC for example.

Specifying options per machine

Since 0.51.0, some options are specified per machine rather than
globally for all machine configurations. Prefixing the option with
build. only affects the build machine configuration, while leaving it
unprefixed only affects the host machine configuration.
For example:

- build.pkg_config_path controls the paths pkg-config will search
for
native: true (build machine) dependencies.

- pkg_config_path controls the paths pkg-config will search for
native: false (host machine) dependencies.

This is useful for cross builds. In native builds, the build and host
machines are the same, and the unprefixed option alone will suffice.

Prior to 0.51.0, these options only affected native builds when
specified on the command line as there was no
build. prefix.
Similarly named fields in the
[properties] section of the cross file
would affect cross compilers, but the code paths were fairly different,
allowing differences in behavior to crop out.

Specifying options per subproject

Several built-in options and all compiler options can be defined per subproject.
This is useful, for example, when building shared libraries in the main project
and statically linking a subproject, or when the main project must build
with no warnings but some subprojects cannot.

Most of the time, this would be used either in the parent project by
setting subproject's default_options (e.g.
subproject('foo',
default_options: 'default_library=static')), or by the user through the
command line:
-Dfoo:default_library=static.

The value is overridden in this order:
-
opt=value from parent project's default_options
-
opt=value from subproject's default_options
-
opt=value from machine file
-
opt=value from command line
-
subp:opt=value from parent project's default options
-
opt=value from subproject() default_options
-
subp:opt=value from machine file
-
subp:opt=value from command line

Old behavior

Between 0.54.0 and 1.7.x only a few options could be defined per subproject:
default_library and werror since 0.54.0*;
warning_level since 0.56.0*;
compiler options since 0.63.0*

The value was overridden in this order:

- opt=value from parent project's default_options
-
opt=value from machine file
-
opt=value from command line
-
opt=value from subproject's default_options
-
subp:opt=value from parent project's default options
-
opt=value from subproject() default_options
-
subp:opt=value from machine file
-
subp:opt=value from command line

In other word, the subproject's default_options had a higher priority
than
opt=value from machine file or command line.

Module options

Some Meson modules have built-in options. They can be set by prefixing the
option with the module's name:
-D<module>.<option>=<value> (e.g. -Dpython.platlibdir=/foo).

Pkgconfig module

| Option | Default value | Possible values | Description |
|-------------|---------------|-----------------|------------------------------------------------------------|
| relocatable | false | true, false | Generate the pkgconfig files as relocatable (Since 0.63.0) |

Since 0.63.0 The pkgconfig.relocatable option is used by the
pkgconfig module–namely
pkg.generate()–and
affects how the
prefix (not to be confused with the
install prefix) in the generated pkgconfig file is set.
When it is
true, the prefix will be relative to the install_dir-this
allows the pkgconfig file to be moved around and still work, as long
as the relative path is not broken. In general, this allows for the whole
installed package to be placed anywhere on the system and still work as a
dependency. When it is set to
false, the prefix will be the same as
the install prefix.

An error will be raised if pkgconfig.relocatable is true and the
install_dir for a generated pkgconfig file points outside the
install prefix. For example: if the install prefix is
/usr and the
install_dir for a pkgconfig file is /var/lib/pkgconfig.

Python module

| Option | Default value | Possible values | Description |
| ------ | ------------- | ----------------- | ----------- |
| bytecompile | 0 | integer from -1 to 2 | What bytecode optimization level to use (Since 1.2.0) |
| install_env | prefix | {auto,prefix,system,venv} | Which python environment to install to (Since 0.62.0) |
| platlibdir | | Directory path | Directory for site-specific, platform-specific files (Since 0.60.0) |
| purelibdir | | Directory path | Directory for site-specific, non-platform-specific files (Since 0.60.0) |
| allow_limited_api | true | true, false | Disables project-wide use of the Python Limited API (Since 1.3.0) |
| build_config | | File path | Specifies the Python build configuration file (PEP 739) (Since 1.10.0) |

Since 0.60.0 The python.platlibdir and python.purelibdir options are used
by the python module methods
python.install_sources() and
python.get_install_dir(); Meson tries to detect the correct installation paths
and make them relative to the installation
prefix by default which will often
result in the interpreter not finding the installed python modules unless
prefix is /usr on Linux, or, for instance, C:\Python39 on Windows. These
options can be absolute paths outside of
prefix.

Since 0.62.0 The python.install_env option is used to detect the correct
installation path. Setting to
system will avoid making the paths relative to
prefix and instead use the global site-packages of the selected python
interpreter directly, even if it is a venv. Setting to
venv will instead use
the paths for the virtualenv the python found installation comes from (or fail
if it is not a virtualenv). Setting to
auto will check if the found
installation is a virtualenv, and use
venv or system as appropriate (but
never
prefix). Note that Conda environments are treated as system.
This option is mutually exclusive with the
platlibdir/purelibdir.

For backwards compatibility purposes, the default install_env is prefix.

Since 1.2.0 The python.bytecompile option can be used to enable compiling
python bytecode. Bytecode has 3 optimization levels:

- 0, bytecode without optimizations
- 1, bytecode with some optimizations
- 2, bytecode with some more optimizations

To this, Meson adds level -1, which is to not attempt to compile bytecode at
all.

Since 1.3.0 The python.allow_limited_api option affects whether the
limited_api keyword argument of the extension_module method is respected.
If set to
false, the effect of the limited_api argument is disabled.

---

Markdown/CMake Module

CMake module

Note: the functionality of this module is governed by Meson's
rules on mixing build systems
.

This module provides helper tools for generating cmake package files.
It also supports the usage of CMake based subprojects, similar to
the normal Meson subprojects.


Usage

To use this module, just do: cmake = import('cmake'). The
following functions will then be available as methods on the object
with the name
cmake. You can, of course, replace the name cmake
with anything else.

It is generally recommended to use the latest Meson version and
CMake >=3.17 for best compatibility. CMake subprojects will
usually also work with older CMake versions. However, this can
lead to unexpected issues in rare cases.

CMake subprojects

Using CMake subprojects is similar to using the "normal" Meson
subprojects. They also have to be located in the
subprojects
directory.

Example:

cmake
add_library(cm_lib SHARED ${SOURCES})

meson
cmake = import('cmake')

Configure the CMake project


sub_proj = cmake.subproject('libsimple_cmake')

Fetch the dependency object


cm_lib = sub_proj.dependency('cm_lib')

executable('exe1', ['sources'], dependencies: [cm_lib])

The subproject method is almost identical to the normal Meson
[[subproject]] function. The only difference is that a CMake project
instead of a Meson project is configured.

The returned sub_proj supports the same options as a "normal"
subproject. Meson automatically detects CMake build targets, which can
be accessed with the methods listed below.

It is usually enough to just use the dependency object returned by the
dependency() method in the build targets. This is almost identical
to using the [[declare_dependency]] object from a normal Meson subproject.

It is also possible to use executables defined in the CMake project as code
generators with the
target() method:

cmake
add_executable(cm_exe ${EXE_SRC})

meson
cmake = import('cmake')

Subproject with the "code generator"


sub_pro = cmake.subproject('cmCodeGen')

Fetch the code generator exe


sub_exe = sub_pro.target('cm_exe')

Use the code generator


generated = custom_target(
'cmake-generated',
input: [],
output: ['test.cpp'],
command: [sub_exe, '@OUTPUT@']
)

It should be noted that not all projects are guaranteed to work. The
safest approach would still be to create a
meson.build for the
subprojects in question.

Configuration options

New in meson 0.55.0

Meson also supports passing configuration options to CMake and overriding
certain build details extracted from the CMake subproject.

meson
cmake   = import('cmake')
opt_var = cmake.subproject_options()

Call CMake with -DSOME_OTHER_VAR=ON


opt_var.add_cmake_defines({'SOME_OTHER_VAR': true})

Globally override the C++ standard to c++11


opt_var.set_override_option('cpp_std', 'c++11')

Override the previous global C++ standard


with c++14 only for the CMake target someLib


opt_var.set_override_option('cpp_std', 'c++14', target: 'someLib')

sub_pro = cmake.subproject('someLibProject', options: opt_var)

Further changes to opt_var have no effect

See the CMake options object for a complete
reference of all supported functions.

The CMake configuration options object is very similar to the
[[@cfg_data]] object] object returned
by [[configuration_data]]. It
is generated by the
subproject_options method.

All configuration options have to be set before the subproject is
configured and must be passed to the
subproject method via the
options key. Altering the configuration object won't have any effect
on previous
cmake.subproject calls.

In earlier Meson versions CMake command-line parameters could be set
with the
cmake_options kwarg. However, this feature is deprecated
since 0.55.0 and only kept for compatibility. It will not work
together with the
options kwarg.

subproject object

This object is returned by the subproject method described above
and supports the following methods:

- dependency(target) returns a dependency object for any CMake target. The
include_type kwarg (new in 0.56.0) controls the include type of the
returned dependency object similar to the same kwarg in the
[[dependency]] function.
-
include_directories(target) returns an array of Meson [[@inc]]
objects for the specified target. Using this method is not necessary
if the dependency object is used.
-
target(target) returns the raw build target.
-
target_type(target) returns the type of the target as a string
-
target_list() returns a list of all target names.
-
get_variable(name) fetches the specified variable from inside
the subproject. Usually
dependency() or target() should be
preferred to extract build targets.
-
found returns true if the subproject is available, otherwise false
new in Meson 0.53.2

cmake options object

This object is returned by the subproject_options() method and
consumed by the
options kwarg of the subproject method. The
following methods are supported:

- add_cmake_defines({'opt1': val1, ...}) add additional CMake commandline defines
-
set_override_option(opt, val) set specific build options
for targets. This will effectively add
opt=val to the override_options
array of the [[build_target]]
-
set_install(bool) override whether targets should be installed or not
-
append_compile_args(lang, arg1, ...) append compile flags for a specific
language to the targets
-
append_link_args(arg1, ...) append linker args to the targets
-
clear() reset all data in the cmake options object

The methods set_override_option, set_install,
append_compile_args and append_link_args support the optional
target kwarg. If specified, the set options affect the specific
target. The effect of the option is global for the subproject
otherwise.

If, for instance, opt_var.set_install(false) is called, no target
will be installed regardless of what is set by CMake. However, it is
still possible to install specific targets (here
foo) by setting the
target kwarg: opt_var.set_install(true, target: 'foo')

Options that are not set won't affect the generated subproject. So, if
for instance,
set_install was not called then the values extracted
from CMake will be used.

Cross compilation

New in 0.56.0

Meson will try to automatically guess most of the required CMake
toolchain variables from existing entries in the cross and native
files. These variables will be stored in an automatically generated
CMake toolchain file in the build directory. The remaining variables
that can't be guessed can be added by the user in the
[cmake]
cross/native file section (new in 0.56.0).

Adding a manual CMake toolchain file is also supported with the
cmake_toolchain_file setting in the [properties] section. Directly
setting a CMake toolchain file with
-DCMAKE_TOOLCHAIN_FILE=/path/to/some/Toolchain.cmake in the
meson.build is not supported since the automatically generated
toolchain file is also used by Meson to inject arbitrary code into
CMake to enable the CMake subproject support.

The closest configuration to only using a manual CMake toolchain file
would be to set these options in the machine file:

ini
[properties]

cmake_toolchain_file = '/path/to/some/Toolchain.cmake'
cmake_defaults = false

[cmake]

No entries in this section

This will result in a toolchain file with just the bare minimum to
enable the CMake subproject support and
include() the
cmake_toolchain_file as the last instruction.

For more information see the cross and native file
specification
.

CMake configuration files

cmake.write_basic_package_version_file()

This method is the equivalent of the corresponding CMake
function
,
it generates a
name package version file.

* name: the name of the package.
*
version: the version of the generated package file.
*
compatibility: a string indicating the kind of compatibility, the accepted values are
AnyNewerVersion, SameMajorVersion, SameMinorVersion or ExactVersion.
It defaults to
AnyNewerVersion. Depending on your cmake installation some kind of
compatibility may not be available.
arch_independent: new in 0.62.0*, if true the generated package file
will skip architecture checks. Useful for header-only libraries.
*
install_dir: optional installation directory, it defaults to $(libdir)/cmake/$(name)


Example:

meson
cmake = import('cmake')

cmake.write_basic_package_version_file(name: 'myProject', version: '1.0.0')

cmake.configure_package_config_file()

This method is the equivalent of the corresponding CMake
function
,
it generates a
name package configuration file from the input
template file. Just like the cmake function in this file the
@PACKAGE_INIT@ statement will be replaced by the appropriate piece
of cmake code. The equivalent
PATH_VARS argument is given through
the
configuration parameter.

* name: the name of the package.
*
input: the template file where that will be treated for variable substitutions contained in configuration.
*
install_dir: optional installation directory, it defaults to $(libdir)/cmake/$(name).
*
configuration: a configuration_data object that will be used for variable substitution in the template file.
Since 0.62.0 it can take a dictionary instead.


Example:

meson.build:

meson
cmake = import('cmake')

conf = configuration_data()
conf.set_quoted('VAR', 'variable value')

cmake.configure_package_config_file(
name: 'myProject',
input: 'myProject.cmake.in',
configuration: conf
)

myProject.cmake.in:

text
@PACKAGE_INIT@

set(MYVAR VAR)

---

Markdown/Code Formatting

---
short-description: Code formatting
...

clang-format

Since 0.50.0

When clang-format is installed and a .clang-format file is found at the main
project's root source directory, Meson automatically adds a
clang-format target
that reformat all C and C++ files (currently only with Ninja backend).

sh
ninja -C builddir clang-format

Since 0.58.0

It is possible to restrict files to be reformatted with optional
.clang-format-include and .clang-format-ignore files.

The file .clang-format-include contains a list of patterns matching the files
that will be reformatted. The
pattern matches this directory and all
subdirectories recursively. Empty lines and lines starting with
# are ignored.
If
.clang-format-include is not found, the pattern defaults to /* which
means all files recursively in the source directory but has the disadvantage to
walk the whole source tree which could be slow in the case it contains lots of
files.

Example of .clang-format-include file:

text

All files in src/ and its subdirectories


src//*

All files in include/ but not its subdirectories


include/*

The file .clang-format-ignore contains a list of patterns matching the files
that will be excluded. Files matching the include list (see above) that match
one of the ignore pattern will not be reformatted. Unlike include patterns, ignore
patterns does not support
and a single * match any characters including
path separators. Empty lines and lines starting with
# are ignored.

The build directory and file without a well known C or C++ suffix are always
ignored.

Example of .clang-format-ignore file:

text

Skip C++ files in src/ directory


src/*.cpp

Note that .clang-format-ignore has the same format as used by
run-clang-format.py.

A new target clang-format-check has been added. It returns an error code if
any file needs to be reformatted. This is intended to be used by CI.

Since 0.60.0

If .clang-format-include file is missing and source files are in a git
repository, only files tracked by git will be included.

---

Markdown/Codegen Module

---
short-description: Common Code Generators Module
authors:
- name: Dylan Baker
email: [email protected]
years: [2024, 2025]
...

Codegen Module

(New in 1.10.0)

This module provides wrappers around common code generators, such as flex/lex and yacc/bison. This purpose of this is to make it easier and more pleasant to use common code generators in a mesonic way.

Functions

lex()

meson
lex_gen = codegen.lex(implementations : ['flex', 'reflex'], flex_version : ['>= 2.6', '< 3'], reflex_version : '!= 1.4.2')

This function provides fine grained control over what implementation(s) and version(s) of lex are acceptable for a given project (These are set per-subproject). It returns a new object, which can be used to generate code.

It accepts the following keyword arguments:

- implementations: a string array of acceptable implementations to use. May include: lex, flex, reflex, or win_flex.
-
lex_version: a string array of version constraints to apply to the lex binary
-
flex_version: a string array of version constraints to apply to the flex binary
-
reflex_version: a string array of version constraints to apply to the relex binary
-
win_flex_version: a string array of version constraints to apply to the win_flex binary
-
required: A boolean or feature option
-
disabler: Return a disabler if not found
-
native: Is this generator for the host or build machine?

yacc()

meson
yacc = codegen.yacc(implementations : ['bison', 'win_bison'])

This function provides fine grained controls over which implementation(s) and version(s) of the parser generator to use.

Accepts the following keyword arguments:

- implementations: a string array of acceptable implementations to use. May include: yacc, byacc, bison, or win_bison.
-
yacc_version: a string array of version constraints to apply to the yacc binary
-
byacc_version: a string array of version constraints to apply to the byacc binary
-
bison_version: a string array of version constraints to apply to the bison binary
-
win_bison_version: a string array of version constraints to apply to the win_bison binary
-
required: A boolean or feature option
-
disabler: Return a disabler if not found
-
native: Is this generator for the host or build machine?

Returned Objects

LexGenerator

#### lex.implementation

meson
lex = codegen.lex()
impl = lex.implementation()

Returns the string name of the lex implementation chosen. May be one of:

- lex
- flex
- reflex
- win_flex

#### lex.generate

meson
lex = codegen.lex()
lex.generate('lexer.l')

This function wraps flex, lex, reflex (but not RE/flex), and win_flex (on Windows). When using win_flex it will automatically add the --wincompat argument.

This requires an input file, which may be a string, File, or generated source. It additionally takes the following options keyword arguments:

- args: An array of extra arguments to pass the lexer
-
plainname: If set to true then @PLAINNAME@ will be used as the source base, otherwise @BASENAME@.
-
source: the name of the source output. If this is unset Meson will use {base}.{ext} with an extension of cpp if the input has an extension of .ll, or c otherwise, with base being determined by the plainname argument.
-
header: The optional output name for a header file. If this is unset no header is added
-
table: The optional output name for a table file. If this is unset no table will be generated

The outputs will be in the form source [header] [table], which means those can be accessed by indexing the output of the lex call:

meson
lex = codegen.lex()
l1 = lex.generate('lexer.l', header : '@[email protected]', table : '@[email protected]')
headers = [l1[1], l1[2]] # [header, table]

l2 = lex.generate('lexer.l', table : '@[email protected]')
table = l2[1]

YaccGenerator

#### yacc.implementation

meson
yacc = codegen.yacc()
impl = yacc.implementation()

Returns the string name of the yacc implementation chosen. May be one of:

- yacc
- bison
- byacc
- win_bison

#### yacc.generate

meson
yacc = codegen.yacc()
yacc.generate('parser.y')

This function wraps bison, yacc, byacc, and win_bison (on Windows), and attempts to abstract away the differences between them

This requires an input file, which may be a string, File, or generated source. It additionally takes the following options keyword arguments:

- version: Version constraints on the lexer
-
args: An array of extra arguments to pass the lexer
-
plainname: If set to true then @PLAINNAME@ will be used as the source base, otherwise @BASENAME@.
-
source: the name of the source output. If this is unset Meson will use {base}.{ext} with an extension of cpp if the input has an extension of .yy or c otherwise, with base being determined by the plainname argument.
-
header: the name of the header output. If this is unset Meson will use {base}.{ext} with an extension of hpp if the input has an extension of .yy or h otherwise, with base being determined by the plainname argument.
-
locations: The name of the locations file, if one is generated. Due to the way yacc works this must be duplicated in the file and in the command.

The outputs will be in the form source header [locations], which means those can be accessed by indexing the output of the yacc call:

meson
yacc = codegen.yacc()
p1 = yacc.generate('parser.y', header : '@[email protected]', locations : 'locations.h')
headers = [p1[1], p1[2]] # [header, locations]

p2 = yacc.generate('parser.yy', locations : 'locations.hpp')
locations = p2[1]

---

Markdown/Commands

Command-line commands

There are two different ways of invoking Meson. First, you can run it
directly from the source tree with the command
/path/to/source/meson.py. Meson may also be installed in which case
the command is simply
meson. In this manual we only use the latter
format for simplicity.

Meson is invoked using the following syntax:
meson [COMMAND] [COMMAND_OPTIONS]

This section describes all available commands and some of their
Optional arguments. The most common workflow is to run
setup, followed by compile, and then
install.

For the full list of all available options for a specific command use
the following syntax:
meson COMMAND --help

configure

{{ configure_usage.inc }}

Changes options of a configured meson project.

{{ configure_arguments.inc }}

Most arguments are the same as in setup.

Note: reconfiguring project will not reset options to their default
values (even if they were changed in
meson.build).

#### Examples:

List all available options:

text
meson configure builddir

Change value of a single option:

text
meson configure builddir -Doption=new_value

compile

(since 0.54.0)

{{ compile_usage.inc }}

Builds a default or a specified target of a configured Meson project.

{{ compile_arguments.inc }}

--verbose argument is available since 0.55.0.

#### Targets

(since 0.55.0)

TARGET has the following syntax [PATH/]NAME.SUFFIX[:TYPE], where:
-
NAME: name of the target from meson.build (e.g. foo from executable('foo', ...)).
-
SUFFIX: name of the suffix of the target from meson.build (e.g. exe from executable('foo', suffix: 'exe', ...)).
-
PATH: path to the target relative to the root meson.build file. Note: relative path for a target specified in the root meson.build is ./.
-
TYPE: type of the target. Can be one of the following: 'executable', 'static_library', 'shared_library', 'shared_module', 'custom', 'alias', 'run', 'jar'.

PATH, SUFFIX, and TYPE can all be omitted if the resulting TARGET can be
used to uniquely identify the target in
meson.build.

Note that SUFFIX did not exist prior to 1.3.0.

#### Backend specific arguments

(since 0.55.0)

BACKEND-args use the following syntax:

If you only pass a single string, then it is considered to have all
values separated by commas. Thus invoking the following command:

text
$ meson compile --ninja-args=-n,-d,explain

would add -n, -d and explain arguments to ninja invocation.

If you need to have commas or spaces in your string values, then you
need to pass the value with proper shell quoting like this:

text
$ meson compile "--ninja-args=['a,b', 'c d']"

#### Examples:

Build the project:

text
meson compile -C builddir

Execute a dry run on ninja backend with additional debug info:

text
meson compile --ninja-args=-n,-d,explain

Build three targets: two targets that have the same foo name, but
different type, and a
bar target:

text
meson compile foo:shared_library foo:static_library bar

Produce a coverage html report (if available):

text
ninja coverage-html

dist

(since 0.52.0)

{{ dist_usage.inc }}

Generates a release archive from the current source tree.

{{ dist_arguments.inc }}

See notes about creating releases for more info.

#### Examples:

Create a release archive:

text
meson dist -C builddir

init

(since 0.45.0)

{{ init_usage.inc }}

Creates a basic set of build files based on a template.

{{ init_arguments.inc }}

#### Examples:

Create a project in sourcedir:

text
meson init -C sourcedir

env2mfile

This command is experimental and subject to change.

{Since 0.62.0}

{{ env2mfile_usage.inc }}

Create native and cross files from the current environment, typically
by sniffing environment variables like
CC and CFLAGS.

{{ env2mfile_arguments.inc }}

#### Examples:

Autodetect the current cross build environment:

text
meson env2mfile --cross -o current_cross.txt --cpu=arm7a --cpu-family=arm --system=linux

Generate a cross build using Debian system information:

text
meson env2mfile --cross --debarch=armhf -o deb_arm_cross.txt

introspect

{{ introspect_usage.inc }}

Displays information about a configured Meson project.

{{ introspect_arguments.inc }}

#### Examples:

Display basic information about a configured project in builddir:

text
meson introspect builddir --projectinfo

install

(since 0.47.0)

{{ install_usage.inc }}

Installs the project to the prefix specified in setup.

{{ install_arguments.inc }}

See the installation documentation for more info.

#### Examples:

Install project to prefix:

text
meson install -C builddir

Install project to $DESTDIR/prefix:

text
DESTDIR=/path/to/staging/area meson install -C builddir

Since 0.60.0 DESTDIR and --destdir can be a path relative to build
directory. An absolute path will be set into environment when executing scripts.

reprotest

(since 1.6.0)

{{ reprotest_usage.inc }}

Simple reproducible build tester that compiles the project twice and
checks whether the end results are identical.

This command must be run in the source root of the project you want to
test.

{{ reprotest_arguments.inc }}

#### Examples

meson reprotest

Builds the current project with its default settings.

meson reprotest --intermediaries -- --buildtype=debugoptimized

Builds the target and also checks that all intermediate files like
object files are also identical. All command line arguments after the
-- are passed directly to the underlying meson invocation. Only
use option arguments, i.e. those that start with a dash, Meson sets
directory arguments automatically.

rewrite

(since 0.50.0)

{{ rewrite_usage.inc }}

Modifies the Meson project.

{{ rewrite_arguments.inc }}

See the Meson file rewriter documentation for more info.

setup

{{ setup_usage.inc }}

Configures a build directory for the Meson project.

Deprecated since 0.64.0: This is the default Meson command (invoked if there
was no COMMAND supplied). However, supplying the command is necessary to avoid
clashes with future added commands, so "setup" should be used explicitly.

Since 1.1.0 --reconfigure is allowed even if the build directory does not
already exist, that argument is ignored in that case.

Since 1.3.0 If the build directory already exists, options are updated with
their new value given on the command line (
-Dopt=value). Unless --reconfigure
is also specified, this won't reconfigure immediately. This has the same behaviour
as
meson configure <builddir> -Dopt=value.

Since 1.3.0 It is possible to clear the cache and reconfigure in a single command
with
meson setup --clearcache --reconfigure <builddir>.

{{ setup_arguments.inc }}

See Meson introduction
page
for more info.

#### Examples:

Configures builddir with default values:

text
meson setup builddir

subprojects

(since 0.49.0)

{{ subprojects_usage.inc }}

Manages subprojects of the Meson project. Since 0.59.0 commands are run on
multiple subprojects in parallel by default, use
--num-processes=1 if it is
not desired.

Since 0.64.0 the update subcommand will not download new wrap files
from WrapDB any more. Use
meson wrap update command for that instead.

{{ subprojects_arguments.inc }}

test

{{ test_usage.inc }}

Run tests for the configure Meson project.

{{ test_arguments.inc }}

See the unit test documentation for more info.

Since 1.2.0 you can use wildcards in args for test names.
For example, "bas*" will match all test with names beginning with "bas".

Since 1.2.0 it is an error to provide a test name or wildcard that
does not match any test.

#### Examples:

Run tests for the project:

text
meson test -C builddir

Run only specific_test_1 and specific_test_2:

text
meson test -C builddir specific_test_1 specific_test_2

wrap

{{ wrap_usage.inc }}

An utility to manage WrapDB dependencies.

{{ wrap_arguments.inc }}

See the WrapDB tool documentation for more info.

devenv

(since 0.58.0)

{{ devenv_usage.inc }}

Runs a command, or open interactive shell if no command is provided, with
environment setup to run project from the build directory, without installation.

We automatically handle bash and set $PS1 accordingly. If the automatic $PS1
override is not desired (maybe you have a fancy custom prompt), set the
$MESON_DISABLE_PS1_OVERRIDE environment variable and use $MESON_PROJECT_NAME
when setting the custom prompt, for example with a snippet like the following:

bash
...
if [[ -n "${MESON_PROJECT_NAME-}" ]];
then
PS1+="[ ${MESON_PROJECT_NAME} ]"
fi
...

These variables are set in environment in addition to those set using [[meson.add_devenv]]:
-
MESON_DEVENV is defined to '1'.
-
MESON_PROJECT_NAME is defined to the main project's name.
-
PKG_CONFIG_PATH includes the directory where Meson generates -uninstalled.pc
files.
-
PATH includes every directory where there is an executable that would be
installed into
bindir. On windows it also includes every directory where there
is a DLL needed to run those executables.
-
LD_LIBRARY_PATH includes every directory where there is a shared library that
would be installed into
libdir. This allows to run system application using
custom build of some libraries. For example running system GEdit when building
GTK from git. On OSX the environment variable is
DYLD_LIBRARY_PATH and
PATH on Windows.
-
GI_TYPELIB_PATH includes every directory where a GObject Introspection
typelib is built. This is automatically set when using
gnome.generate_gir().
-
GSETTINGS_SCHEMA_DIR Since 0.59.0 includes every directory where a GSettings
schemas is compiled. This is automatically set when using
gnome.compile_schemas().
Note that this requires GLib >= 2.64 when
gnome.compile_schemas() is used in
more than one directory.
-
QEMU_LD_PREFIX Since 1.0.0 is set to the sys_root value from cross file
when cross compiling and that property is defined.
-
XDG_DATA_DIRS Since 1.11.0 if not set in user's environment, the default value
/usr/local/share:/usr/share is set before adding project paths.
-
XDG_CONFIG_DIRS Since 1.11.0 if not set in user's environment, the default value
/etc/xdg is set before adding project paths.

Since 0.62.0 if bash-completion scripts are being installed and the
shell is bash, they will be automatically sourced.

Since 0.62.0 when GDB helper scripts (-gdb.py, -gdb.gdb, and *-gdb.csm)
are installed with a library name that matches one being built, Meson adds the
needed auto-load commands into
<builddir>/.gdbinit file. When running gdb from
top build directory, that file is loaded by gdb automatically. In the case of
python scripts that needs to load other python modules,
PYTHONPATH may need
to be modified using
meson.add_devenv().

Since 0.63.0 when cross compiling for Windows WINEPATH is used instead
of
PATH which allows running Windows executables using wine. Note that since
WINEPATH size is currently limited to 1024 characters, paths relative to the
root of build directory are used. That means current workdir must be the root of
build directory when running wine.

Since 1.1.0 meson devenv --dump [<filename>] command takes an optional
filename argument to write the environment into a file instead of printing to
stdout.

Since 1.1.0 --dump-format argument has been added to select which shell
format should be used. There are currently 3 formats supported:
-
sh: Lines are in the format VAR=/prepend:$VAR:/append.
-
export: Same as sh but with extra export VAR lines.
-
vscode: Same as sh but without $VAR substitution because they do not
seems to be properly supported by vscode.

{{ devenv_arguments.inc }}


format

(since 1.5.0)

{{ format_usage.inc }}

Format specified meson.build documents. For compatibility with muon, fmt
is an alias to
format.

{{ format_arguments.inc }}

The configuration file is a .ini file. If a meson.format file exists
beside the provided build file to analyze, and no configuration file is
provided on the command line, the
meson.format file is automatically used.

If no build file is provided on the command line, the meson.build file in
current directory is analyzed.

The following options are recognized:

- max_line_length (int): When an array, a dict, a function or a method
would be longer that this, it is formatted one argument per line
(Default is 80).
- indent_by (str): Indentation to use (Default is four spaces
' ').
- space_array (bool): Whether to add spaces between
[] and array
arguments (default is false).
- kwargs_force_multiline (bool): If true, arguments are formatted one per
line as soon as there is a keyword argument (default is false).
- wide_colon (bool): If true, a space is placed before colon in dict
and in keyword arguments (default is false).
- no_single_comma_function (bool): If true, a comma is never appended
to function arguments if there is only one argument, even if
using multiline arguments (default is false).
- end_of_line ('cr', 'lf', 'crlf', 'native'): Line ending to use
(applied when using
--output or --inline argument) (default
is 'native).
- indent_before_comments (str): Indentation to use before inline comments
(default is two spaces
' ').
- simplify_string_literals (bool): When true, multiline strings are
converted to single line strings if they don't contain newlines.
Formatted strings are converted to normal strings if they don't
contain substitutions (default is true).
- insert_final_newline (bool): If true, force the
meson.build file
to end with a newline character (default is true).
- tab_width (int): Width of tab stops, used to compute line length
when
indent_by uses tab characters (default is 4).
- sort_files (bool): When true, arguments of
files() function are
sorted (default was true before 1.11.0; since 1.11.0 it is false).
Since 1.11.0, arguments are sorted
naturally rather than
alphabetically.
- group_arg_value (bool): When true, string argument with
-- prefix
followed by string argument without
-- prefix are grouped on the
same line, in multiline arguments (default is false).
- use_editor_config (bool): When true, also uses config from .editorconfig .

The first six options are the same than for the muon fmt command.

It is also possible to use a .editorconfig file, by providing
the
--editor-config option on the command line, or with the
use_editor_config option in the config file.

When --recursive option is specified, meson.build files from
subdir are also analyzed (must be used in conjunction with --inplace
or
--check-only option).

Since 1.7.0 You can use - as source file name to read source from standard
input instead of reading it from a file. This cannot be used with
--recursive
or
--inline arguments.

Since 1.9.0 Using - as source file with --editor-config now requires
--source-file-path argument to ensure consistent results.

Since 1.10.0 When --check-diff is specified, instead of silently exiting
with an error code,
meson format will print a diff of the formatting changes.


#### Differences with
muon fmt

The meson format command should be compatible with the muon fmt command.
However, it has more features, and some differences:

- By default, meson format put two spaces before inline comments,
while
muon fmt only puts one.
-
muon fmt can potentially mix crlf and lf end-of-lines, as it is not aware
of them.
meson format will always be consistent in the output it produces.
-
muon fmt only recognize the indent_by option from .editorconfig files.
meson format also recognizes max_line_length, end_of_line,
insert_final_newline and tab_width options.
-
meson format has many additional format rules (see option list above).

---

Markdown/Comparisons

---
title: Comparisons
...

Comparing Meson with other build systems

A common question is *Why should I choose Meson over a different build
system X?* There is no one true answer to this as it depends on the
use case. Almost all build systems have all the functionality needed
to build medium-to-large projects so the decision is usually made on
other points. Here we list some pros and cons of various build systems
to help you do the decision yourself.

GNU Autotools

Pros

Excellent support for legacy Unix platforms, large selection of
existing modules.

Cons

Needlessly slow, complicated, hard to use correctly, unreliable,
painful to debug, incomprehensible for most people, poor support for
non-Unix platforms (especially Windows).

CMake

Pros

Great support for multiple backends (Visual Studio, XCode, etc).

Cons

The scripting language is cumbersome to work with. Some simple things
are more complicated than necessary.

SCons

Pros

Full power of Python available for defining your build.

Cons

Slow. Requires you to pass your configuration settings on every
invocation. That is, if you do
scons OPT1 OPT2 and then just
scons, it will reconfigure everything without settings OPT1 and
OPT2. Every other build system remembers build options from the
previous invocation.

Bazel

Pros

Proven to scale to very large projects.

Cons

Implemented in Java. Poor Windows support. Heavily focused on Google's
way of doing things (which may be a good or a bad thing). Contributing
code requires signing a CLA.

Meson

Pros

The fastest build system see
measurements
, user friendly, designed to
be as invisible to the developer as possible, native support for
modern tools (precompiled headers, coverage, Valgrind etc). Not Turing
complete so build definition files are easy to read and understand.

Cons

Relatively new so it does not have a large user base yet, and may thus
contain some unknown bugs. Visual Studio and XCode backends not as
high quality as Ninja one.

---

Markdown/Compiler Properties

Compiler properties

Not all compilers and platforms are alike. Therefore Meson provides
the tools to detect properties of the system during configure time. To
get most of this information, you first need to extract the *compiler
object
* from the main
meson variable.

meson
compiler = [[#meson.get_compiler]]('c')

Here we extract the C compiler. We could also have given the argument
cpp to get the C++ compiler, objc to get the objective C compiler
and so on. The call is valid for all languages specified in the
project declaration. Trying to obtain some other compiler will lead
to an unrecoverable error.

System information

This is a bit complex and more thoroughly explained on the page on
cross compilation. But if you just want to
know the operating system your code will run on, issue this command:

meson
host_machine.system()

Compiler id

The compiler object method [[compiler.get_id]] returns a
lower case string describing the "family" of the compiler. Since 0.53.0
[[compiler.get_linker_id]] returns a lower case string with the linker name. Since
compilers can often choose from multiple linkers depending on operating
system,
get_linker_id can be useful for handling or mitigating effects
of particular linkers.

The compiler object also has a method [[compiler.get_argument_syntax]] which
returns a lower case string of
gcc, msvc, or another undefined string
value; identifying whether the compiler arguments use the same syntax as
either
gcc or msvc, or that its arguments are not like either. This should
only be used to select the syntax of the arguments, such as those to test
with [[compiler.has_argument]].

See reference tables for a list of
supported compiler ids and their argument type.

Does code compile?

Sometimes the only way to test the system is to try to compile some
sample code and see if it works. For example, this can test that a
"C++17" compiler actually supports a particular C++17 feature,
without resorting to maintaining a feature list vs. compiler vendor,
compiler version and operating system.
Testing that a code snippet runs is a two-phase operation. First
we define some code using the multiline string operator:

meson
code = '''#include<stdio.h>
void func() { printf("Compile me.\n"); }
'''

Then we can run the test.

meson
result = [[#compiler.compiles]](code, name : 'basic check')

The variable result will now contain either true or false
depending on whether the compilation succeeded or not. The keyword
argument
name is optional. If it is specified, Meson will write the
result of the check to its log.

Sometimes it is necessary to check whether a certain code fragment not
only compiles, but also links successfully, e.g. to check if a symbol
is actually present in a library. This can be done using the
[[compiler.links]] method like this:

meson
code = '''#include<stdio.h>
void func() { printf("Compile me.\n"); }
'''

Then we can run the test.

meson
result = [[#compiler.links]](code, args : '-lfoo', name : 'link check')

The variable result will now contain either true or false
depending on whether the compilation and linking succeeded or not. The
keyword argument
name is optional. If it is specified, Meson will
write the result of the check to its log.

Compile and run test application

Here is how you would compile and run a small test application.
Testing if a code snippets runs versus merely that it links
is particularly important for some dependencies such as MPI.

meson
code = '''#include<stdio.h>
int main(int argc, char argv) {
printf("%s\n", "stdout");
fprintf(stderr, "%s\n", "stderr");
return 0;
}
'''
result = [[#compiler.run]](code, name : 'basic check')

The result variable encapsulates the state of the test, which can be
extracted with the following methods. The
name keyword argument
works the same as with
compiles.

| Method | Return value |
| ------ | ------------ |
| compiled |
True if compilation succeeded. If false then all other methods return undefined values. |
| returncode | The return code of the application as an integer |
| stdout | Program's standard out as text. |
| stderr | Program's standard error as text. |

Here is an example usage:

meson
if result.stdout().strip() == 'some_value'
# do something
endif

Does a header exist?

Header files provided by different platforms vary quite a lot. Meson
has functionality to detect whether a given header file is available
on the system. The test is done by trying to compile a simple test
program that includes the specified header. The following snippet
describes how this feature can be used.

meson
if [[#compiler.has_header]]('sys/fstat.h')
# header exists, do something
endif

Expression size

Often you need to determine the size of a particular element (such as
int, wchar_t or char*). Using the compiler variable mentioned
above, the check can be done like this.

meson
wcharsize = [[#compiler.sizeof]]('wchar_t', prefix : '#include<wchar.h>')

This will put the size of wchar_t as reported by sizeof into
variable
wcharsize. The keyword argument prefix is optional. If
specified its contents is put at the top of the source file. This
argument is typically used for setting
#include directives in
configuration files.

In older versions (<= 0.30) Meson would error out if the size could
not be determined. Since version 0.31 it returns -1 if the size could
not be determined.

Does a function exist?

Just having a header doesn't say anything about its contents.
Sometimes you need to explicitly check if some function exists. This
is how we would check whether the function
open_memstream exists in
header
stdio.h

meson
if [[#compiler.has_function]]('open_memstream', prefix : '#include <stdio.h>')
# function exists, do whatever is required.
endif

Note that, on macOS programs can be compiled targeting older macOS
versions than the one that the program is compiled on. It can't be
assumed that the OS version that is compiled on matches the OS version
that the binary will run on.

Therefore when detecting function availability with [[compiler.has_function]], it
is important to specify the correct header in the prefix argument.

In the example above, the function open_memstream is detected, which
was introduced in macOS 10.13. When the user builds on macOS 10.13,
but targeting macOS 10.11 (
-mmacosx-version-min=10.11), this will
correctly report the function as missing. Without the header however,
it would lack the necessary availability information and incorrectly
report the function as available.

Is a macro defined?

Macro detection can often be useful to determine if non-standard features
are supported on your target platform. Fortunately, Meson makes it
easy to check if a macro is defined:

meson
if [[#compiler.has_define]]('__SIZEOF_INT128__')
# macro is defined, do whatever is required
endif

Does a structure contain a member?

Some platforms have different standard structures. Here's how one
would check if a struct called
mystruct from header myheader.h
contains a member called
some_member.

meson
if [[#compiler.has_member]]('struct mystruct', 'some_member', prefix : '#include<myheader.h>')
# member exists, do whatever is required
endif

Type alignment

Most platforms can't access some data types at any address. For
example it is common that a
char can be at any address but a 32 bit
integer only at locations which are divisible by four. Determining the
alignment of data types is simple.

meson
int_alignment = [[#compiler.alignment]]('int') # Will most likely contain the value 4.

Has argument

This method tests if the compiler supports a given command line
argument. This is implemented by compiling a small file with the given
argument.

meson
has_special_flags = [[#compiler.has_argument]]('-Wspecialthing')

Note: some compilers silently swallow command line arguments they do
not understand. Thus this test cannot be made 100% reliable.

---

Markdown/Conference Presentations

Conference presentations on Meson

- FOSDEM 2014, Introducing the Meson build
system

(jpakkane)

- LCA 2015, Making build systems not
suck
(jpakkane)

- GUADEC 2015, Improving the way Gnome apps are
built
(jpakkane)

- GStreamer conference 2015, Done in 6.0
seconds

(jpakkane)

- LCA 2016, Builds, dependencies and deployment in the modern
multiplatform world

(jpakkane)

- GUADEC 2016, Making your GNOME app compile 2.4x
faster

(nirbheek)

- Libre Application Summit 2016, New world, new
tools
(jpakkane)

- GStreamer conference 2016, GStreamer Development on Windows and
faster builds everywhere with
Meson

(tpm)

---

Markdown/Configuration

---
short-description: Build-time configuration options
...

Configuration

If there are multiple configuration options, passing them through
compiler flags becomes very burdensome. It also makes the
configuration settings hard to inspect. To make things easier, Meson
supports the generation of configure files. This feature is similar to
one found in other build systems such as CMake.

Suppose we have the following Meson snippet:

meson
conf_data = [[#configuration_data]]
conf_data.set('version', '1.2.3')
[[#configure_file]](input : 'config.h.in',
output : 'config.h',
configuration : conf_data)

and that the contents of config.h.in are

c
#define VERSION_STR "@version@"

Meson will then create a file called config.h in the corresponding
build directory whose contents are the following.

c
#define VERSION_STR "1.2.3"

More specifically, Meson will find all strings of the type @varname@
and replace them with respective values set in
conf_data. You can
use a single
configuration_data object as many times as you like,
but it becomes immutable after being passed to the
configure_file
function. That is, after it has been used once to generate output the
set function becomes unusable and trying to call it causes an error.
Copy of immutable
configuration_data is still immutable.

For more complex configuration file generation Meson provides a second
form. To use it, put a line like this in your configuration file.

#mesondefine TOKEN

The replacement that happens depends on what the value and type of TOKEN is:

c
#define TOKEN     // If TOKEN is set to boolean true.
#undef TOKEN // If TOKEN is set to boolean false.
#define TOKEN 4 // If TOKEN is set to an integer or string value.
/ undef TOKEN / // If TOKEN has not been set to any value.

Note that if you want to define a C string, you need to do the quoting
yourself like this:

meson
conf_data.set('TOKEN', '"value"')

Since this is such a common operation, Meson provides a convenience
method:

meson
plain_var = 'value'
conf_data.set_quoted('TOKEN', plain_var) # becomes #define TOKEN "value"

Often you have a boolean value in Meson but need to define the C/C++
token as 0 or 1. Meson provides a convenience function for this use
case.

meson
conf_data.set10(token, boolean_value)

The line above is equivalent to this:


if boolean_value
conf_data.set(token, 1)
else
conf_data.set(token, 0)
endif

Configuring without an input file

If the input file is not defined then Meson will generate a header
file with all the entries in the configuration data object. The
replacements are the same as when generating
#mesondefine entries:

meson
conf_data.set('FOO', '"string"') => #define FOO "string"
conf_data.set('FOO', 'a_token') => #define FOO a_token
conf_data.set('FOO', true) => #define FOO
conf_data.set('FOO', false) => #undef FOO
conf_data.set('FOO', 1) => #define FOO 1
conf_data.set('FOO', 0) => #define FOO 0

In this mode, you can also specify a comment which will be placed
before the value so that your generated files are self-documenting.

meson
conf_data.set('BAR', true, description : 'Set BAR if it is available')

Will produce:

c
/ Set BAR if it is available /
#define BAR

Dealing with file encodings

The default Meson file encoding to configure files is utf-8. If you
need to configure a file that is not utf-8 encoded the
encoding
keyword will allow you to specify which file encoding to use. It is
however strongly advised to convert your non utf-8 file to utf-8
whenever possible. Supported file encodings are those of python3, see
standard-encodings.

Using dictionaries

Since 0.49.0 [[configuration_data]] takes an optional dictionary as
first argument. If provided, each key/value pair is added into the
configuration_data as if set() method was called for each of them.
[[configure_file]]'s
configuration kwarg also accepts a dictionary
instead of a configuration_data object.

Example:

meson
cdata = configuration_data({
'STRING' : '"foo"',
'INT' : 42,
'DEFINED' : true,
'UNDEFINED' : false,
})

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

configure_file(output : 'config2.h',
configuration : {
'STRING' : '"foo"',
'INT' : 42,
'DEFINED' : true,
'UNDEFINED' : false,
}
)

A full example

Generating and using a configuration file requires the following steps:

- generate the file
- create an include directory object for the directory that holds the file
- use it in a target

We are going to use the traditional approach of generating a header
file in the top directory. The common name is
config.h but we're
going to use an unique name. This avoids the problem of accidentally
including the wrong header file when building a project with many
subprojects.

At the top level we generate the file:

meson
conf_data = configuration_data()

Set data


configure_file(input : 'projconfig.h.in',
output : 'projconfig.h',
configuration : conf_data)

Immediately afterwards we generate the include object.

meson
configuration_inc = include_directories('.')

Finally we specify this in a target that can be in any subdirectory.

meson
executable(..., include_directories : configuration_inc)

Now any source file in this target can include the configuration
header like this:

c
#include<projconfig.h>

---

Markdown/Configuring A Build Directory

---
short-description: Configuring a pre-generated build directory
...

Configuring a build directory

Often you want to change the settings of your build after it has been
generated. For example you might want to change from a debug build
into a release build, set custom compiler flags, change the build
options provided in your
meson.options file and so on.

The main tool for this is the meson configure command.

You invoke meson configure by giving it the location of your build
dir. If omitted, the current working directory is used instead. Here's
a sample output for a simple project.

Core properties

Source dir /home/jpakkane/clangdemo/2_address
Build dir /home/jpakkane/clangdemo/2_address/buildmeson

Core options:
Option Current Value Possible Values Description
------ ------------- --------------- -----------
auto_features auto [enabled, disabled, auto] Override value of all 'auto' features
backend ninja [ninja, vs, vs2010, vs2015, vs2017, vs2019, vs2022, xcode] Backend to use
buildtype release [plain, debug, debugoptimized, release, minsize, custom] Build type to use
debug false [true, false] Debug
default_library shared [shared, static, both] Default library type
install_umask 0022 [preserve, 0000-0777] Default umask to apply on permissions of installed files
layout mirror [mirror, flat] Build directory layout
optimization 3 [plain, 0, g, 1, 2, 3, s] Optimization level
prefer_static false [true, false] Whether to try static linking before shared linking
strip false [true, false] Strip targets on install
unity off [on, off, subprojects] Unity build
warning_level 1 [0, 1, 2, 3, everything] Compiler warning level to use
werror false [true, false] Treat warnings as errors

Backend options:
Option Current Value Possible Values Description
------ ------------- --------------- -----------
backend_max_links 0 >=0 Maximum number of linker processes to run or 0 for no limit

Base options:
Option Current Value Possible Values Description
------ ------------- --------------- -----------
b_asneeded true [true, false] Use -Wl,--as-needed when linking
b_colorout always [auto, always, never] Use colored output
b_coverage false [true, false] Enable coverage tracking.
b_lto false [true, false] Use link time optimization
b_lundef true [true, false] Use -Wl,--no-undefined when linking
b_ndebug false [true, false, if-release] Disable asserts
b_pch true [true, false] Use precompiled headers
b_pgo off [off, generate, use] Use profile guided optimization
b_sanitize none [none, address, thread, undefined, leak, memory, address,undefined] Code sanitizer to use
b_staticpic true [true, false] Build static libraries as position independent

Compiler options:
Option Current Value Possible Values Description
------ ------------- --------------- -----------
c_args [] Extra arguments passed to the C compiler
c_link_args [] Extra arguments passed to the C linker
c_std c99 [none, c89, c99, c11, c17, c18, c2x, c23, c2y, gnu89, gnu99, gnu11, gnu17, gnu18, gnu2x, gnu23, gnu2y] C language standard to use
cpp_args [] Extra arguments passed to the C++ compiler
cpp_debugstl false [true, false] STL debug mode
cpp_link_args [] Extra arguments passed to the C++ linker
cpp_std c++11 [none, c++98, c++03, c++11, c++14, c++17, c++1z, c++2a, c++20, gnu++03, gnu++11, gnu++14, gnu++17, gnu++1z, gnu++2a, gnu++20] C++ language standard to use
fortran_std [] [none, legacy, f95, f2003, f2008, f2018] language standard to use

Directories:
Option Current Value Description
------ ------------- -----------
bindir bin Executable directory
datadir share Data file directory
includedir include Header file directory
infodir share/info Info page directory
libdir lib/x86_64-linux-gnu Library directory
libexecdir libexec Library executable directory
localedir share/locale Locale data directory
localstatedir /var/local Localstate data directory
mandir share/man Manual page directory
prefix /usr/local Installation prefix
sbindir sbin System executable directory
sharedstatedir /var/local/lib Architecture-independent data directory
sysconfdir etc Sysconf data directory

Project options:
Option Current Value Possible Values Description
------ ------------- --------------- -----------
array_opt [one, two] [one, two, three] array_opt
combo_opt three [one, two, three] combo_opt
free_array_opt [one, two] free_array_opt
integer_opt 3 >=0, <=5 integer_opt
other_one false [true, false] other_one
some_feature enabled [enabled, disabled, auto] some_feature
someoption optval An option

Testing options:
Option Current Value Possible Values Description
------ ------------- --------------- -----------
errorlogs true [true, false] Whether to print the logs from failing tests
stdsplit true [true, false] Split stdout and stderr in test logs

These are all the options available for the current project arranged
into related groups. The first column in every field is the name of
the option. To set an option you use the
-D option. For example,
changing the installation prefix from
/usr/local to /tmp/testroot
you would issue the following command.

meson configure -Dprefix=/tmp/testroot

Then you would run your build command (usually meson compile), which
would cause Meson to detect that the build setup has changed and do
all the work required to bring your build tree up to date.

Since 0.50.0, it is also possible to get a list of all build options
by invoking
meson configure with the
project source directory or the path to the root
meson.build. In
this case, Meson will print the default values of all options similar
to the example output from above.

Per project subproject options rewrite (Since 1.8)

A common requirement when building large projects with many
subprojects is to build some (or all) subprojects with project options
that are different from the "main project". This has been sort of
possible in a limited way but is now natively supported. Per project
options can be added, changed and removed at runtime using the command
line, in other words, without editing existing
meson.build files.

Starting with version 1.8 you can specify per-project option settings.
These can be specified for every top level (i.e. not project) options.
Suppose you have a project that has a single subproject called
numbercruncher that does heavy computation. During development you
want to build that subproject with optimizations enabled but your main
project without optimizations. This can be done by specifying a custom
value to the given subproject:

meson configure -Dnumbercruncher:optimization=3

Another case might be that you want to build with warnings as errors,
but some subproject does not support it. To configure
werror per
subproject you can do:

meson configure -Dwerror=true -Dnaughty:werror=false

You can also specify a different value on the top level project. For
example you could enable optimizations on all subprojects but not the
top level project:

meson configure -Doptimization=2 -D:optimization=0

Note the colon after the second D.

Subproject specific values can be removed with -U

meson configure -Usubproject:optionnname

---

Markdown/Contact Information

Contact information

For general discussion and questions, it is strongly recommended that
you use the mailing
list
.

If you find bugs, please file them in the issue
tracker
.

The maintainer of Meson is Jussi Pakkanen. You should usually not
contact him privately but rather use the channels listed above.
However if such a need arises, he can be reached at gmail where his
username is
jpakkane (that is not a typo, the last letter is indeed
e).

---

Markdown/Continuous Integration

Continuous Integration

Here you will find snippets to use Meson with various CI such as
Travis and AppVeyor.

Please file an issue
if these instructions don't work for you.

Travis-CI with Docker

Travis with Docker gives access to newer non-LTS Ubuntu versions with
pre-installed libraries of your choice.

This yml file is derived from the
configuration used by Meson
for running its own tests.

yaml
os:
- linux
- osx

language:
- cpp

services:
- docker

before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install python3 ninja; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then pip3 install meson; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull YOUR/REPO:eoan; fi

script:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo FROM YOUR/REPO:eoan > Dockerfile; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo ADD . /root >> Dockerfile; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker build -t withgit .; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && TRAVIS=true CC=$CC CXX=$CXX meson setup builddir && meson test -C builddir"; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) meson setup builddir && meson test -C builddir; fi

CircleCI for Linux host (with custom Docker images)

CircleCi can work for spinning all of the
Linux images you wish. Here's a sample
yml file for use with that.

text
/ Detailed source-code truncated for AI context efficiency. /

CircleCI for Linux host (without custom Docker images)

This CircleCI configuration defines two jobs, build-linux and build-macos,
within a workflow named
build. The build-linux job utilizes a Docker image
with Python 3.12.3, while
build-macos runs on macOS with Xcode 15.3.0. Each
job involves checking out the code, installing Meson and Ninja, configuring the
project, compiling it, and running tests using Meson.

yaml
version: 2.1

jobs:
build-linux:
docker:
- image: cimg/python:3.12.3
steps:
- checkout
- run:
name: Install Meson and Ninja
command: |
python -m pip install --user meson ninja
- run:
name: Configure Project
command: |
meson setup builddir
- run:
name: Compile Project
command: |
meson compile -C builddir
- run:
name: Run Tests
command: |
meson test -C builddir

build-macos:
macos:
xcode: 15.3.0
steps:
- checkout
- run:
name: Install Meson and Ninja
command: |
python -m pip install meson ninja
- run:
name: Configure Project
command: |
meson setup builddir
- run:
name: Compile Project
command: |
meson compile -C builddir
- run:
name: Run Tests
command: |
meson test -C builddir

workflows:
version: 2.1
build:
jobs:
- build-linux
- build-macos

AppVeyor for Windows

For CI on Windows, AppVeyor has a wide
selection of default
configurations
.
AppVeyor also has
MacOS and
Linux CI
images. This is a sample
appveyor.yml file for Windows with Visual
Studio 2017, 2019, and 2022.

yaml
version: 1.0.{build}
image:
- Visual Studio 2022
- Visual Studio 2019
- Visual Studio 2017

install:
- cmd: python -m pip install meson ninja

build_script:
- cmd: >-
meson setup builddir
meson compile -C builddir

test_script:
- cmd: meson test -C builddir

Qt

For Qt 5, add the following line near the PYTHON_ROOT assignment:

yaml
- cmd: if %arch%==x86 (set QT_ROOT=C:\Qt\5.11\%compiler%) else (set QT_ROOT=C:\Qt\5.11\%compiler%_64)

And afterwards add %QT_ROOT%\bin to the PATH variable.

You might have to adjust your build matrix as there are, for example,
no msvc2017 32-bit builds. Visit the Build
Environment
page in
the AppVeyor docs for more details.

Boost

The following statement is sufficient for Meson to find Boost:

yaml
- cmd: set BOOST_ROOT=C:\Libraries\boost_1_67_0

GitHub Actions

GitHub Actions provides a versatile platform for continuous integration
(CI). This example workflow file,
ci_meson.yml, is tailored for C-based
projects utilizing GCC on Linux, macOS, and Windows. Triggered by changes
to C code files, it automates building and testing processes using different
versions of Meson (1.0.0, 1.1.0, 1.2.0, 1.3.0, 1.4.0) across various operating
systems. Each job in the workflow handles checkout, dependency installation,
project configuration, test execution, and optional test log uploads upon
failure.

yaml
name: CI Meson

on:
push:
paths:
- ".c"
- ".h"
pull_request:
paths:
- ".c"
- ".h"

jobs:
build:
name: Build and Test on ${{ matrix.os }} with Meson v${{ matrix.meson_version }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
meson_version: ["1.2.0", "1.3.0", "1.4.0"]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: python -m pip install meson==${{ matrix.meson_version }} ninja
- name: Configure Project
run: meson setup builddir/
env:
CC: gcc
- name: Run Tests
run: meson test -C builddir/ -v
- name: Upload Test Log
uses: actions/upload-artifact@v4
if: failure()
with:
name: ${{ matrix.os }}_Meson_Testlog
path: builddir/meson-logs/testlog.txt

---

Markdown/Contributing

---
short-description: Contributing to Meson
...

Contributing to Meson

A large fraction of Meson is contributed by people outside the core
team. This documentation explains some of the design rationales of
Meson as well as how to create and submit your patches for inclusion
to Meson.

Thank you for your interest in participating to the development.

Submitting patches

All changes must be submitted as pull requests to
GitHub
. This causes them
to be run through the CI system. All submissions must pass a full CI
test run before they are even considered for submission.

Keeping pull requests up to date

It is possible that while your pull request is being reviewed, other
changes are committed to master that cause merge conflicts that must
be resolved. The basic rule for this is very simple: keep your pull
request up to date using rebase _only_.

Do not merge head back to your branch. Any merge commits in your pull
request make it not acceptable for merging into master and you must
remove them.

Special procedure for new features

Every new feature requires some extra steps, namely:

- Must include a project test under test cases/, or if that's not
possible or if the test requires a special environment, it must go
into
run_unittests.py.
- Must be registered with the FeatureChecks
framework

that will warn the user if they try to use a new feature while
targeting an older Meson version.
- Needs a release note snippet inside
docs/markdown/snippets/ with
a heading and a brief paragraph explaining what the feature does
with an example.

Acceptance and merging

The kind of review and acceptance any merge proposal gets depends on
the changes it contains. All pull requests must be reviewed and
accepted by someone with commit rights who is not the original
submitter. Merge requests can be roughly split into three different
categories.

The first one consists of MRs that only change the markdown
documentation under
docs/markdown. Anyone with access rights can
push changes to these directly to master. For major changes it is
still recommended to create a MR so other people can comment on it.

The second group consists of merges that don't change any
functionality, fixes to the CI system and bug fixes that have added
regression tests (see below) and don't change existing
functionality. Once successfully reviewed anyone with merge rights can
merge these to master.

The final kind of merges are those that add new functionality or
change existing functionality in a backwards incompatible way. These
require the approval of the project lead.

In a simplified list form the split would look like the following:

- members with commit access can do:
- documentation changes (directly to master if warranted)
- bug fixes that don't change functionality
- refactorings
- new dependency types
- new tool support (e.g. a new Doxygen-kind of tool)
- support for new compilers to existing languages
- project leader decision is needed for:
- new modules
- new functions in the Meson language
- syntax changes for Meson files
- changes breaking backwards compatibility
- support for new languages

A green CI run is mandatory for merging

No merge request may be merged until it has a fully green CI run. It
does not matter why CI fails, it is a hard blocker. Even if the MR
could possibly not have anything to do with the failure and clearly
should be permitted, it may not be merged. Only MRs that fix the CI
issue are allowed to land in trunk.

There is one, and only one, exception to this. At the time of writing
the Apple CI is unreliable and sometimes fails with clock skew errors.

If a merge causes CI failure any developer can revert it out of
master. It is then the responsibility of the original submitter to
resubmit a fixed version.

Strategy for merging pull requests to trunk

Meson's merge strategy should fulfill the following guidelines:

- preserve as much history as possible

- have as little junk in the repo as possible

- everything in the "master lineage" should always pass all tests

These goals are slightly contradictory so the correct thing to do
often requires some judgement on part of the person doing the
merge. GitHub provides three different merge options, The rules of
thumb for choosing between them goes like this:

- single commit pull requests should always be rebased

- a pull request with one commit and one "fixup" commit (such as
testing something to see if it passes CI) should be squashed

- large branches with many commits should be merged with a merge
commit, especially if one of the commits does not pass all tests
(which happens in e.g. large and difficult refactorings)

If in doubt, ask for guidance on IRC.

Tests

All new features must come with automatic tests that thoroughly prove
that the feature is working as expected. Similarly bug fixes must come
with a unit test that demonstrates the bug, proves that it has been
fixed and prevents the feature from breaking in the future.

Sometimes it is difficult to create a unit test for a given bug. If
this is the case, note this in your pull request. We may permit bug
fix merge requests in these cases. This is done on a case by case
basis. Sometimes it may be easier to write the test than convince the
maintainers that one is not needed. Exercise judgment and ask for help
in problematic cases.

The tests are split into two different parts: unit tests and full
project tests. To run all tests, execute
./run_tests.py. Unit tests
can be run with
./run_unittests.py and project tests with
./run_project_tests.py.

Project tests

Subsets of project tests can be selected with
./run_project_tests.py --only option. This can save a great deal of
time when only a certain part of Meson is being tested.
For example, a useful and easy contribution to Meson is making
sure the full set of compilers is supported. One could for example test
various Fortran compilers by setting
FC=ifort, FC=flang or
FC=flang-new or similar with ./run_project_test.py --only fortran.
Some families of tests require a particular backend to run.
For example, all the CUDA project tests run and pass on Windows via
./run_project_tests.py --only cuda --backend ninja

Each project test is a standalone project that can be compiled on its
own. They are all in the
test cases subdirectory. The simplest way to
run a single project test is to do something like
./meson.py test\
cases/common/1\ trivial builddir. The one exception to this is test
cases/unit directory discussed below.

The test cases in the common subdirectory are meant to be run always
for all backends. They should only depend on C and C++, without any
external dependencies such as libraries. Tests that require those are
in the
test cases/frameworks directory. If there is a need for an
external program in the common directory, such as a code generator, it
should be implemented as a Python script. The goal of test projects is
also to provide sample projects that end users can use as a base for
their own projects.

All project tests follow the same pattern: they are configured,
compiled, tests are run and finally install is run. Passing means that
configuring, building and tests succeed and that installed files match
those expected.

Any tests that require more thorough analysis, such as checking that
certain compiler arguments can be found in the command line or that
the generated pkg-config files actually work should be done with a
unit test.

Additionally:

* crossfile.ini and nativefile.ini are passed to the configure step with
--cross-file and --native-file options, respectively.

* mlog.cmd_ci_include() can be called from anywhere inside Meson to
capture the contents of an additional file into the CI log on failure.

Projects needed by unit tests are in the test cases/unit
subdirectory. They are not run as part of
./run_project_tests.py.

Configuring project tests

The (optional) test.json file, in the root of a test case, is used
for configuring the test. All of the following root entries in the
test.json
are independent of each other and can be combined as needed.

Example test.json:

json
{
"env": {
"VAR": "VAL"
},
"installed": [
{ "type": "exe", "file": "usr/bin/testexe" },
{ "type": "pdb", "file": "usr/bin/testexe" },
{ "type": "shared_lib", "file": "usr/lib/z", "version": "1.2.3" },
],
"matrix": {
"options": {
"opt1": [
{ "val": "abc" },
{ "val": "qwert" },
{ "val": "bad" }
],
"opt2": [
{ "val": null },
{ "val": "true" },
{ "val": "false" },
]
},
"exclude": [
{ "opt1": "qwert", "opt2": "false" },
{ "opt1": "bad" }
]
},
"tools": {
"cmake": ">=3.11"
}
}

#### env

The env key contains a dictionary which specifies additional
environment variables to be set during the configure step of the test.

There is some basic support for configuring the string with the @<VAR>@ syntax:

- @ROOT@: absolute path of the source directory
-
@PATH@: current value of the PATH env variable

#### installed

The installed dict contains a list of dicts, describing which files are expected
to be installed. Each dict contains the following keys:

- file
-
type
-
platform (optional)
-
version (optional)
-
language (optional)

The file entry contains the relative path (from the install root) to the
actually installed file.

The type entry specifies how the file path should be interpreted based on the
current platform. The following values are currently supported:

| type | Description |
| ------------- | ------------------------------------------------------------------------------------------------------- |
|
file | No postprocessing, just use the provided path |
|
python_file | Use the provided path while replacing the python directory. |
|
dir | To include all files inside the directory (for generated docs, etc). The path must be a valid directory |
|
exe | For executables. On Windows the .exe suffix is added to the path in file |
|
shared_lib | For shared libraries, always written as name. The appropriate suffix and prefix are added by platform |
|
python_lib | For python libraries, while replacing the python directory. The appropriate suffix is added by platform |
|
pdb | For Windows PDB files. PDB entries are ignored on non Windows platforms |
|
implib | For Windows import libraries. These entries are ignored on non Windows platforms |
|
py_implib | For Windows import libraries. These entries are ignored on non Windows platforms |
|
implibempty | Like implib, but no symbols are exported in the library |
|
expr | file is an expression. This type should be avoided and removed if possible |

Except for the file, python_file and expr types, all paths should be provided without a suffix.

| Argument | Applies to | Description |
| -----------|----------------------------|-------------------------------------------------------------------------------|
|
version | shared_lib, pdb | Sets the version to look for appropriately per-platform |
|
language | pdb | Determines which compiler/linker determines the existence of this file |

The shared_lib and pdb types takes an optional additional
parameter,
version, this is us a string in X.Y.Z format that will
be applied to the library. Each version to be tested must have a
single version. The harness will apply this correctly per platform:

The python_file, python_lib, and py_implib types have basic support for configuring the string with the @<VAR>@ syntax:

- @PYTHON_PLATLIB@: python get_install_dir directory relative to prefix
-
@PYTHON_PURELIB@: python get_install_dir(pure: true) directory relative to prefix

pdb takes an optional language argument. This determines which
compiler/linker should generate the pdb file. Because it's possible to
mix compilers that do and don't generate pdb files (dmd's optlink
doesn't). Currently this is only needed when mixing D and C code.

json
{
"type": "shared_lib", "file": "usr/lib/lib",
"type": "shared_lib", "file": "usr/lib/lib", "version": "1",
"type": "shared_lib", "file": "usr/lib/lib", "version": "1.2.3.",
}

This will be applied appropriately per platform. On windows this
expects
lib.dll and lib-1.dll. on MacOS it expects liblib.dylib
and
liblib.1.dylib. On other Unices it expects liblib.so,
liblib.so.1, and liblib.so.1.2.3.

If the platform key is present, the installed file entry is only
considered if the platform matches. The following values for
platform are currently supported:

| platform | Description |
| ---------- | -------------------------------------------------------------------- |
|
msvc | Matches when a msvc like compiler is used (msvc, clang-cl, etc.) |
|
gcc | Not msvc |
|
cygwin | Matches when the platform is cygwin |
|
!cygwin | Not cygwin |
|
windows | Matches when the platform is windows or cygwin |
|
!windows | Not windows |

#### matrix

The matrix section can be used to define a test matrix to run
project tests with different Meson options.

In the options dict, all possible options and their values are
specified. Each key in the
options dict is a Meson option. It stores
a list of all potential values in a dict format.

Each value must contain the val key for the value of the option.
null can be used for adding matrix entries without the current
option.

The skip_on_env key (as described below) may be used in the value to skip that
matrix entry, based on the current environment.

The expect_skip_on_jobname and expect_skip_on_os keys (as described below)
may be used to expect that the test will be skipped, based on the current environment.

Similarly, the compilers key can be used to define a mapping of
compilers to languages that are required for this value.

json
{
"compilers": {
"c": "gcc",
"cpp": "gcc",
"d": "gdc"
}
}

Specific option combinations can be excluded with the exclude
section. It should be noted that
exclude does not require exact
matches. Instead, any matrix entry containing all option value
combinations in
exclude will be excluded. Thus an empty dict ({})
to will match all elements in the test matrix.

The above example will produce the following matrix entries:
-
opt1=abc
-
opt1=abc opt2=true
-
opt1=abc opt2=false
-
opt1=qwert
-
opt1=qwert opt2=true

#### do_not_set_opts

Currently supported values are:
-
prefix
-
libdir

#### tools

This section specifies a dict of tool requirements in a simple
key-value format. If a tool is specified, it has to be present in the
environment, and the version requirement must be fulfilled. Otherwise,
the entire test is skipped (including every element in the test
matrix).

#### stdout

The stdout key contains a list of dicts, describing the expected
stdout.

Each dict contains the following keys:

- line
-
match (optional)
-
count (optional)

Each item in the list is matched, in order, against the remaining
actual stdout lines, after any previous matches. If the actual stdout
is exhausted before every item in the list is matched, the expected
output has not been seen, and the test has failed.

The match element of the dict determines how the line element is
matched:

| Type | Description |
| -------- | ----------------------- |
|
literal | Literal match (default) |
|
re | regex match |

The count element determines how many times the line is expected, and allowed,
to be in the output. If unspecified, it must appear "any number of times, but at
least once".

#### skip_on_env

The skip_on_env key can be used to specify a list of environment variables. If
at least one environment variable in the
skip_on_env list is present, the test
is skipped.

#### expect_skip_on_jobname

The expect_skip_on_jobname key contains a list of strings. If the MESON_CI_JOBNAME
environment variable is set, and any of them are a sub-string of it, the test is
expected to be skipped (that is, it is expected that the test will output
MESON_SKIP_TEST, because the CI environment is not one in which it can run,
for whatever reason).

The test is failed if it either skips unexpectedly or runs unexpectedly.

#### expect_skip_on_os

The expect_skip_on_os key can be used to specify a list of OS names (or their
negations, prefixed with a
!). If at least one item in the expect_skip_on_os list
is matched, the test is expected to be skipped.

The test is failed if it either skips unexpectedly or runs unexpectedly.

Skipping integration tests

Meson uses several continuous integration testing systems that have
slightly different interfaces for indicating a commit should be
skipped.

Continuous integration systems currently used:
- Azure Pipelines
allows
NO_CI in the commit message.
- Sider
runs Flake8 (see below)

To promote consistent naming policy, use:

- [skip ci] in the commit title if you want to disable all
integration tests

Documentation

The docs directory contains the full documentation that will be used
to generate the Meson web site. Line length
in most cases should not exceed 70 characters (lines containing links
or examples are usually exempt). Every change in functionality must
change the documentation pages. In most cases this means updating the
reference documentation page but bigger changes might need changes in
other documentation, too.

All new functionality needs to have a mention in the release
notes. These features should be written in standalone files in the
docs/markdown/snippets directory. The release manager will combine
them into one page when doing the release.

Python Coding style

Meson follows the basic Python coding style. Additional rules are the
following:

- indent 4 spaces, no tabs ever
- indent meson.build files with two spaces
- try to keep the code as simple as possible
- contact the mailing list before embarking on large scale projects
to avoid wasted effort

Meson uses Flake8 for style guide enforcement. The Flake8 options for
the project are contained in .flake8.

To run Flake8 on your local clone of Meson:

console
$ python3 -m pip install flake8
$ cd meson
$ flake8

To run it automatically before committing:

console
$ flake8 --install-hook=git
$ git config --bool flake8.strict true

C/C++ coding style

Meson has a bunch of test code in several languages. The rules for
those are simple.

- indent 4 spaces, no tabs ever
- brace always on the same line as if/for/else/function definition

Dependency support policy

The goal of Meson is to be as easily usable as possible. The user
experience should be "get Python3 and Ninja, run", even on
Windows.

Additionally, Meson is popularly used in many core infrastructure packages in a
Unix (and particularly, Linux) userland. This includes:
- package managers, such as pacman (Arch Linux) and portage (Gentoo)
- init systems (systemd, openrc, dinit)
- graphics stacks (xorg, wayland, libdrm, Mesa, gtk)

As such it needs to be able to run early on when bootstrapping a system from
scratch.

Python

We will always support all non EOL versions of CPython. Yes, there are people
out there using and depending on every old version of python. In fact, there
are people using and depending on systems that had a brand new python at the
time of release, but with a much longer support cycle than Python itself. We
need to balance the tradeoff between supporting those systems and being able to
improve our own codebase and code quality.

Meson will also be honest about what versions of python it supports. When a
version of CPython becomes EOL, it becomes eligible to be removed from our
support policy. We cannot guarantee continued support forever for software that
is not supported by its own developers, even if some deprecated LTS systems out
there still ship it. However, that doesn't mean we will drop support for those
versions simply because they are old. If we are not using new functionality
from new python versions, we will continue to mark Meson as compatible with the
older version -- and test it in CI!

(Note that contrary to popular belief, it is actually easier to test support
for very old versions of python than it is to drop support for it. We already
have the CI setup necessary for testing. Upgrading the CI to use newer versions
of python, on the other hand, represents mildly painful administrative work
that has to be done.)

So, in order to start requiring a newer version of python, one should check a
few factors:
- are the older versions being dropped, already EOL? Python EOL chart
- document the new minimum version of corresponding OSes
- rationalize the benefit of the change in terms of improvements to development
and maintenance of Meson. What new language features will be unlocked by the
upgrade, that Meson will be able to make good use of? Not every version has
new features requiring an upgrade, and not every new feature is so great we
need to drop everything to use it

External dependencies

Unfortunately this also means that we can't have dependencies on
projects outside of Python's standard library. This applies only to
core functionality, though. For additional helper programs etc the use
of external dependencies may be ok. If you feel that you are dealing
with this kind of case, please contact the developers first with your
use case.

Turing completeness

The main design principle of Meson is that the definition language is
not Turing complete. Any change that would make Meson Turing complete
is automatically rejected. In practice this means that defining your
own functions inside
meson.build files and generalised loops will
not be added to the language.

Do I need to sign a CLA in order to contribute?

No you don't. All contributions are welcome.

No lingering state

Meson operates in much the same way as functional programming
languages. It has inputs, which include
meson.build files, values of
options, compilers and so on. These are passed to a function, which
generates output build definition. This function is pure, which means that:

- for any given input the output is always the same
- running Meson twice in a row _always_ produce the same output in both runs

The latter one is important, because it enforces that there is no way
for "secret state" to pass between consecutive invocations of
Meson. This is the reason why, for example, there is no
set_option
function even though there is a
get_option one.

If this were not the case, we could never know if the build output is
"stable". For example suppose there were a
set_option function and a
boolean variable
flipflop. Then you could do this:

meson
set_option('flipflop', not get_option('flipflop'))

This piece of code would never converge. Every Meson run would change
the value of the option and thus the output you get out of this build
definition would be random.

Meson does not permit this by forbidding these sorts of covert
channels.

There is one exception to this rule. Users can call into external
commands with
run_command. If the output of that command does not
behave like a pure function, this problem arises. Meson does not try
to guard against this case, it is the responsibility of the user to
make sure the commands they run behave like pure functions.

Environment variables

Environment variables are like global variables, except that they are
also hidden by default. Envvars should be avoided whenever possible,
all functionality should be exposed in better ways such as command
line switches.

Random design points that fit nowhere else

- All features should follow the 90/9/1 rule. 90% of all use cases
should be easy, 9% should be possible and it is totally fine to not
support the final 1% if it would make things too complicated.

- Any build directory will have at most two toolchains: one native and
one cross.

- Prefer specific solutions to generic frameworks. Solve the end
user's problems rather than providing them tools to do it
themselves.

- Never use features of the Unix shell (or Windows shell for that
matter). Doing things like forwarding output with
> or invoking
multiple commands with
&& are not permitted. Whenever these sorts
of requirements show up, write an internal Python script with the
desired functionality and use that instead.

---

Markdown/Creating Linux Binaries

---
short-description: Creating universal Linux binaries
...

Creating Linux binaries

Creating Linux binaries that can be downloaded and run on any distro
(like .dmg packages for OSX or .exe installers for Windows) has
traditionally been difficult. This is even more tricky if you want to
use modern compilers and features, which is especially desired in game
development. There is still no simple turn-key solution for this
problem but with a bit of setup it can be relatively straightforward.

Installing system and GCC

First you need to do a fresh operating system install. You can use
spare hardware, VirtualBox, cloud or whatever you want. Note that the
distro you install must be at least as old as the oldest release you
wish to support. Debian stable is usually a good choice, though
immediately after its release you might want to use Debian oldstable
or the previous Ubuntu LTS. The oldest supported version of CentOS is
also a good choice.

Once you have installed the system, you need to install
build-dependencies for GCC. In Debian-based distros this can be done
with the following commands:

console
$ apt-get build-dep g++
$ apt-get install pkg-config libgmp-dev libmpfr-dev libmpc-dev

Then create a src subdirectory in your home directory. Copy-paste
the following into
install_gcc.sh and execute it.

bash
#!/bin/sh

wget ftp://ftp.fu-berlin.de/unix/languages/gcc/releases/gcc-4.9.2/gcc-4.9.2.tar.bz2
tar xf gcc-4.9.2.tar.bz2

mkdir objdir
cd objdir
../gcc-4.9.2/configure --disable-bootstrap --prefix=${HOME}/devroot \
--disable-multilib --enable-languages=c,c++
make -j 4
make install-strip
ln -s gcc ${HOME}/devroot/bin/cc

Then finally add the following lines to your .bashrc.

console
$ export LD_LIBRARY_PATH=${HOME}/devroot/lib
$ export PATH=${HOME}/devroot/bin:$PATH
$ export PKG_CONFIG_PATH=${HOME}/devroot/lib/pkgconfig

Log out and back in and now your build environment is ready to use.

Adding other tools

Old distros might have too old versions of some tools. For Meson this
could include Python 3 and Ninja. If this is the case you need to
download, build and install new versions into
~/devroot in the usual
way.

Adding dependencies

You want to embed and statically link every dependency you can
(especially C++ dependencies). Meson's Wrap package
manager
might be of use here. This
is equivalent to what you would do on Windows, OSX, Android etc.
Sometimes static linking is not possible. In these cases you need to
copy the .so files inside your package. Let's use SDL2 as an example.
First we download and install it as usual giving it our custom install
prefix (that is,
./configure --prefix=${HOME}/devroot). This makes
Meson's dependency detector pick it up automatically.

Building and installing

Building happens in much the same way as normally. There are just two
things to note. First, you must tell GCC to link the C++ standard
library statically. If you don't then your app is guaranteed to break
as different distros have binary-incompatible C++ libraries. The
second thing is that you need to point your install prefix to some
empty staging area. Here's the Meson command to do that:

console
$ LDFLAGS=-static-libstdc++ meson --prefix=/tmp/myapp <other args>

The aim is to put the executable in /tmp/myapp/bin and shared
libraries to
/tmp/myapp/lib. The next thing you need is the
embedder. It takes your dependencies (in this case only
libSDL2-2.0.so.0) and copies them in the lib directory. Depending on
your use case you can either copy the files by hand or write a script
that parses the output of
ldd binary_file. Be sure not to copy
system libraries (
libc, libpthread, libm etc). For an example,
see the sample
project
.

Make the script run during install with this:

meson
[[#meson.add_install_script]]('linux_bundler.sh')

Final steps

If you try to run the program now it will most likely fail to start or
crashes. The reason for this is that the system does not know that the
executable needs libraries from the
lib directory. The solution for
this is a simple wrapper script. Create a script called
myapp.sh
with the following content:

bash
#!/bin/bash

cd "${0%/*}"
export LD_LIBRARY_PATH="$(pwd)/lib"
bin/myapp

Install it with this Meson snippet:

meson
[[#install_data]]('myapp.sh', install_dir : '.')

And now you are done. Zip up your /tmp/myapp directory and you have
a working binary ready for deployment. To run the program, just unzip
the file and run
myapp.sh.

---

Markdown/Creating OSX Packages

---
short-description: Tools to create OS X packages
...

Creating OSX packages

Meson does not have native support for building OSX packages but it
does provide all the tools you need to create one yourself. The reason
for this is that it is a very hard task to write a system that
provides for all the different ways to do that but it is very easy to
write simple scripts for each application.

Sample code for this can be found in the Meson manual test
suite
.

Creating an app bundle

OSX app bundles are actually extremely simple. They are just a
directory of files in a certain format. All the details you need to
know are on this
page

and it is highly recommended that you read it first.

Let's assume that we are creating our app bundle into
/tmp/myapp.app. Suppose we have one executable, so we need to
install that into
Contents/MacOS. If we define the executable like
this:

meson
executable('myapp', 'foo1.c', ..., install : true)

then we just need to initialize our build tree with this command:

console
$ meson --prefix=/tmp/myapp.app \
--bindir=Contents/MacOS \
builddir \
<other flags you might need>

Now when we do meson install the bundle is properly staged. If you
have any resource files or data, you need to install them into
Contents/Resources either by custom install commands or specifying
more install paths to the Meson command.

Next we need to install an Info.plist file and an icon. For those we
need the following two Meson definitions.

meson
install_data('myapp.icns', install_dir : 'Contents/Resources')
install_data('Info.plist', install_dir : 'Contents')

The format of Info.plist can be found in the link or the sample
project linked above. The simplest way to get an icon in the
icns
format is to save your image as a tiff an then use the
tiff2icns helper
application that comes with XCode.

Some applications assume that the working directory of the app process
is the same where the binary executable is. If this is the case for
you, then you need to create a wrapper script that looks like this:

bash
#!/bin/bash

cd "${0%/*}"
./myapp

install it with this:

meson
install_data('myapp.sh', install_dir : 'Contents/MacOS')

and make sure that you specify myapp.sh as the executable to run in
your
Info.plist.

If you are not using any external libraries, this is all you need to
do. You now have a full app bundle in
/tmp/myapp.app that you can
use.

External libraries

Most applications use third party frameworks and libraries.
If it is the case for your project, you need to add them to
the bundle so it will work on other peoples' machines.

As an example we are going to use the SDL2
framework. In order to bundle it in our app, we first specify an
installer script to run.

meson
[[#meson.add_install_script]]('install_script.sh')

The install script does two things. First it copies the whole
framework into our bundle.

console
$ mkdir -p ${MESON_INSTALL_PREFIX}/Contents/Frameworks
$ cp -R /Library/Frameworks/SDL2.framework \
${MESON_INSTALL_PREFIX}/Contents/Frameworks

Then it needs to alter the library search path of our
executable(s). This tells OSX that the libraries your app needs are
inside your bundle. In the case of SDL2, the invocation goes like
this:

console
$ install_name_tool -change @rpath/SDL2.framework/Versions/A/SDL2 \
@executable_path/../FrameWorks/SDL2.framework/Versions/A/SDL2 \
${MESON_INSTALL_PREFIX}/Contents/MacOS/myapp

This is the part of OSX app bundling that you must always do
manually. OSX dependencies come in many shapes and forms and
unfortunately there is no reliable automatic way to determine how each
dependency should be handled. Frameworks go to the
Frameworks
directory while plain
.dylib files usually go to
Contents/Resources/lib (but you can put them wherever you like). To
get this done you have to check what your program links against with
otool -L /path/to/binary and manually add the copy and fix steps to
your install script. Do not copy system libraries inside your bundle,
though.

After this you have a fully working, self-contained OSX app bundle
ready for distribution.

#### Qt

Qt offers a deployment tool,
called
macdeployqt, that automates bundling Qt's libraries in your application folder and
optionally create the final
.dmg installer

console

cd into the folder that contains the myapp.app folder


macdeployqt myapp.app -executable=myapp.app/Contents/MacOS/myapp

This copies the needed Qt libraries to the correct subfolders within myapp.app.
The
-executable=myapp.app/Contents/MacOS/myapp argument is
to automatically alter the search path of the executable
myapp.app/Contents/MacOS/myapp for the Qt libraries. One can also pass the -dmg
argument to create a
.dmg installer from the updated myapp.app folder.
More information is available on the tool's documentation page.

Creating a .dmg installer

A .dmg installer is similarly quite simple, at its core it is
basically a fancy compressed archive. A good description can be found
on this page. Please read it
and create a template image file according to its instructions.

The actual process of creating the installer is very simple: you mount
the template image, copy your app bundle in it, unmount it and convert
the image into a compressed archive. The actual commands to do this
are not particularly interesting, feel free to steal them from either
the linked page above or from the sample script in Meson's test suite.

Putting it all together

There are many ways to put the .dmg installer together and different
people will do it in different ways. The linked sample code does it by
having two different scripts. This separates the different pieces
generating the installer into logical pieces.

install_script.sh only deals with embedding dependencies and fixing
the library paths.

build_osx_installer.sh sets up the build with the proper paths,
compiles, installs and generates the .dmg package.

The main reasoning here is that in order to build a complete OSX
installer package from source, all you need to do is to cd into the
source tree and run
./build_osx_installer.sh. To build packages on
other platforms you would write scripts such as
build_windows_installer.bat and so on.

---

Markdown/Creating Releases

---
short-description: Creating releases
...

Creating releases

In addition to development, almost all projects provide periodical
source releases. These are standalone packages (usually either in
tar or zip format) of the source code. They do not contain any
revision control metadata, only the source code. Meson provides
a simple way of generating these, with the
meson dist command.

Meson provides a simple way of generating these. It consists of a
single command (available since 0.52.0):

sh
meson dist

or alternatively (on older Meson versions with ninja backend):

sh
ninja dist

This creates a file called projectname-version.tar.xz in the build
tree subdirectory
meson-dist. This archive contains the full
contents of the latest commit in revision control including all the
submodules (recursively). All revision control metadata is removed.
Meson then takes this archive and tests that it works by doing a full
compile + test + install cycle. If all these pass, Meson will
then create a
SHA-256 checksum file next to the archive.

Modifying the dist directory before creating the archive

Modification to the checked out files like generating files or
setting version info can be done with dist scripts:

meson
[[#meson.add_dist_script]]('distscript.sh')

Autotools dist VS Meson dist

Meson behaviour is different from Autotools. The Autotools "dist"
target packages up the current source tree. Meson packages the latest
revision control commit. The reason for this is that it prevents
developers from doing accidental releases where the distributed
archive does not match any commit in revision control (especially the
one tagged for the release).


Include subprojects in your release

The meson dist command has --include-subprojects command line
option. When enabled, the source tree of all subprojects used by the
current build will also be included in the final tarball. This is
useful to distribute self contained tarball that can be built offline
(i.e.
--wrap-mode=nodownload).


Skip build and test with --no-tests

The meson dist command has a --no-tests option to skip build and
tests steps of generated packages. It can be used to not waste time
for example when done in CI that already does its own testing.

So with --no-tests you can tell Meson "Do not build and test generated
packages.".

Use --allow-dirty to override error when git repository contains uncommitted changes

Since 0.62.0 Instead of emitting a warning when a repository contains
uncommitted changes, Meson will produce an error message notifying the
user and immediately exit. If
--allow-dirty is given as an option to
meson dist, a warning will be emitted instead and Meson will proceed
as usual.

Release a subproject separately

Since 0.57.0 the meson dist command can now create a distribution tarball
for a subproject in the same git repository as the main project. This can be
useful if parts of the project (e.g. libraries) can be built and distributed
separately. In that case they can be moved into
subprojects/mysub and running
meson dist in that directory will now create a tarball containing only the
source code from that subdir and not the rest of the main project or other
subprojects.

For example:

sh
git clone https://github.com/myproject
cd myproject/subprojects/mysubproject
meson setup builddir
meson dist -C builddir

This produces
builddir/meson-dist/mysubproject-1.0.tar.xz tarball.

Cement a version obtained from VCS

Since 1.4.0 the meson dist command enables rewriting the build
configuration of the distribution tarball. This is needed when the
configuration depends on metadata from revision control such as in the
following example.

meson.build:

meson
project('tig', 'c',
version : run_command('version.sh', 'get-vcs').stdout().strip())

meson.add_dist_script('version.sh', 'set-dist', meson.project_version())


version.sh:
sh
#!/bin/sh

if [ "$1" = "get-vcs" ]; then
git -C "$MESON_SOURCE_ROOT" describe --always --dirty
elif [ "$1" = "set-dist" ]; then
$MESONREWRITE --sourcedir="$MESON_PROJECT_DIST_ROOT" kwargs set project / version "$2"
else
exit 1
fi

---

Markdown/Cross Compilation

---
short-description: Setting up cross-compilation
...

Cross compilation

Meson has full support for cross compilation through the use of
a cross build definition file. An minimal example of one such
file
x86_64-w64-mingw32.txt for a GCC/MinGW cross compiler
targeting 64-bit Windows could be:

ini
[binaries]
c = 'x86_64-w64-mingw32-gcc'
cpp = 'x86_64-w64-mingw32-g++'
ar = 'x86_64-w64-mingw32-ar'
windres = 'x86_64-w64-mingw32-windres'
strip = 'x86_64-w64-mingw32-strip'
exe_wrapper = 'wine64'

[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

Which is then used during the setup phase.

sh
meson setup --cross-file x86_64-w64-mingw32.txt build-mingw
meson compile -C build-mingw

Since cross compiling is
more complicated than native building, let's first go over some
nomenclature. The three most important definitions are traditionally
called build, host and target. This is confusing because those
terms are used for quite many different things. To simplify the issue,
we are going to call these the build machine, host machine and
target machine. Their definitions are the following:

build machine* is the computer that is doing the actual compiling.
host machine* is the machine on which the compiled binary will run.
target machine* is the machine on which the compiled binary's
output will run, only meaningful if the program produces
machine-specific output.

The tl/dr summary is the following: if you are doing regular cross
compilation, you only care about [[@build_machine]] and
[[@host_machine]]. Just ignore [[@target_machine]] altogether and you will
be correct 99% of the time. Only compilers and similar tools care
about the target machine. In fact, for so-called "multi-target" tools
the target machine need not be fixed at build-time like the others but
chosen at runtime, so
target_machine still doesn't matter. If your
needs are more complex or you are interested in the actual details, do
read on.

This might be easier to understand through examples. Let's start with
the regular, not cross-compiling case. In these cases all of these
three machines are the same. Simple so far.

Let's next look at the most common cross-compilation setup. 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). This should be quite understandable as
well.

The usual mistake in this case is to call the OSX system the host
and the ARM Linux board the target. That's because these were their
actual names when the cross-compiler itself was compiled! Let's assume
the cross-compiler was created on OSX too. When that happened the
build and host machines were the same OSX and different from the
ARM Linux target machine.

In a nutshell, the typical mistake assumes that the terms build,
host and target refer to some fixed positions whereas they're
actually relative to where the current compiler is running. Think of
host as a child of the current compiler and target as an
optional grand-child. Compilers don't change their terminology when
they're creating another compiler, that would at the very least make
their user interface much more complex.

The most complicated case is when you cross-compile a cross compiler.
As an example you can, on a Linux machine, generate a cross compiler
that runs on Windows but produces binaries for MIPS Linux. In this case
build machine is x86 Linux, host machine is x86 Windows and
target machine is MIPS Linux. This setup is known as the Canadian
Cross
.
As a side note, be careful when reading cross compilation articles on
Wikipedia or the net in general. It is very common for them to get
build, host and target mixed up, even in consecutive sentences, which
can leave you puzzled until you figure it out.

Again note that when you cross-compile something, the 3 systems
(build, host, and target) used when building the cross compiler
don't align with the ones used when building something with that
newly-built cross compiler. To take our Canadian Cross scenario from
above (for full generality), since its host machine is x86 Windows,
the build machine of anything we build with it is x86 Windows. And
since its target machine is MIPS Linux, the host machine of
anything we build with it is MIPS Linux. Only the target machine
of whatever we build with it can be freely chosen by us, say if we
want to build another cross compiler that runs on MIPS Linux and
targets Aarch64 iOS. As this example hopefully makes clear to you, the
machine names are relative and shifted over to the left by one
position.

If you did not understand all of the details, don't worry. For most
people it takes a while to wrap their head around these concepts.
Don't panic, it might take a while to click, but you will get the hang
of it eventually.

Defining the environment

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.

There are a number of options shared by cross and native files,
here. It is assumed that you have read that
section already, as this documentation will only call out options
specific to cross files.

Binaries

ini
[binaries]
exe_wrapper = 'wine' # A command used to run generated executables.

The exe_wrapper option defines a wrapper command that can be used
to run executables for this host. In this case we can use Wine, which
runs Windows applications on Linux. Other choices include running the
application with qemu or a hardware simulator. If you have this kind
of a wrapper, these lines are all you need to write. Meson will
automatically use the given wrapper when it needs to run host
binaries. This happens e.g. when running the project's test suite.

Note that exe_wrapper in the cross file is handled separately
from the
exe_wrapper argument in
add_test_setup
and
meson test --wrapper
command line argument. Meson must have
exe_wrapper specified in the
cross file or else it will skip tests that attempt to run cross
compiled binaries. Only the cross file
exe_wrapper value will be
stored in the
MESON_EXE_WRAPPER environment variable. If another
wrapper is given in the test setup with
exe_wrapper or as a
meson test --wrapper command line argument, then meson will prepend
the additional wrapper before the cross file wrapper like the
following command:

text
[prepend_wrapper] <cross_file_wrapper> <exe_binary> <args...>

Properties

In addition to the properties allowed in all machine
files
, the cross file may contain
specific information about the cross compiler or the host machine. It
looks like this:

ini
[properties]
sizeof_int = 4
sizeof_wchar_t = 4
sizeof_void* = 4

alignment_char = 1
alignment_void* = 4
alignment_double = 4

has_function_printf = true

sys_root = '/some/path'
pkg_config_libdir = '/some/path/lib/pkgconfig'

In most cases you don't need the size and alignment settings, Meson
will detect all these by compiling and running some sample programs.
If your build requires some piece of data that is not listed here,
Meson will stop and write an error message describing how to fix the
issue. If you need extra compiler arguments to be used during cross
compilation you can set them with
[langname]_args = [args]. Just
remember to specify the args as an array and not as a single string
(i.e. not as
'-DCROSS=1 -DSOMETHING=3').

Since 0.52.0 The sys_root property may point to the root of the
host system path (the system that will run the compiled binaries).
This is used internally by Meson to set the
PKG_CONFIG_SYSROOT_DIR
environment variable for pkg-config. If this is unset the host system
is assumed to share a root with the build system.

Since 0.54.0 The pkg_config_libdir property may point to a list of
path used internally by Meson to set the
PKG_CONFIG_LIBDIR environment
variable for pkg-config. This prevents pkg-config from searching cross
dependencies in system directories.

One important thing to note, if you did not define an exe_wrapper in
the previous section, is that Meson will make a best-effort guess at
whether it can run the generated binaries on the build machine. It
determines whether this is possible by looking at the
system and
cpu_family of build vs host. There will however be cases where they
do match up, but the build machine is actually not compatible with the
host machine. Typically this will happen if the libc used by the build
and host machines are incompatible, or the code relies on kernel
features not available on the build machine. One concrete example is a
macOS build machine producing binaries for an iOS Simulator x86-64
host. They're both
darwin and the same architecture, but their
binaries are not actually compatible. In such cases you may use the
needs_exe_wrapper property to override the auto-detection:

ini
[properties]
needs_exe_wrapper = true

Machine Entries

The next bit is the definition of host and target machines. Every
cross build definition must have one or both of them. If it had
neither, the build would not be a cross build but a native build. You
do not need to define the build machine, as all necessary information
about it is extracted automatically. The definitions for host and
target machines look the same. Here is a sample for host machine.

ini
[host_machine]
system = 'windows'
subsystem = 'windows'
kernel = 'nt'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'

These values define the machines sufficiently for cross compilation
purposes. The corresponding target definition would look the same but
have
target_machine in the header. These values are available in
your Meson scripts. There are three predefined variables called,
surprisingly, [[@build_machine]], [[@host_machine]] and
[[@target_machine]]. Determining the operating system of your host
machine is simply a matter of calling
host_machine.system().
Starting from version 1.2.0 you can get more fine grained information
using the
.subsystem() and .kernel() methods. The return values of
these functions are documented in the reference table
page
.

There are two different values for the CPU. The first one is
cpu_family. It is a general type of the CPU. This should have a
value from the CPU Family table.
Note that Meson does not add
el to end cpu_family value for little
endian systems. Big endian and little endian mips are both just
mips, with the endian field set appropriately.

The second value is cpu which is a more specific subtype for the
CPU. Typical values for a
x86 CPU family might include i386 or
i586 and for arm family armv5 or armv7hl. Note that CPU type
strings are very system dependent. You might get a different value if
you check its value on the same machine but with different operating
systems.

If you do not define your host machine, it is assumed to be the build
machine. Similarly if you do not specify target machine, it is assumed
to be the host machine.


Starting a cross build


Once you have the cross file, starting a build is simple

console
$ meson setup builddir --cross-file cross_file.txt

Once configuration is done, compilation is started by invoking meson compile
in the usual way.

Introspection and system checks

The main meson object provides two functions to determine cross
compilation status.

meson
[[#meson.is_cross_build]]        # returns true when cross compiling
[[#meson.can_run_host_binaries]] # returns true if the host binaries can be run, either with a wrapper or natively

You can run system checks on both the system compiler or the cross
compiler. You just have to specify which one to use.

meson
build_compiler = [[#meson.get_compiler]]('c', native : true)
host_compiler = [[#meson.get_compiler]]('c', native : false)

build_int_size = build_compiler.sizeof('int')
host_int_size = host_compiler.sizeof('int')

Mixing host and build targets

Sometimes you need to build a tool which is used to generate source
files. These are then compiled for the actual target. For this you
would want to build some targets with the system's native compiler.
This requires only one extra keyword argument.

meson
native_exe = executable('mygen', 'mygen.c', native : true)

You can then take native_exe and use it as part of a generator rule or anything else you might want.

Using a custom standard library

Sometimes in cross compilation you need to build your own standard
library instead of using the one provided by the compiler. Meson has
built-in support for switching standard libraries transparently. The
invocation to use in your cross file is the following:

ini
[properties]
c_stdlib = ['mylibc', 'mylibc_dep'] # Subproject name, variable name

This specifies that C standard library is provided in the Meson
subproject
mylibc in internal dependency variable mylibc_dep. It
is used on every cross built C target in the entire source tree
(including subprojects) and the standard library is disabled. The
build definitions of these targets do not need any modification.

Note that it is supported for any language, not only c, using <lang>_stdlib
property.

Since 0.56.0 the variable name parameter is no longer required as long as the
subproject calls
meson.override_dependency('c_stdlib', mylibc_dep).
The above example becomes:

ini
[properties]
c_stdlib = 'mylibc'

Changing cross file settings

Cross file settings are only read when the build directory is set up
the first time. Any changes to them after the fact will be ignored.
This is the same as regular compiles where you can't change the
compiler once a build tree has been set up. If you need to edit your
cross file, then you need to wipe your build tree and recreate it from
scratch.

Custom data

You can store arbitrary data in properties and access them from your
Meson files. As an example if your cross file has this:

ini
[properties]
somekey = 'somevalue'

then you can access that using the meson object like this:

meson
myvar = meson.get_external_property('somekey')

myvar now has the value 'somevalue'

Cross file locations

As of version 0.44.0 Meson supports loading cross files from system
locations (except on Windows). This will be
$XDG_DATA_DIRS/meson/cross, or if XDG_DATA_DIRS is undefined, then
/usr/local/share/meson/cross and /usr/share/meson/cross will be tried
in that order, for system wide cross files. User local files can be
put in $XDG_DATA_HOME/meson/cross, or ~/.local/share/meson/cross if
that is undefined.

The order of locations tried is as follows:
- A file relative to the local dir
- The user local location
- The system wide locations in order

Distributions are encouraged to ship cross files either with their
cross compiler toolchain packages or as a standalone package, and put
them in one of the system paths referenced above.

These files can be loaded automatically without adding a path to the
cross file. For example, if a ~/.local/share/meson/cross contains a
file called x86-linux, then the following command would start a cross
build using that cross files:

sh
meson setup builddir/ --cross-file x86-linux

---

Markdown/Cuda Module

---
short-description: CUDA module
authors:
- name: Olexa Bilaniuk
years: [2019]
has-copyright: false
...

Unstable CUDA Module


_Since: 0.50.0_

This module provides helper functionality related to the CUDA Toolkit and
building code using it.


Note: this module is unstable. It is only provided as a technology preview.
Its API may change in arbitrary ways between releases or it might be removed
from Meson altogether.


Importing the module

The module may be imported as follows:

` meson
cuda = [[#import]]('unstable-cuda')

text
It offers several useful functions that are enumerated below.


Functions

nvcc_arch_flags()


_Since: 0.50.0_
meson
cuda.nvcc_arch_flags(cuda_version_string, ...,
detected: string_or_array)
text
Returns a list of -gencode flags that should be passed to cuda_args: in
order to compile a "fat binary" for the architectures/compute capabilities
enumerated in the positional argument(s). The flags shall be acceptable to
an NVCC with CUDA Toolkit version string
cuda_version_string.

A set of architectures and/or compute capabilities may be specified by:

- The single positional argument 'All', 'Common' or 'Auto'
- As (an array of)
- Architecture names (
'Kepler', 'Maxwell+Tegra', 'Turing') and/or
- Compute capabilities (
'3.0', '3.5', '5.3', '7.5')

A suffix of +PTX requests PTX code generation for the given architecture.
A compute capability given as
A.B(X.Y) requests PTX generation for an older
virtual architecture
X.Y before binary generation for a newer architecture
A.B.

Multiple architectures and compute capabilities may be passed in using

- Multiple positional arguments
- Lists of strings
- Space (
), comma (,) or semicolon (;)-separated strings

The single-word architectural sets 'All', 'Common' or 'Auto'
cannot be mixed with architecture names or compute capabilities. Their
interpretation is:

| Name | Compute Capability |
|-------------------|--------------------|
|
'All' | All CCs supported by given NVCC compiler. |
|
'Common' | Relatively common CCs supported by given NVCC compiler. Generally excludes Tegra and Tesla devices. |
|
'Auto' | The CCs provided by the detected: keyword, filtered for support by given NVCC compiler. |

The supported architecture names and their corresponding compute capabilities
are:

| Name | Compute Capability |
|-------------------|----------------------------|
|
'Fermi' | 2.0, 2.1(2.0) |
|
'Kepler' | 3.0, 3.5 |
|
'Kepler+Tegra' | 3.2 |
|
'Kepler+Tesla' | 3.7 |
|
'Maxwell' | 5.0, 5.2 |
|
'Maxwell+Tegra' | 5.3 |
|
'Pascal' | 6.0, 6.1 |
|
'Pascal+Tegra' | 6.2 |
|
'Volta' | 7.0 |
|
'Xavier' | 7.2 |
|
'Turing' | 7.5 |
|
'Ampere' | 8.0, 8.6 |
|
'Orin' | 8.7 |
|
'Lovelace' | 8.9 |
|
'Hopper' | 9.0 |
|
'Hopper(A)' | 9.0a |
|
'Thor' | 10.1, 11.0 |
|
'Thor(A)' | 10.1a, 11.0a |
|
'Blackwell' | 10.0, 10.3, 12.0, 12.1 |
|
'Blackwell(A)' | 10.0a, 10.3a, 12.0a, 12.1a |

The '(A)' names select the architecture-specific (a-suffixed) compute
capabilities of their family. Code built for these can use
architecture-specific features, but runs only on exactly that architecture:
it has no forward compatibility, so it cannot be combined with
+PTX.
The family-specific
f-suffixed compute capabilities introduced with
CUDA 12.9 (e.g.
10.0f, which runs on all later members of the same
family) may be requested explicitly, but are not part of any named set.

Note: the f-suffixed capabilities only benefit kernels that use
architecture-conditional features (such as the 5th-generation tensor core
instructions), which plain compute capabilities cannot express. For all
other code they gain nothing: a plain capability plus
+PTX is compatible
beyond the family, and NVCC refuses to combine
X.Yf with plain X.Y
in the same build. Prefer the plain capabilities unless you know your
kernels require family-specific features.


Examples:

cuda.nvcc_arch_flags('10.0', '3.0', '3.5', '5.0+PTX')
cuda.nvcc_arch_flags('10.0', ['3.0', '3.5', '5.0+PTX'])
cuda.nvcc_arch_flags('10.0', [['3.0', '3.5'], '5.0+PTX'])
cuda.nvcc_arch_flags('10.0', '3.0 3.5 5.0+PTX')
cuda.nvcc_arch_flags('10.0', '3.0,3.5,5.0+PTX')
cuda.nvcc_arch_flags('10.0', '3.0;3.5;5.0+PTX')
cuda.nvcc_arch_flags('10.0', 'Kepler 5.0+PTX')
# Returns ['-gencode', 'arch=compute_30,code=sm_30',
# '-gencode', 'arch=compute_35,code=sm_35',
# '-gencode', 'arch=compute_50,code=sm_50',
# '-gencode', 'arch=compute_50,code=compute_50']

cuda.nvcc_arch_flags('10.0', '3.5(3.0)')
# Returns ['-gencode', 'arch=compute_30,code=sm_35']

cuda.nvcc_arch_flags('8.0', 'Common')
# Returns ['-gencode', 'arch=compute_30,code=sm_30',
# '-gencode', 'arch=compute_35,code=sm_35',
# '-gencode', 'arch=compute_50,code=sm_50',
# '-gencode', 'arch=compute_52,code=sm_52',
# '-gencode', 'arch=compute_60,code=sm_60',
# '-gencode', 'arch=compute_61,code=sm_61',
# '-gencode', 'arch=compute_61,code=compute_61']

cuda.nvcc_arch_flags('9.2', 'Auto', detected: '6.0 6.0 6.0 6.0')
cuda.nvcc_arch_flags('9.2', 'Auto', detected: ['6.0', '6.0', '6.0', '6.0'])
# Returns ['-gencode', 'arch=compute_60,code=sm_60']

cuda.nvcc_arch_flags(nvcc, 'All')
# Returns ['-gencode', 'arch=compute_20,code=sm_20',
# '-gencode', 'arch=compute_20,code=sm_21',
# '-gencode', 'arch=compute_30,code=sm_30',
# '-gencode', 'arch=compute_32,code=sm_32',
# '-gencode', 'arch=compute_35,code=sm_35',
# '-gencode', 'arch=compute_37,code=sm_37',
# '-gencode', 'arch=compute_50,code=sm_50', # nvcc.version() < 7.0
# '-gencode', 'arch=compute_52,code=sm_52',
# '-gencode', 'arch=compute_53,code=sm_53', # nvcc.version() >= 7.0
# '-gencode', 'arch=compute_60,code=sm_60',
# '-gencode', 'arch=compute_61,code=sm_61', # nvcc.version() >= 8.0
# '-gencode', 'arch=compute_70,code=sm_70',
# '-gencode', 'arch=compute_72,code=sm_72', # nvcc.version() >= 9.0
# '-gencode', 'arch=compute_75,code=sm_75'] # nvcc.version() >= 10.0

_Note:_ This function is intended to closely replicate CMake's FindCUDA module
function
CUDA_SELECT_NVCC_ARCH_FLAGS(out_variable, [list of CUDA compute architectures])

nvcc_arch_readable()


_Since: 0.50.0_
meson
cuda.nvcc_arch_readable(cuda_version_string, ...,
detected: string_or_array)
text
Has precisely the same interface as nvcc_arch_flags(),
but rather than returning a list of flags, it returns a "readable" list of
architectures that will be compiled for. The output of this function is solely
intended for informative message printing.

archs = '3.0 3.5 5.0+PTX'
readable = cuda.nvcc_arch_readable('10.0', archs)
message('Building for architectures ' + ' '.join(readable))

This will print

Message: Building for architectures sm30 sm35 sm50 compute50

_Note:_ This function is intended to closely replicate CMake's
FindCUDA module function
CUDA_SELECT_NVCC_ARCH_FLAGS(out_variable,
[list of CUDA compute architectures])

min_driver_version()


_Since: 0.50.0_
meson
cuda.min_driver_version(cuda_version_string)
``

Returns the minimum NVIDIA proprietary driver version required, on the
host system, by kernels compiled with a CUDA Toolkit with the given
version string.

The output of this function is generally intended for informative
message printing, but could be used for assertions or to conditionally
enable features known to exist within the minimum NVIDIA driver
required.

---