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