Friday, October 30, 2020

How to build dependencies as Meson subprojects using SDL as an example

Today we released version 0.56.0 of the Meson build system. This is an especially important release as it marks the 10 000th commit since the start of the project. A huge thank you to everyone who has contributed their time and effort, this project would not exist without all of you. However in this post we are not going to talk about that, those interested can find further details in the release notes. Instead we are going to be talking about how to build your dependencies from source on every platform without needing anything other than Meson. 

Last month I had a lightning talk at CppCon about this way of managing dependencies:

Since then there have been many improvements to the workflow for a smoother experience. To demonstrate this I upgraded the sample program to use SDL Mixer and SDL Image instead of relying on plain SDL. The code is available in this Github repo (only tested on Windows because I ran out of time to do proper multiplatform testing)  The core of the build definition is this:

sdl2_dep = dependency('sdl2')
sdl2_image_dep = dependency('sdl2_image')
sdl2_mixer_dep = dependency('sdl2_mixer')
executable('sdltestapp', 'main.cpp',
  dependencies : [sdl2_image_dep, sdl2_mixer_dep, sdl2_dep],
  win_subsystem: 'windows')

This has always worked on Linux and other platforms that provide system dependencies via Pkg-Config. As of the latest release of Meson and newest code from WrapDB, this works transparently on all platforms. Basically for every dependency you want to build yourself, you need a wrap file, like this:

The contents consist mostly of download links, hashes and build meta info. Upstream sources are not checked in your repo (unless you want to) so it remains small. The actual files are in the repository linked above. When you start building and the project needs some dependency, Meson will use info in wrap files to download, patch and build the dependencies as subprojects as needed. This is what it looks like when configuring on Windows using MSVC without any external dependency providers.

Then you can build it. Here I'm using Visual Studio Code because why not.

The end result runs directly as a native Windows application (text annotations not part of the original program) using SDL's Direct3D accelerated rendering.

There are three different source files loaded using SDL Image: a png file, a jpg file and an LZW compressed tif file. The app is also playing sound effects in Ogg Vorbis and wav formats using SDL Mixer. Dependencies of dependencies work automatically as one would expect. All dependency libraries are statically linked as it is the easiest way to get things working under Windows (at least until your project gets too big).

If you want to try it yourself, here's what you need to do:

  1. Install Visual Studio, Meson and Ninja (not strictly required, you can use the VS backend instead if you wish)
  2. Open the VS x64 dev tools shell.
  3. Clone the repo and cd inside it.
  4. Run meson build
  5. Run ninja -C build
The executable should now be at the root of the build dir ready to run.

Contributing to the WrapDB

The biggest problem facing WrapDB has at the moment is its selection of available libraries is fairly small. Fortunately it is easy to contribute new dependencies. There are two main cases.

Submitting projects that already build with Meson

  1. Make sure your project gets all its dependencies via the dependency function rather than invoking subproject directly and provide a suitable dependency object via declare_dependency.
  2. Create an upstream.wrap file with the necessary info. See the documentation or, if you prefer examples, how it is done in libtiff.
  3. Request that your project be added to WrapDB as described in the documentation linked above.
That's pretty much it. Once your project is in the WrapDB it can be immediately used by any other Meson project.

Contributing projects that do not build with Meson

The basic outline is the same as above, except that first you need to rewrite the project's build system in Meson. I'm not going to lie: sometimes this is a fair bit of work. Sometimes it is not the most pleasant thing in the world. No pain, no gain and all that.

Given that there are thousands upon thousands of projects available, which ones should be converted first? The most obvious answer is the ones that you personally need, because then you are doing work that directly benefits yourself. After that it gets trickier. One good approach is to look at established cross platform open source projects. Many of them have a directory where they store copies of their third party dependencies. Any libraries there are most likely needed by other programs as well. Here are links to some of them:

No comments:

Post a Comment