|
|
|
# Wrap dependency system manual
|
|
|
|
|
|
|
|
One of the major problems of multiplatform development is wrangling
|
|
|
|
all your dependencies. This is easy on Linux where you can use system
|
|
|
|
packages but awkward on other platforms. Most of those do not have a
|
|
|
|
package manager at all. This has been worked around by having third
|
|
|
|
party package managers. They are not really a solution for end user
|
|
|
|
deployment, because you can't tell them to install a package manager
|
|
|
|
just to use your app. On these platforms you must produce
|
|
|
|
self-contained applications.
|
|
|
|
|
|
|
|
The traditional approach to this has been to bundle dependencies
|
|
|
|
inside your own project. Either as prebuilt libraries and headers or
|
|
|
|
by embedding the source code inside your source tree and rewriting
|
|
|
|
your build system to build them as part of your project.
|
|
|
|
|
|
|
|
This is both tedious and error prone because it is always done by
|
|
|
|
hand. The Wrap dependency system of Meson aims to provide an automated
|
|
|
|
way to do this.
|
|
|
|
|
|
|
|
## How it works
|
|
|
|
|
|
|
|
Meson has a concept of [subprojects](Subprojects.md). They are a way
|
|
|
|
of nesting one Meson project inside another. Any project that builds
|
|
|
|
with Meson can detect that it is built as a subproject and build
|
|
|
|
itself in a way that makes it easy to use (usually this means as a
|
|
|
|
static library).
|
|
|
|
|
|
|
|
To use this kind of a project as a dependency you could just copy and
|
|
|
|
extract it inside your project's `subprojects` directory. However
|
|
|
|
there is a simpler way. You can specify a Wrap file that tells Meson
|
|
|
|
how to download it for you. An example wrap file would look like this
|
|
|
|
and should be put in `subprojects/foobar.wrap`:
|
|
|
|
|
|
|
|
```ini
|
|
|
|
[wrap-file]
|
|
|
|
directory = libfoobar-1.0
|
|
|
|
|
|
|
|
source_url = https://example.com/foobar-1.0.tar.gz
|
|
|
|
source_filename = foobar-1.0.tar.gz
|
|
|
|
source_hash = 5ebeea0dfb75d090ea0e7ff84799b2a7a1550db3fe61eb5f6f61c2e971e57663
|
|
|
|
```
|
|
|
|
|
|
|
|
If you then use this subproject in your build, Meson will
|
|
|
|
automatically download and extract it during build. This makes
|
|
|
|
subproject embedding extremely easy.
|
|
|
|
|
|
|
|
Unfortunately most software projects in the world do not build with
|
|
|
|
Meson. Because of this Meson allows you to specify a patch URL. This
|
|
|
|
works in much the same way as Debian's distro patches. That is, they
|
|
|
|
are downloaded and automatically applied to the subproject. These
|
|
|
|
files contain a Meson build definition for the given subproject. A
|
|
|
|
wrap file with an additional patch URL would look like this.
|
|
|
|
|
|
|
|
```ini
|
|
|
|
[wrap-file]
|
|
|
|
directory = libfoobar-1.0
|
|
|
|
|
|
|
|
source_url = https://upstream.example.com/foobar-1.0.tar.gz
|
|
|
|
source_filename = foobar-1.0.tar.gz
|
|
|
|
source_hash = 5ebeea0dfb75d090ea0e7ff84799b2a7a1550db3fe61eb5f6f61c2e971e57663
|
|
|
|
|
|
|
|
patch_url = https://myserver.example.com/libfoobar-meson.tar.gz
|
|
|
|
patch_filename = libfoobar-meson.tar.gz
|
|
|
|
patch_hash = 8c9d00702d5fe4a6bf25a36b821a332f6b2dfd117c66fe818b88b23d604635e9
|
|
|
|
```
|
|
|
|
|
|
|
|
In this example the Wrap manager would download the patch and unzip it
|
|
|
|
in libfoobar's directory.
|
|
|
|
|
|
|
|
This approach makes it extremely simple to embed dependencies that
|
|
|
|
require build system changes. You can write the Meson build definition
|
|
|
|
for the dependency in total isolation. This is a lot better than doing
|
|
|
|
it inside your own source tree, especially if it contains hundreds of
|
|
|
|
thousands of lines of code. Once you have a working build definition,
|
|
|
|
just zip up the Meson build files (and others you have changed) and
|
|
|
|
put them somewhere where you can download them.
|
|
|
|
|
|
|
|
## Branching subprojects directly from git
|
|
|
|
|
|
|
|
The above mentioned scheme assumes that your subproject is working off
|
|
|
|
packaged files. Sometimes you want to check code out directly from
|
|
|
|
Git. Meson supports this natively. All you need to do is to write a
|
|
|
|
slightly different wrap file.
|
|
|
|
|
|
|
|
```ini
|
|
|
|
[wrap-git]
|
|
|
|
directory = samplesubproject
|
|
|
|
url = https://github.com/jpakkane/samplesubproject.git
|
|
|
|
revision = head
|
|
|
|
```
|
|
|
|
|
|
|
|
The format is straightforward. The only thing to note is the revision
|
|
|
|
element that can have one of two values. The first is `head` which
|
|
|
|
will cause Meson to track the master head (doing a repull whenever the
|
|
|
|
build definition is altered). The second type is a commit hash or a
|
|
|
|
tag. In this case Meson will use the commit specified (with `git
|
|
|
|
checkout [hash/tag id]`).
|
|
|
|
|
|
|
|
Note that in this case you cannot specify an extra patch file to
|
|
|
|
use. The git repo must contain all necessary Meson build definitions.
|
|
|
|
|
|
|
|
Usually you would use subprojects as read only. However in some cases
|
|
|
|
you want to do commits to subprojects and push them upstream. For
|
|
|
|
these cases you can specify the upload URL by adding the following at
|
|
|
|
the end of your wrap file:
|
|
|
|
|
|
|
|
```ini
|
|
|
|
push-url = git@git.example.com:projects/someproject.git # Supported since version 0.37.0
|
|
|
|
```
|
|
|
|
|
|
|
|
If the git repo contains submodules, you can tell Meson to clone them
|
|
|
|
automatically by adding the following *(since 0.48.0)*:
|
|
|
|
|
|
|
|
```ini
|
|
|
|
clone-recursive = true
|
|
|
|
```
|
|
|
|
|
|
|
|
## Using wrapped projects
|
|
|
|
|
|
|
|
To use a subproject simply do this in your top level `meson.build`.
|
|
|
|
|
|
|
|
```meson
|
|
|
|
foobar_proj = subproject('foobar')
|
|
|
|
```
|
|
|
|
|
|
|
|
Usually dependencies consist of some header files plus a library to
|
|
|
|
link against. To do this in a project so it can be used as a subproject you
|
|
|
|
would declare this internal dependency like this:
|
|
|
|
|
|
|
|
```meson
|
|
|
|
foobar_dep = declare_dependency(link_with : mylib,
|
|
|
|
include_directories : myinc)
|
|
|
|
```
|
|
|
|
|
|
|
|
Then in your main project you would use them like this:
|
|
|
|
|
|
|
|
```meson
|
|
|
|
executable('toplevel_exe', 'prog.c',
|
|
|
|
dependencies : foobar_proj.get_variable('foobar_dep'))
|
|
|
|
```
|
|
|
|
|
|
|
|
Note that the subproject object is *not* used as the dependency, but
|
|
|
|
rather you need to get the declared dependency from it with
|
|
|
|
`get_variable` because a subproject may have multiple declared
|
|
|
|
dependencies.
|
|
|
|
|
|
|
|
## Toggling between distro packages and embedded source
|
|
|
|
|
|
|
|
When building distro packages it is very important that you do not
|
|
|
|
embed any sources. Some distros have a rule forbidding embedded
|
|
|
|
dependencies so your project must be buildable without them or
|
|
|
|
otherwise the packager will hate you.
|
|
|
|
|
|
|
|
Doing this with Meson and Wrap is simple. Here's how you would use
|
|
|
|
distro packages and fall back to embedding if the dependency is not
|
|
|
|
available.
|
|
|
|
|
|
|
|
```meson
|
|
|
|
foobar_dep = dependency('foobar', required : false)
|
|
|
|
|
|
|
|
if not foobar_dep.found()
|
|
|
|
foobar_proj = subproject('foobar')
|
|
|
|
# the subproject defines an internal dependency with
|
|
|
|
# the command declare_dependency().
|
|
|
|
foobar_dep = foobar_proj.get_variable('foobar_dep')
|
|
|
|
endif
|
|
|
|
|
|
|
|
executable('toplevel_exe', 'prog.c',
|
|
|
|
dependencies : foobar_dep)
|
|
|
|
```
|
|
|
|
|
|
|
|
Because this is such a common operation, Meson provides a shortcut for
|
|
|
|
this use case.
|
|
|
|
|
|
|
|
```meson
|
|
|
|
foobar_dep = dependency('foobar', fallback : ['foobar', 'foobar_dep'])
|
|
|
|
```
|
|
|
|
|
|
|
|
The `fallback` keyword argument takes two items, the name of the
|
|
|
|
subproject and the name of the variable that holds the dependency. If
|
|
|
|
you need to do something more complicated, such as extract several
|
|
|
|
different variables, then you need to do it yourself with the manual
|
|
|
|
method described above.
|
|
|
|
|
|
|
|
With this setup when foobar is provided by the system, we use it. When
|
|
|
|
that is not the case we use the embedded version. Note that
|
|
|
|
`foobar_dep` can point to an external or an internal dependency but
|
|
|
|
you don't have to worry about their differences. Meson will take care
|
|
|
|
of the details for you.
|
|
|
|
|
|
|
|
## Getting wraps
|
|
|
|
|
|
|
|
Usually you don't want to write your wraps by hand. There is an online
|
|
|
|
repository called [WrapDB](Using-the-WrapDB.md) that provides many
|
|
|
|
dependencies ready to use.
|