Some platforms do not provide a native packaging system. In these cases it is common to bundle all third party libraries in your source tree. This is usually frowned upon because it makes it hard to add these kinds of projects into e.g. those Linux distributions that forbid bundled libraries.

Meson tries to solve this problem by making it extremely easy to provide both at the same time. The way this is done is that Meson allows you to take any other Meson project and make it a part of your build without (in the best case) any changes to its Meson setup. It becomes a transparent part of the project. The basic idiom goes something like this.

dep = dependency('foo', fallback : [subproject_name, variable_name])

As an example, suppose we have a simple project that provides a shared library. It would be set up like this.

project('simple', 'c')
i = include_directories('include')
l = shared_library('simple', 'simple.c', include_directories : i, install : true)
simple_dep = declare_dependency(include_directories : i,
  link_with : l)

Then we could use that from a master project. First we generate a subdirectory called subprojects in the root of the master directory. Then we create a subdirectory called simple and put the subproject in that directory. Now the subproject can be used like this.

project('master', 'c')
dep = dependency('simple', fallback : ['simple', 'simple_dep'])
exe = executable('prog', 'prog.c',
                 dependencies : dep, install : true)

With this setup the system dependency is used when it is available, otherwise we fall back on the bundled version. If you wish to always use the embedded version, then you would declare it like this:

simple_sp = subproject('simple')
dep = simple_sp.get_variable('simple_dep')

All Meson features of the subproject, such as project options keep working and can be set in the master project. There are a few limitations, the most important being that global compiler arguments must be set in the main project before calling subproject. Subprojects must not set global arguments because there is no way to do that reliably over multiple subprojects. To check whether you are running as a subproject, use the is_subproject function.

It should be noted that this only works for subprojects that are built with Meson. It can not be used with any other build system. The reason is the simple fact that there is no possible way to do this reliably with mixed build systems.

Subprojects can use other subprojects, but all subprojects must reside in the top level subprojects directory. Recursive use of subprojects is not allowed, though, so you can't have subproject a that uses subproject b and have b also use a.

Command-line options

The usage of subprojects can be controlled by users and distros with the following command-line options:

  • --wrap-mode=nodownload

    Meson will not use the network to download any subprojects or fetch any wrap information. Only pre-existing sources will be used. This is useful (mostly for distros) when you want to only use the sources provided by a software release, and want to manually handle or provide missing dependencies.

  • --wrap-mode=nofallback

    Meson will not use subproject fallbacks for any dependency declarations in the build files, and will only look for them in the system. Note that this does not apply to unconditional subproject() calls, and those are meant to be used for sources that cannot be provided by the system, such as copylibs.

  • --wrap-mode=forcefallback

    Meson will not look at the system for any dependencies which have subproject fallbacks available, and will only use subprojects for them. This is useful when you want to test your fallback setup, or want to specifically build against the library sources provided by your subprojects.

Obtaining subprojects

Meson ships with a dependency system to automatically obtain dependency subprojects. It is documented in the Wrap dependency system manual.

Why must all subprojects be inside a single directory?

There are several reasons.

First of all, to maintain any sort of sanity, the system must prevent going inside other subprojects with subdir() or variations thereof. Having the subprojects in well defined places makes this easy. If subprojects could be anywhere at all, it would be a lot harder.

Second of all it is extremely important that end users can easily see what subprojects any project has. Because they are in one, and only one, place, reviewing them becomes easy.

This is also a question of convention. Since all Meson projects have the same layout w.r.t subprojects, switching between projects becomes easier. You don't have to spend time on a new project traipsing through the source tree looking for subprojects. They are always in the same place.

Finally if you can have subprojects anywhere, this increases the possibility of having many different (possibly incompatible) versions of a dependency in your source tree. Then changing some code (such as changing the order you traverse directories) may cause a completely different version of the subproject to be used by accident.

The results of the search are