| # An in-depth tutorial | |
| In this tutorial we set up a project with multiple targets, unit tests | |
| and dependencies between targets. Our main product is a shared library | |
| called *foo* that is written in `C++11`. We are going to ignore the | |
| contents of the source files, as they are not really important from a | |
| build definition point of view. The library makes use of the `GLib` | |
| library so we need to detect and link it properly. We also make the | |
| resulting library installable. | |
| The source tree contains three subdirectories `src`, `include` and | |
| `test` that contain, respectively, the source code, headers and unit | |
| tests of our project. | |
| To start things up, here is the top level `meson.build` file. | |
| ```meson | |
| project('c++ foolib', 'cpp', | |
| version : '1.0.0', | |
| license : 'MIT') | |
| add_global_arguments('-DSOME_TOKEN=value', language : 'cpp') | |
| glib_dep = dependency('glib-2.0') | |
| inc = include_directories('include') | |
| subdir('include') | |
| subdir('src') | |
| subdir('test') | |
| pkg_mod = import('pkgconfig') | |
| pkg_mod.generate(libraries : foolib, | |
| version : '1.0', | |
| name : 'libfoobar', | |
| filebase : 'foobar', | |
| description : 'A Library to barnicate your foos.') | |
| ``` | |
| The definition always starts with a call to the `project` function. In | |
| it you must specify the project's name and programming languages to | |
| use, in this case only `C++`. We also specify two additional | |
| arguments, the project's version and the license it is under. Our | |
| project is version `1.0.0` and is specified to be under the MIT | |
| license. | |
| Then we find GLib, which is an *external dependency*. The `dependency` | |
| function tells Meson to find the library (by default using | |
| `pkg-config`). If the library is not found, Meson will raise an error | |
| and stop processing the build definition. | |
| Then we add a global compiler argument `-DSOME_TOKEN=value`. This flag | |
| is used for *all* C++ source file compilations. It is not possible to | |
| unset it for some targets. The reason for this is that it is hard to | |
| keep track of what compiler flags are in use if global settings change | |
| per target. | |
| Since `include` directory contains the header files, we need a way to | |
| tell compilations to add that directory to the compiler command line. | |
| This is done with the `include_directories` command that takes a | |
| directory and returns an object representing this directory. It is | |
| stored in variable `inc` which makes it accessible later on. | |
| After this are three `subdir` commands. These instruct Meson to go to | |
| the specified subdirectory, open the `meson.build` file that's in | |
| there and execute it. The last few lines are a stanza to generate a | |
| `pkg-config` file. We'll skip that for now and come back to it at the | |
| end of this document. | |
| The first subdirectory we go into is `include`. In it we have a | |
| header file for the library that we want to install. This requires one | |
| line. | |
| ```meson | |
| install_headers('foolib.h') | |
| ``` | |
| This installs the given header file to the system's header directory. | |
| This is by default `/[install prefix]/include`, but it can be changed | |
| with a command line argument. | |
| The Meson definition of `src` subdir is simple. | |
| ```meson | |
| foo_sources = ['source1.cpp', 'source2.cpp'] | |
| foolib = shared_library('foo', | |
| foo_sources, | |
| include_directories : inc, | |
| dependencies : glib_dep, | |
| install : true) | |
| ``` | |
| Here we just tell Meson to build the library with the given sources. | |
| We also tell it to use the include directories we stored to variable | |
| `inc` earlier. Since this library uses GLib, we tell Meson to add all | |
| necessary compiler and linker flags with the `dependencies` keyword | |
| argument. Its value is `glib_dep` which we set at the top level | |
| `meson.build` file. The `install` argument tells Meson to install the | |
| result. As with the headers, the shared library is installed to the | |
| system's default location (usually `/[install prefix]/lib`) but is | |
| again overridable. | |
| The resulting library is stored in variable `foolib` just like the | |
| include directory was stored in the previous file. | |
| Once Meson has processed the `src` subdir it returns to the main Meson | |
| file and executes the next line that moves it into the `test` subdir. | |
| Its contents look like this. | |
| ```meson | |
| testexe = executable('testexe', 'footest.cpp', | |
| include_directories : inc, | |
| link_with : foolib) | |
| test('foolib test', testexe) | |
| ``` | |
| First we build a test executable that has the same include directory | |
| as the main library and which also links against the freshly built | |
| shared library. Note that you don't need to specify `glib_dep` here | |
| just to be able to use the built library `foolib`. If the executable | |
| used GLib functionality itself, then we would of course need to add it | |
| as a keyword argument here. | |
| Finally we define a test with the name `foolib test`. It consists of | |
| running the binary we just built. If the executable exits with a zero | |
| return value, the test is considered passed. Nonzero return values | |
| mark the test as failed. | |
| At this point we can return to the pkg-config generator line. All | |
| shared libraries should provide a pkg-config file, which explains how | |
| that library is used. Meson provides this simple generator that should | |
| be sufficient for most simple projects. All you need to do is list a | |
| few basic pieces of information and Meson takes care of generating an | |
| appropriate file. More advanced users might want to create their own | |
| pkg-config files using Meson's [configuration file generator | |
| system](Configuration.md). | |
| With these four files we are done. To configure, build and run the | |
| test suite, we just need to execute the following commands (starting | |
| at source tree root directory). | |
| ```console | |
| $ meson setup builddir && cd builddir | |
| $ meson compile | |
| $ meson test | |
| ``` | |
| To then install the project you only need one command. | |
| ```console | |
| $ meson install | |
| ``` |