Getting started with Meson in C++ (part 3)

German Diago Gomez
5 min readMay 21, 2018

Hello everyone. After seeing how to manage basic dependencies in Meson in the previous post, today we are going to see how to perform installation of our software in Meson.

Installing your own executables, libraries, etc. in Meson is not very different from what you can see in tools such as in CMake and, especially, Autotools.

We will start with the project startingmeson2 as our starting point and will proceed from there.

Performing installation: basic functions

So, what can you do when performing installation? If you take a look at Meson help , you will see the following:

--prefix PREFIX       Installation prefix (default: /usr/local).
--libdir LIBDIR Library directory (default: lib).
--libexecdir LIBEXECDIR
Library executable directory (default: libexec).
--bindir BINDIR Executable directory (default: bin).
--sbindir SBINDIR System executable directory (default: sbin).
--includedir INCLUDEDIR
Header file directory (default: include).
--datadir DATADIR Data file directory (default: share).
--mandir MANDIR Manual page directory (default: share/man).
--infodir INFODIR Info page directory (default: share/info).
--localedir LOCALEDIR
Locale data directory (default: share/locale).
--sysconfdir SYSCONFDIR
Sysconf data directory (default: etc).
--localstatedir LOCALSTATEDIR
Localstate data directory (default: var).
--sharedstatedir SHAREDSTATEDIR
Architecture-independent data directory (default:
com).

These are the default directories for installation, which looks very similar to Autotools. In Meson you have a few functions for explicit installation:

  • install_headers
  • install_man
  • install_subdir
  • install_data

Let us see what they do: install_headers install, as it is obvious, installs headers. The permissions are correctly set for what you want to do with them. You can use a subdir keyword argument if you want your headers to be installed in a subdirectory of includedir.

The function install_man installs compressed, as it is usual for man pages, in the default directory MANDIR

The function install_subdir will install a full subdirectory. You can include/exclude and other options to tweak its behavior.

The function install_data is more flexible and you can set the permissions, owner and group of the files with a syntax familiar to POSIX semantics.

All of these functions support a keyword argument install_dir that can change where things are installed by default. If you give it an absolute path, that is used. If you use a relative path, it will be used relative to the installation prefix for the kind of install_* command you are using. For example, if you writeinstall_data('LICENSE.txt', install_mode : 'rw-r--r--', install_dir : 'license')then your license will be installed in DATADIR/license/LICENSE.txt.

Performing installation: direct support for your executables and libraries

In Meson, many times you can just skip the install_* commands and use keyword arguments in your executables and libraries that will do the right thing for you.

For example, if you want to install an executable, you just need to use the install keyword for your library or executable: executable('myprog', sources : 'mysource.cpp', install : true)and your executable/library will be installed in the expected default directory.

But the story is not so easy sometimes: what about RPATH and the like if you are using shared libraries? For security reasons, binaries in many systems are installed in ways in which the libraries they can point to are restricted: this is done to avoid injecting code at run-time through malicious techniques such as changing the runtime library search and loading untrusted code.

Meson has direct support for RPATH handling. Meson supports two keywords for this: build_rpath and install_rpath.

The build_rpath keyword argument can be used for loading some library at runtime when building before installation. Namely, you can point to your executable/library somewhere in your build directory. Note that this build_rpath is removed after installation. You should not usually need to use this, since Meson, at least for me, always finds the libraries after compiling (it seems to set the right dependencies at least in common cases) but I just wanted to mention that this keyword argument exists in case you need it.

The install_rpath keyword argument is used after (and only after) installation. Please note that LIBDIR is relative to PREFIX. Rpaths are usually absolute directories, so when setting it, use PREFIX explicitly, besides LIBDIR:

executable('myprog', sources : 'mysource.cpp',
install_rpath : join_paths(get_option('prefix'), get_option('libdir'))

Custom install scripts

Meson supports the execution of custom logic at install time. Just add your script like this and it will be executed.

meson.add_install_script('myscript')

In these scripts, you have access to the following environment variables:

  • MESON_INSTALL_PREFIX
  • MESON_SOURCE_ROOT
  • MESON_BUILD_ROOT
  • MESON_ISNTALL_DESTDIR_PREFIX
  • MESONINTROSPECT

Note that Meson supports, as far as my knowledge goes, shebang parsing, including Windows. This means that you can leave your script language choice as an implementation detail and put the shebang line and the right interpreter will be called.

Since Meson uses Python as a dependency, it is a good idea to use Python for multiplatform scripting (instead of bash) if Windows is one of the systems you must support, because, anyway, Python must be installed. People often say Python dependency for a build system is a bad idea, but, well, in this scenario… it can help us :)

Advanced features: DESTDIR

Sometimes package maintainers need to install a library in a staged directory, without running any code. This is a feature that is directly supported by Meson through the DESTDIR environment variable. DESTDIR is a variable that affects where things are installed without affecting any other thing. For example, if you issue the following:

meson --prefix=/my/custom/prefix builddir
DESTDIR=/my/staging ninja -C builddir install

This will install things in /my/staging/my/custom/prefix. But it will not affect RPATHS or other things. This is what maintainers or bulk installs want: they just want a staging dir, but things will be eventually moved to /my/custom/prefix and everything will work. They do not need to run anything from the staging dir.

Installation example

Now let us go practical. The example presented in the article starts from the project created in the previous post, which is also available in the Github repository under the name startingmeson2.

We are going to modify the project startingmeson2 and call it (surprisingly!) startingmeson3.

The project, besides the name change, will:

  • install a executable
  • install the dependent library in a subdirectory, to force setting rpath in our executable
  • set the install_rpath for the executable

The relevant modifications, are as follows. We want to install the executable, so we tell Meson and we also tell meson where to point the rpath to:

executable('startingmeson3', sources : ['startingmeson3.cpp'],
dependencies : mylib_dep, install : true,
install_rpath : join_paths(get_option('prefix'), get_option('libdir'), 'mylib'))

You set the library as installable as well and set the install directory:

mylib = library('mylib', sources : ['mylib.hpp', 'mylib.cpp'],
dependencies : [boost_dep, boost_filesystem_dep],
install : true,
install_dir : join_paths(get_option('libdir'), 'mylib'))

With these two small modifications to staringmeson2 now we have a project that installs the executable, the dependent library in a custom directory, and RPATH settings correctly set for our executable.

Now, try to compile and install. From the root of the project:

mkdir build
meson --prefix=`pwd`/install build
ninja -C build install

Now you have an executable in install/bin, the library in install/lib/mylib and everything set up correctly to be run.

The full example can be found under the name startingmeson3 in the Github repository.

That’s all for today and happy Meson use!

For the next installment in the series we will take a look at the basics of Meson command line and language syntax, which I left behind because the language is quite simple. I also plan to write about cross compilation, but that will have to wait a bit longer.

You can find the next part of this series here.

Thanks for reading!

--

--

German Diago Gomez

In software industry for more than a decade doing backend software.