| # 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 |
| ``` |