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).
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
------
@ -13,25 +24,58 @@ The first thing we measured was the time it took to run the configure step.
![GLib config time](images/glib_conf.png)
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.
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.
Then we measured the build times. Two parallel compilation processes
were used for both systems.
![GLib build time](images/glib_build.png)
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.
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.
![GLib no-op time](images/glib_empty.png)
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.
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.
![GLib link time](images/glib_link.png)
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.
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.
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
Often you need to specify extra compiler arguments. Meson provides two different ways to achieve this: global arguments and per-target 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.
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.
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.
Per target arguments
--
@ -30,7 +46,8 @@ Per target arguments are just as simple to define.
**If you don't have permissions to do something on this page, please open issue against https://github.com/mesonbuild/wrapweb/issues to let us know that you want to start new project.**
**If you don't have permissions to do something on this page, please
open issue against https://github.com/mesonbuild/wrapweb/issues to
let us know that you want to start new project.**
## Overview
The wrap provider service is a simple web service that makes it easy to download build definitions for projects. It works 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 Git repositories on GitHub. They only contain build definition files. You may also think of them as an overlay to upstream source.
The wrap provider service is a simple web service that makes it easy
to download build definitions for projects. It works 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
Git repositories on GitHub. They only contain build definition
files. You may also think of them as an overlay to upstream source.
## Creator script
The WrapDB repository has a [helper script](https://github.com/mesonbuild/wrapweb/blob/master/tools/repoinit.py) to generate new repositories. The documentation below roughly explains what it does using plain shell commands.
to generate new repositories. The documentation below roughly explains
what it does using plain shell commands.
## Choosing the repository name
Wrapped subprojects are used much like external dependencies. Thus they should have the same name as the upstream projects. If the project provides a pkg-config file, then the repository 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 repository is named plain `ogg`.
Wrapped subprojects are used much like external dependencies. Thus
they should have the same name as the upstream projects. If the
project provides a pkg-config file, then the repository 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 repository is
named plain `ogg`.
## Adding new project to the Wrap provider service
@ -61,13 +78,21 @@ First you need to fork the repository to your own page. Then you can create the
git commit -a -m 'Created wrap files for libfoo-1.0.0.'
git push origin 1.0.0
Now you can file a merge request. Remember to file it against branch 1.0.0 rather than master. GitHub should do this automatically.
Now you can file a merge request. Remember to file it against branch
1.0.0 rather than master. GitHub should do this automatically.
## 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.
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.
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
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 a option definition file. Its name is `meson_options.txt` and it is placed at the root of your source tree.
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 a option definition
file. Its name is `meson_options.txt` and it is placed at the root of
your source tree.
Here is a simple option file.
@ -14,7 +18,14 @@ option('other_one', type : 'boolean', value : false)
option('combo_opt', type : 'combo', choices : ['one', 'two', 'three'], value : 'three')
```
This demonstrates the three basic option types and their usage. String option is just a free form string and a boolean option is, unsurprisingly, true or false. The combo option can have any value from the strings listed in argument `choices`. If `value` is not set, it defaults to empty string for strings, `true` for booleans or the first element in a combo. You can specify `description`, which is a free form piece of text describing the option. It defaults to option name.
This demonstrates the three basic option types and their usage. String
option is just a free form string and a boolean option is,
unsurprisingly, true or false. The combo option can have any value
from the strings listed in argument `choices`. If `value` is not set,
it defaults to empty string for strings, `true` for booleans or the
first element in a combo. You can specify `description`, which is a
free form piece of text describing the option. It defaults to option
name.
These options are accessed in Meson code with the `get_option` function.
@ -22,13 +33,19 @@ These options are accessed in Meson code with the `get_option` function.
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:
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 can not set option values in your Meson scripts. They have to be set externally with the `mesonconf` command line tool. Running `mesonconf` without arguments in a build dir shows you all options you can set. To change their values use the `-D` option:
It should be noted that you can not set option values in your Meson
scripts. They have to be set externally with the `mesonconf` command
line tool. Running `mesonconf` without arguments in a build dir shows
you all options you can set. To change their values use the `-D`
@ -4,10 +4,24 @@ 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.
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.
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.
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
@ -4,7 +4,13 @@ short-description: Definition of build targets
# Build targets
Meson provides three kinds of build targets: executables, static libraries and shared libraries. They are created with the commands `executable`, `static_library` and `shared_library`, respectively. All objects created in this way are **immutable**. That is, you can not 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.
Meson provides three kinds of build targets: executables, static
libraries and shared libraries. They are created with the commands
`executable`, `static_library` and `shared_library`, respectively. All
objects created in this way are **immutable**. That is, you can not
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.
As an example, here is how you would build a shared library.
@ -13,14 +19,16 @@ project('shared lib', 'c')
shared_library('mylib', 'source.c')
```
In Unix-like operating systems, shared libraries can be versioned. Meson supports this with keyword arguments.
In Unix-like operating systems, shared libraries can be
versioned. Meson supports this with keyword arguments.
```meson
project('shared lib', 'c')
shared_library('mylib', 'source.c', version : '1.2.3', soversion : '0')
```
It is common to build a library and then an executable that links against it. This is supported as well.
It is common to build a library and then an executable that links
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.
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.
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.
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.
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.
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.
In Meson you can extract object files from targets and use them as-is
Here we take the internal class object and use it directly in the test. The source file is only compiled once.
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.
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
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.
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.
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).
Needlessly slow, complicated, hard to use correctly, unreliable,
painful to debug, incomprehensible for most people, poor support for
non-Unix platforms (especially Windows).
## CMake ##
@ -24,7 +32,8 @@ 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.
The scripting language is cumbersome to work with. Some simple things
are more complicated than necessary.
## SCons ##
@ -34,7 +43,11 @@ 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.
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
@ -44,14 +57,22 @@ 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](https://bazel.build/contributing.html).
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](https://bazel.build/contributing.html).
## Meson ##
### Pros ###
The fastest build system [see measurements](Performance-comparison.md), 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.
The fastest build system [see
measurements](Performance-comparison.md), 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.
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
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.
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.
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](Cross-compilation.md). But if you just want to know the operating system your code will run on, issue this command:
This is a bit complex and more thoroughly explained on the page on
[cross compilation](Cross-compilation.md). But if you just want to
know the operating system your code will run on, issue this command:
```meson
host_machine.system()
@ -19,7 +28,9 @@ host_machine.system()
Compiler id
==
The compiler object has a method called `get_id`, which returns a lower case string describing the "family" of the compiler. It has one of the following values.
The compiler object has a method called `get_id`, which returns a
lower case string describing the "family" of the compiler. It has one
of the following values.
| Value | Compiler family |
| ----- | ---------------- |
@ -42,7 +53,9 @@ The compiler object has a method called `get_id`, which returns a lower case str
Does code compile?
==
Sometimes the only way to test the system is to try to compile some sample code and see if it works. This is a two-phase operation. First we define some code using the multiline string operator:
Sometimes the only way to test the system is to try to compile some
sample code and see if it works. This is a two-phase operation. First
we define some code using the multiline string operator:
```meson
code = '''#include<stdio.h>
@ -56,15 +69,18 @@ Then we can run the test.
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.
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.
Does code compile and link?
==
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 '''.links()''' method on a
compiler object like this:
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
'''.links()''' method on a compiler object like this:
```meson
code = '''#include<stdio.h>
@ -79,9 +95,9 @@ 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.
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
@ -100,7 +116,9 @@ int main(int argc, char **argv) {
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`.
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
| ------ | ------------
@ -121,7 +139,11 @@ 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.
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')
@ -132,20 +154,31 @@ 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.
Often you need to determine the size of a particular element (such as
`int`, `wchar_t` or `char*`). Using the `compiler` variable mentioned
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.
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.
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 `somefunc` exists in header `someheader.h`
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 `somefunc`
exists in header `someheader.h`
```meson
if compiler.has_function('somefunc', prefix : '#include<someheader.h>')
@ -156,7 +189,9 @@ 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</hh> contains a member called `some_member`.
Some platforms have different standard structures. Here's how one
would check if a struct called `mystruct` from header `myheader.h</hh>
contains a member called `some_member`.
```meson
if compiler.has_member('struct mystruct', 'some_member', prefix : '#include<myheader.h>')
@ -167,7 +202,10 @@ 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.
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.
@ -175,10 +213,13 @@ 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.
This method tests if the compiler supports a given command line
argument. This is implemented by compiling a small file with the given
@ -4,11 +4,18 @@ 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.txt` file and so on.
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.txt` file and so on.
The main tool for this is the `mesonconf` script. You may also use the `mesongui` graphical application if you want. However this document describes the use of the command line client.
The main tool for this is the `mesonconf` script. You may also use the
`mesongui` graphical application if you want. However this document
describes the use of the command line client.
You invoke `mesonconf` 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.
You invoke `mesonconf` 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
@ -43,8 +50,14 @@ You invoke `mesonconf` by giving it the location of your build dir. If omitted,
This project does not have any options
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.
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.
mesonconf -Dprefix=/tmp/testroot
Then you would run your build command (usually `ninja`), 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.
Then you would run your build command (usually `ninja`), 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.
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*).
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
@ -4,7 +4,10 @@ short-description: Build targets for custom languages or corner-cases
# Custom build targets
While Meson tries to support as many languages and tools as possible, there is no possible way for it to cover all corner cases. For these cases it permits you to define custom build targets. Here is how one would use it.
While Meson tries to support as many languages and tools as possible,
there is no possible way for it to cover all corner cases. For these
cases it permits you to define custom build targets. Here is how one
This would generate the binary `output.bin` and install it to `${prefix}/subdir/output.bin`. Variable substitution works just like it does for source generation.
This would generate the binary `output.bin` and install it to
`${prefix}/subdir/output.bin`. Variable substitution works just like
it does for source generation.
## Details on compiler invocations ##
Meson only permits you to specify one command to run. This is by design as writing shell pipelines into build definition files leads to code that is very hard to maintain. If your compilation requires multiple steps you need to write a wrapper script that does all the necessary work. When doing this you need to be mindful of the following issues:
Meson only permits you to specify one command to run. This is by
design as writing shell pipelines into build definition files leads to
code that is very hard to maintain. If your compilation requires
multiple steps you need to write a wrapper script that does all the
necessary work. When doing this you need to be mindful of the
following issues:
* do not assume that the command is invoked in any specific directory
* a target called `target` file `outfile` defined in subdir `subdir` must be written to `build_dir/subdir/foo.dat`
* if you need a subdirectory for temporary files, use `build_dir/subdir/target.dir`
* a target called `target` file `outfile` defined in subdir `subdir`
must be written to `build_dir/subdir/foo.dat`
* if you need a subdirectory for temporary files, use
@ -4,14 +4,22 @@ short-description: Dependencies for external libraries and frameworks
# Dependencies
Very few applications are fully self-contained, but rather they use external libraries and frameworks to do their work. Meson makes it very easy to find and use external dependencies. Here is how one would use the zlib compression library.
Very few applications are fully self-contained, but rather they use
external libraries and frameworks to do their work. Meson makes it
very easy to find and use external dependencies. Here is how one would
First Meson is told to find the external library `zlib` and error out if it is not found. The `version` keyword is optional and specifies a version requirement for the dependency. Then an executable is built using the specified dependency. Note how the user does not need to manually handle compiler or linker flags or deal with any other minutiae.
First Meson is told to find the external library `zlib` and error out
if it is not found. The `version` keyword is optional and specifies a
version requirement for the dependency. Then an executable is built
using the specified dependency. Note how the user does not need to
manually handle compiler or linker flags or deal with any other
minutiae.
If you have multiple dependencies, pass them as an array:
@ -19,7 +27,8 @@ If you have multiple dependencies, pass them as an array:
If the dependency is optional, you can tell Meson not to error out if the dependency is not found and then do further configuration.
If the dependency is optional, you can tell Meson not to error out if
the dependency is not found and then do further configuration.
```meson
opt_dep = dependency('somedep', required : false)
@ -30,26 +39,39 @@ else
endif
```
You can pass the `opt_dep` variable to target construction functions whether the actual dependency was found or not. Meson will ignore non-found dependencies.
You can pass the `opt_dep` variable to target construction functions
whether the actual dependency was found or not. Meson will ignore
non-found dependencies.
The dependency detector works with all libraries that provide a `pkg-config` file. Unfortunately several packages don't provide pkg-config files. Meson has autodetection support for some of these.
The dependency detector works with all libraries that provide a
`pkg-config` file. Unfortunately several packages don't provide
pkg-config files. Meson has autodetection support for some of these.
## Boost ##
Boost is not a single dependency but rather a group of different libraries. To use Boost with Meson, simply list which Boost modules you would like to use.
Boost is not a single dependency but rather a group of different
libraries. To use Boost with Meson, simply list which Boost modules
You can call `dependency` multiple times with different modules and use those to link against your targets.
You can call `dependency` multiple times with different modules and
use those to link against your targets.
If your boost headers or libraries are in non-standard locations you can set the BOOST_ROOT, BOOST_INCLUDEDIR, and/or BOOST_LIBRARYDIR environment variables.
If your boost headers or libraries are in non-standard locations you
can set the BOOST_ROOT, BOOST_INCLUDEDIR, and/or BOOST_LIBRARYDIR
environment variables.
## GTest and GMock ##
GTest and GMock come as sources that must be compiled as part of your project. With Meson you don't have to care about the details, just pass `gtest` or `gmock` to `dependency` and it will do everything for you. If you want to use GMock, it is recommended to use GTest as well, as getting it to work standalone is tricky.
GTest and GMock come as sources that must be compiled as part of your
project. With Meson you don't have to care about the details, just
pass `gtest` or `gmock` to `dependency` and it will do everything for
you. If you want to use GMock, it is recommended to use GTest as well,
as getting it to work standalone is tricky.
## MPI ##
@ -60,15 +82,17 @@ language-specific, you must specify the requested language using the
* `dependency('mpi', language='cpp')` for the C++ MPI headers and libraries
* `dependency('mpi', language='fortran')` for the Fortran MPI headers and libraries
Meson prefers pkg-config for MPI, but if your MPI implementation does not
provide them, it will search for the standard wrapper executables, `mpic`,
`mpicxx`, `mpic++`, `mpifort`, `mpif90`, `mpif77`. If these are not in your
path, they can be specified by setting the standard environment variables
`MPICC`, `MPICXX`, `MPIFC`, `MPIF90`, or `MPIF77`, during configuration.
Meson prefers pkg-config for MPI, but if your MPI implementation does
not provide them, it will search for the standard wrapper executables,
`mpic`, `mpicxx`, `mpic++`, `mpifort`, `mpif90`, `mpif77`. If these
are not in your path, they can be specified by setting the standard
environment variables `MPICC`, `MPICXX`, `MPIFC`, `MPIF90`, or
`MPIF77`, during configuration.
## Qt5 ##
Meson has native Qt5 support. Its usage is best demonstrated with an example.
Meson has native Qt5 support. Its usage is best demonstrated with an
example.
```meson
qt5_mod = import('qt5')
@ -88,7 +112,15 @@ q5exe = executable('qt5test',
dependencies: qt5widgets)
```
Here we have an UI file created with Qt Designer and one source and header file each that require preprocessing with the `moc` tool. We also define a resource file to be compiled with `rcc`. We just have to tell Meson which files are which and it will take care of invoking all the necessary tools in the correct order, which is done with the `preprocess` method of the `qt5` module. Its output is simply put in the list of sources for the target. The `modules` keyword of `dependency` works just like it does with Boost. It tells which subparts of Qt the program uses.
Here we have an UI file created with Qt Designer and one source and
header file each that require preprocessing with the `moc` tool. We
also define a resource file to be compiled with `rcc`. We just have to
tell Meson which files are which and it will take care of invoking all
the necessary tools in the correct order, which is done with the
`preprocess` method of the `qt5` module. Its output is simply put in
the list of sources for the target. The `modules` keyword of
`dependency` works just like it does with Boost. It tells which
subparts of Qt the program uses.
## Pcap
@ -102,7 +134,9 @@ pcap_dep = dependency('pcap', version : '>=1.0')
## Declaring your own
You can declare your own dependency objects that can be used interchangeably with dependency objects obtained from the system. The syntax is straightforward:
You can declare your own dependency objects that can be used
interchangeably with dependency objects obtained from the system. The
As a part of the software configuration, you may want to get extra data by running external commands. The basic syntax is the following.
As a part of the software configuration, you may want to get extra
data by running external commands. The basic syntax is the following.
```meson
r = run_command('command', 'arg1', 'arg2', 'arg3')
@ -15,6 +16,19 @@ output = r.stdout().strip()
errortxt = r.stderr().strip()
```
The `run_command` function returns an object that can be queried for return value and text written to stdout and stderr. The `strip` method call is used to strip trailing and leading whitespace from strings. Usually output from command line programs ends in a newline, which is unwanted in string variables. The first argument can be either a string or an executable you have detected earlier with `find_program`.
The `run_command` function returns an object that can be queried for
return value and text written to stdout and stderr. The `strip` method
call is used to strip trailing and leading whitespace from
strings. Usually output from command line programs ends in a newline,
which is unwanted in string variables. The first argument can be
either a string or an executable you have detected earlier with
`find_program`.
Note that you can not pass your command line as a single string. That is, calling `run_command('do_something foo bar')` will not work. You must either split up the string into separate arguments or pass the split command as an array. It should also be noted that Meson will not pass the command to the shell, so any command lines that try to use things such as environment variables, backticks or pipelines will not work. If you require shell semantics, write your command into a script file and call that with `run_command`.
Note that you can not pass your command line as a single string. That
is, calling `run_command('do_something foo bar')` will not work. You
must either split up the string into separate arguments or pass the
split command as an array. It should also be noted that Meson will not
pass the command to the shell, so any command lines that try to use
things such as environment variables, backticks or pipelines will not
work. If you require shell semantics, write your command into a script
@ -4,11 +4,22 @@ short-description: Using precompiled headers to reduce compilation time
# Precompiled headers
Parsing header files of system libraries is surprisingly expensive. A typical source file has less than one thousand lines of code. In contrast the headers of large libraries can be tens of thousands of lines. This is especially problematic with C++, where header-only libraries are common and they may contain extremely complex code. This makes them slow to compile.
Precompiled headers are a tool to mitigate this issue. Basically what they do is parse the headers and then serialize the compiler's internal state to disk. The downside of precompiled headers is that they are tricky to set up. Meson has native support for precompiled headers, but using them takes a little work.
A precompiled header file is relatively simple. It is a header file that contains `#include` directives for the system headers to precompile. Here is a C++ example.
Parsing header files of system libraries is surprisingly expensive. A
typical source file has less than one thousand lines of code. In
contrast the headers of large libraries can be tens of thousands of
lines. This is especially problematic with C++, where header-only
libraries are common and they may contain extremely complex code. This
makes them slow to compile.
Precompiled headers are a tool to mitigate this issue. Basically what
they do is parse the headers and then serialize the compiler's
internal state to disk. The downside of precompiled headers is that
they are tricky to set up. Meson has native support for precompiled
headers, but using them takes a little work.
A precompiled header file is relatively simple. It is a header file
that contains `#include` directives for the system headers to
precompile. Here is a C++ example.
```cpp
#include<vector>
@ -16,7 +27,13 @@ A precompiled header file is relatively simple. It is a header file that contain
#include<map>
```
In Meson, precompiled header files are always per-target. That is, the given precompiled header is used when compiling every single file in the target. Due to limitations of the underlying compilers, this header file must not be in the same subdirectory as any of the source files. It is strongly recommended that you create a subdirectory called `pch` in the target directory and put the header files (and nothing else) there.
In Meson, precompiled header files are always per-target. That is, the
given precompiled header is used when compiling every single file in
the target. Due to limitations of the underlying compilers, this
header file must not be in the same subdirectory as any of the source
files. It is strongly recommended that you create a subdirectory
called `pch` in the target directory and put the header files (and
nothing else) there.
Toggling the usage of precompiled headers
--
@ -33,15 +50,23 @@ order) and working around compiler bugs.
Using precompiled headers with GCC and derivatives
--
Once you have a file to precompile, you can enable the use of pch for a give target with a *pch* keyword argument. As an example, here's how you would use it with a C binary.
Once you have a file to precompile, you can enable the use of pch for
a give target with a *pch* keyword argument. As an example, here's how
You should note that your source files must _not_ include the file `myexe_pch.h` and you must _not_ add the pch subdirectory to your search path. Meson will make the compiler include the pch with compiler options. If you want to disable pch (because of, say, compiler bugs), it can be done entirely on the build system side with no changes to source code.
You should note that your source files must _not_ include the file
`myexe_pch.h` and you must _not_ add the pch subdirectory to your
search path. Meson will make the compiler include the pch with
compiler options. If you want to disable pch (because of, say,
compiler bugs), it can be done entirely on the build system side with
no changes to source code.
You can use precompiled headers on any build target. If your target has multiple languages, you can specify multiple pch files like this.
You can use precompiled headers on any build target. If your target
has multiple languages, you can specify multiple pch files like this.
MSVC is a bit trickier, because in addition to the header file, it also requires a corresponding source file. If your header is called `foo_pch.h`, the corresponding source file is usually called `foo_pch.cpp` and it resides in the same `pch` subdirectory as the header. Its contents are this:
MSVC is a bit trickier, because in addition to the header file, it
also requires a corresponding source file. If your header is called
`foo_pch.h`, the corresponding source file is usually called
`foo_pch.cpp` and it resides in the same `pch` subdirectory as the
This form will work with both GCC and msvc, because Meson knows that GCC does not need a `.cpp` file and thus just ignores it.
This form will work with both GCC and msvc, because Meson knows that
GCC does not need a `.cpp` file and thus just ignores it.
It should be noted that due to implementation details of the MSVC compiler, having precompiled headers for multiple languages in the same target is not guaranteed to work.
It should be noted that due to implementation details of the MSVC
compiler, having precompiled headers for multiple languages in the