1# How do I do X in Meson? 2 3This page lists code snippets for common tasks. These are written 4mostly using the C compiler, but the same approach should work on 5almost all other compilers. 6 7## Set compiler 8 9When first running Meson, set it in an environment variable. 10 11```console 12$ CC=mycc meson <options> 13``` 14 15Note that environment variables like `CC` only works in native builds. The `CC` 16refers to the compiler for the host platform, that is the compiler used to 17compile programs that run on the machine we will eventually install the project 18on. The compiler used to build things that run on the machine we do the 19building can be specified with `CC_FOR_BUILD`. You can use it in cross builds. 20 21Note that environment variables are never the idiomatic way to do anything with 22Meson, however. It is better to use the native and cross files. And the tools 23for the host platform in cross builds can only be specified with a cross file. 24 25There is a table of all environment variables supported [Here](Reference-tables.md#compiler-and-linker-selection-variables) 26 27 28## Set dynamic linker 29 30*New in 0.53.0* 31 32Like the compiler, the linker is selected via the `<compiler variable>_LD` 33environment variable, or through the `<compiler entry>_ld` entry in a native 34or cross file. You must be aware of whether you're using a compiler that 35invokes the linker itself (most compilers including GCC and Clang) or a 36linker that is invoked directly (when using MSVC or compilers that act like 37it, including Clang-Cl). With the former `c_ld` or `CC_LD` should be the value 38to pass to the compiler's special argument (such as `-fuse-ld` with clang and 39gcc), with the latter it should be an executable, such as `lld-link.exe`. 40 41*NOTE* In meson 0.53.0 the `ld` entry in the cross/native file and the `LD` 42environment variable were used, this resulted in a large number of regressions 43and was changed in 0.53.1 to `<lang>_ld` and `<comp variable>_LD`. 44 45```console 46$ CC=clang CC_LD=lld meson <options> 47``` 48 49or 50 51```console 52$ CC=clang-cl CC_LD=link meson <options> 53``` 54 55or in a cross or native file: 56 57```ini 58[binaries] 59c = 'clang' 60c_ld = 'lld' 61``` 62 63There is a table of all environment variables supported [Here](Reference-tables.md#compiler-and-linker-selection-variables) 64 65 66## Set default C/C++ language version 67 68```meson 69project('myproj', 'c', 'cpp', 70 default_options : ['c_std=c11', 'cpp_std=c++11']) 71``` 72 73The language version can also be set on a per-target basis. 74 75```meson 76executable(..., override_options : ['c_std=c11']) 77``` 78 79## Enable threads 80 81Lots of people seem to do this manually with `find_library('pthread')` 82or something similar. Do not do that. It is not portable. Instead do 83this. 84 85```meson 86thread_dep = dependency('threads') 87executable(..., dependencies : thread_dep) 88``` 89 90## Set extra compiler and linker flags from the outside (when e.g. building distro packages) 91 92The behavior is the same as with other build systems, with environment 93variables during first invocation. Do not use these when you need to rebuild 94the source 95 96```console 97$ CFLAGS=-fsomething LDFLAGS=-Wl,--linker-flag meson <options> 98``` 99 100## Use an argument only with a specific compiler 101 102First check which arguments to use. 103 104```meson 105if meson.get_compiler('c').get_id() == 'clang' 106 extra_args = ['-fclang-flag'] 107else 108 extra_args = [] 109endif 110``` 111 112Then use it in a target. 113 114```meson 115executable(..., c_args : extra_args) 116``` 117 118If you want to use the arguments on all targets, then do this. 119 120```meson 121if meson.get_compiler('c').get_id() == 'clang' 122 add_global_arguments('-fclang-flag', language : 'c') 123endif 124``` 125 126## Set a command's output to configuration 127 128```meson 129txt = run_command('script', 'argument').stdout().strip() 130cdata = configuration_data() 131cdata.set('SOMETHING', txt) 132configure_file(...) 133``` 134 135## Generate a runnable script with `configure_file` 136 137`configure_file` preserves metadata so if your template file has 138execute permissions, the generated file will have them too. 139 140## Producing a coverage report 141 142First initialize the build directory with this command. 143 144```console 145$ meson <other flags> -Db_coverage=true 146``` 147 148Then issue the following commands. 149 150```console 151$ meson compile 152$ meson test 153$ meson compile coverage-html (or coverage-xml) 154``` 155 156The coverage report can be found in the meson-logs subdirectory. 157 158*New in 0.55.0* llvm-cov support for use with clang 159 160## Add some optimization to debug builds 161 162By default the debug build does not use any optimizations. This is the 163desired approach most of the time. However some projects benefit from 164having some minor optimizations enabled. GCC even has a specific 165compiler flag `-Og` for this. To enable its use, just issue the 166following command. 167 168```console 169$ meson configure -Dc_args=-Og 170``` 171 172This causes all subsequent builds to use this command line argument. 173 174## Use address sanitizer 175 176Clang comes with a selection of analysis tools such as the [address 177sanitizer](https://clang.llvm.org/docs/AddressSanitizer.html). Meson 178has native support for these with the `b_sanitize` option. 179 180```console 181$ meson <other options> -Db_sanitize=address 182``` 183 184After this you just compile your code and run the test suite. Address 185sanitizer will abort executables which have bugs so they show up as 186test failures. 187 188## Use Clang static analyzer 189 190Install scan-build and configure your project. Then do this: 191 192```console 193$ meson compile scan-build 194``` 195 196You can use the `SCANBUILD` environment variable to choose the 197scan-build executable. 198 199```console 200$ SCANBUILD=<your exe> meson compile scan-build 201``` 202 203 204## Use profile guided optimization 205 206Using profile guided optimization with GCC is a two phase 207operation. First we set up the project with profile measurements 208enabled and compile it. 209 210```console 211$ meson setup <Meson options, such as --buildtype=debugoptimized> -Db_pgo=generate 212$ meson compile -C builddir 213``` 214 215Then we need to run the program with some representative input. This 216step depends on your project. 217 218Once that is done we change the compiler flags to use the generated 219information and rebuild. 220 221```console 222$ meson configure -Db_pgo=use 223$ meson compile 224``` 225 226After these steps the resulting binary is fully optimized. 227 228## Add math library (`-lm`) portably 229 230Some platforms (e.g. Linux) have a standalone math library. Other 231platforms (pretty much everyone else) do not. How to specify that `m` 232is used only when needed? 233 234```meson 235cc = meson.get_compiler('c') 236m_dep = cc.find_library('m', required : false) 237executable(..., dependencies : m_dep) 238``` 239 240## Install an executable to `libexecdir` 241 242```meson 243executable(..., install : true, install_dir : get_option('libexecdir')) 244``` 245 246## Use existing `Find<name>.cmake` files 247 248Meson can use the CMake `find_package()` ecosystem if CMake is installed. 249To find a dependency with custom `Find<name>.cmake`, set the `cmake_module_path` 250property to the path in your project where the CMake scripts are stored. 251 252Example for a `FindCmakeOnlyDep.cmake` in a `cmake` subdirectory: 253 254```meson 255cm_dep = dependency('CmakeOnlyDep', cmake_module_path : 'cmake') 256``` 257 258The `cmake_module_path` property is only needed for custom CMake scripts. System 259wide CMake scripts are found automatically. 260 261More information can be found [here](Dependencies.md#cmake) 262 263## Get a default not-found dependency? 264 265```meson 266null_dep = dependency('', required : false) 267``` 268 269This can be used in cases where you want a default value, but might override it 270later. 271 272```meson 273# Not needed on Windows! 274my_dep = dependency('', required : false) 275if host_machine.system() in ['freebsd', 'netbsd', 'openbsd', 'dragonfly'] 276 my_dep = dependency('some dep', required : false) 277elif host_machine.system() == 'linux' 278 my_dep = dependency('some other dep', required : false) 279endif 280 281executable( 282 'myexe', 283 my_sources, 284 deps : [my_dep] 285) 286``` 287