### README # Meson Documentation ## Build dependencies Meson uses itself and [hotdoc](https://github.com/hotdoc/hotdoc) for generating documentation. Minimum required version of hotdoc is *0.8.9*. Instructions on how to install hotdoc are [here](https://hotdoc.github.io/installing.html). Our custom hotdoc extensions require: - [chevron](https://pypi.org/project/chevron) - [strictyaml](https://pypi.org/project/strictyaml) ## Building the documentation From the Meson repository root dir: ``` $ cd docs/ $ meson setup built_docs/ $ ninja -C built_docs/ ``` Now you should be able to open the documentation locally ``` 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: ``` $ 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, `_args` and `_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 `#include`ed - `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`](Build-options.md#features) 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](Dependencies.md#qt) The 'modules' argument is used to include Qt modules in the project. See the Qt documentation for the [list of modules](http://doc.qt.io/qt-5/qtmodules.html). 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](Reference-manual.md) * [Options](Build-options.md) * [Configuration](Configuration.md) * [Dependencies](Dependencies.md) * [Tests](Unit-tests.md) * [Syntax](Syntax.md) ### [Modules](Module-reference.md) * [codegen](Codegen-module.md) * [gnome](Gnome-module.md) * [i18n](i18n-module.md) * [pkgconfig](Pkgconfig-module.md) * [rust](Rust-module.md) * [wayland](Wayland-module.md) --- ### 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](Reference-manual.md). 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](Reference-tables.md). 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](https://github.com/mesonbuild/wrapdb). 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. ``` ${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: ``` sha256sum path/to/libfoo-1.0.0.tar.gz ``` Under macOS the command is the following: ``` 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](Wrap-dependency-system-manual.md). 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/`. ``` ${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](https://github.com/mesonbuild/wrapdb#readme), and push the result to GitHub. ``` 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. ``` ${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= 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](Builtin-options.md). 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](Build-options.md) 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](Cross-compilation.md#defining-the-environment), 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](#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,
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,
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,
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 - ``` 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` 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](https://clang.llvm.org/docs/AddressSanitizer.html#usage) (`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](https://clang.llvm.org/docs/ThinLTO.html) 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
c++2a, c++1z, gnu++03, gnu++11, gnu++14, gnu++17, gnu++1z,
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 `_*` options are specified per machine. See below in the [specifying options per machine](#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 `_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](#specifying-options-per-subproject) 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.