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