| --- |
| short-description: Using Meson projects as subprojects within other Meson projects |
| ... |
| |
| # Subprojects |
| |
| 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. |
| |
| It should be noted that this is only guaranteed to work for subprojects |
| that are built with Meson. The reason is the simple fact that there is |
| no possible way to do this reliably with mixed build systems. Because of |
| this, only Meson subprojects are described here. |
| [CMake based subprojects](CMake-module.md#cmake-subprojects) are also |
| supported but not guaranteed to work. |
| |
| ## A subproject example |
| |
| Usually dependencies consist of some header files plus a library to |
| link against. To declare this internal dependency use |
| `declare_dependency` function. |
| |
| As an example, suppose we have a simple project that provides a shared |
| library. Its `meson.build` would look like this. |
| |
| ```meson |
| project('libsimple', 'c') |
| |
| inc = include_directories('include') |
| libsimple = shared_library('simple', |
| 'simple.c', |
| include_directories : inc, |
| install : true) |
| |
| libsimple_dep = declare_dependency(include_directories : inc, |
| link_with : libsimple) |
| ``` |
| |
| ### Naming convention for dependency variables |
| |
| Ideally the dependency variable name should be of `<project_name>_dep` |
| form. This way one can just use it without even looking inside build |
| definitions of that subproject. |
| |
| In cases where there are multiple dependencies need to be declared, |
| the default one should be named as `<project_name>_dep` (e.g. |
| `gtest_dep`), and others can have `<project_name>_<other>_<name>_dep` |
| form (e.g. `gtest_main_dep` - gtest with main function). |
| |
| There may be exceptions to these rules where common sense should be applied. |
| |
| ### Adding variables to the dependency |
| |
| *New in 0.54.0* |
| |
| In some cases a project may define special variables via pkg-config or |
| cmake that a caller needs to know about. Meson provides a |
| `dependency.get_variable` method to hide what kind of dependency is |
| provided, and this is available to subprojects as well. Use the |
| `variables` keyword to add a dict of strings: |
| |
| ```meson |
| my_dep = declare_dependency(..., variables : {'var': 'value', 'number': '3'}) |
| ``` |
| |
| Which another project can access via: |
| |
| ```meson |
| var = my_dep.get_variable(internal : 'var', cmake : 'CMAKE_VAR') |
| ``` |
| |
| The values of the dict must be strings, as pkg-config and cmake will |
| return variables as strings. |
| |
| ### Build options in subproject |
| |
| 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. |
| |
| ## Using a subproject |
| |
| All subprojects must be inside `subprojects` directory. The |
| `subprojects` directory must be at the top level of your project. |
| Subproject declaration must be in your top level `meson.build`. |
| |
| ### A simple example |
| |
| Let's use `libsimple` as a subproject. |
| |
| At the top level of your project create `subprojects` directory. |
| Then copy `libsimple` into `subprojects` directory. |
| |
| Your project's `meson.build` should look like this. |
| |
| ```meson |
| project('my_project', 'cpp') |
| |
| libsimple_proj = subproject('libsimple') |
| libsimple_dep = libsimple_proj.get_variable('libsimple_dep') |
| |
| executable('my_project', |
| 'my_project.cpp', |
| dependencies : libsimple_dep, |
| install : true) |
| ``` |
| |
| 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 system libraries and embedded sources |
| |
| 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. |
| |
| Here's how you would use system libraries and fall back to embedding sources |
| if the dependency is not available. |
| |
| ```meson |
| project('my_project', 'cpp') |
| |
| libsimple_dep = dependency('libsimple', required : false) |
| |
| if not libsimple_dep.found() |
| libsimple_proj = subproject('libsimple') |
| libsimple_dep = libsimple_proj.get_variable('libsimple_dep') |
| endif |
| |
| executable('my_project', |
| 'my_project.cpp', |
| dependencies : libsimple_dep, |
| install : true) |
| ``` |
| |
| Because this is such a common operation, Meson provides a shortcut for |
| this use case. |
| |
| ```meson |
| dep = dependency('foo', fallback : [subproject_name, variable_name]) |
| ``` |
| |
| 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. |
| |
| Using this shortcut the build definition would look like this. |
| |
| ```meson |
| project('my_project', 'cpp') |
| |
| libsimple_dep = dependency('libsimple', fallback : ['libsimple', 'libsimple_dep']) |
| |
| executable('my_project', |
| 'my_project.cpp', |
| dependencies : libsimple_dep, |
| install : true) |
| ``` |
| |
| With this setup when libsimple is provided by the system, we use it. |
| When that is not the case we use the embedded version (the one from |
| subprojects). |
| |
| Note that `libsimple_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. |
| |
| ### Subprojects depending on other subprojects |
| |
| 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`. |
| |
| ## Obtaining subprojects |
| |
| Meson ships with a dependency system to automatically obtain |
| dependency subprojects. It is documented in the [Wrap dependency |
| system manual](Wrap-dependency-system-manual.md). |
| |
| ## 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. |
| |
| This option may be overridden by `--force-fallback-for` for specific |
| dependencies. |
| |
| * **--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. |
| |
| * **--force-fallback-for=list,of,dependencies** |
| |
| Meson will not look at the system for any dependencies listed there, |
| provided a fallback was supplied when the dependency was declared. |
| |
| This option takes precedence over `--wrap-mode=nofallback`, and when |
| used in combination with `--wrap-mode=nodownload` will only work |
| if the dependency has already been downloaded. |
| |
| This is useful when your project has many fallback dependencies, |
| but you only want to build against the library sources for a few |
| of them. |
| |
| **Warning**: This could lead to mixing system and subproject version of the |
| same library in the same process. Take this case as example: |
| - Libraries `glib-2.0` and `gstreamer-1.0` are installed on your system. |
| - `gstreamer-1.0` depends on `glib-2.0`, pkg-config file `gstreamer-1.0.pc` |
| has `Requires: glib-2.0`. |
| - In your application build definition you do: |
| ```meson |
| executable('app', ..., |
| dependencies: [ |
| dependency('glib-2.0', fallback: 'glib'), |
| dependency('gstreamer-1.0', fallback: 'gstreamer')], |
| ) |
| ``` |
| - You configure with `--force-fallback-for=glib`. |
| This result in linking to two different versions of library `glib-2.0` |
| because `dependency('glib-2.0', fallback: 'glib')` will return the |
| subproject dependency, but `dependency('gstreamer-1.0', fallback: 'gstreamer')` |
| will not fallback and return the system dependency, including `glib-2.0` |
| library. To avoid that situation, every dependency that itself depend on |
| `glib-2.0` must also be forced to fallback, in this case with |
| `--force-fallback-for=glib,gsteamer`. |
| |
| * **--wrap-mode=nopromote** |
| |
| *Since 0.56.0* Meson will automatically use wrap files found in subprojects |
| and copy them into the main project. That new behavior can be disabled by |
| passing `--wrap-mode=nopromote`. In that case only wraps found in the main |
| project will be used. |
| |
| ## `meson subprojects` command |
| |
| *Since 0.49.0* |
| |
| `meson subprojects` has various subcommands to manage all subprojects. |
| If the subcommand fails on any subproject the execution continues with |
| other subprojects. All subcommands accept `--sourcedir` argument |
| pointing to the root source dir of the main project. |
| |
| *Since 0.56.0* all subcommands accept `--types <file|git|hg|svn>` |
| argument to run the subcommands only on subprojects of the given |
| types. Multiple types can be set as comma separated list e.g. `--types |
| git,file`. |
| |
| *Since 0.56.0* If the subcommand fails on any subproject an error code |
| is returned at the end instead of retuning success. |
| |
| ### Download subprojects |
| |
| *Since 0.49.0* |
| |
| Meson will automatically download needed subprojects during configure, |
| unless **--wrap-mode=nodownload** option is passed. It is sometimes |
| preferable to download all subprojects in advance, so the Meson |
| configure can be performed offline. The command-line `meson |
| subprojects download` can be used for that, it will download all |
| missing subprojects, but will not update already fetched subprojects. |
| |
| ### Update subprojects |
| |
| *Since 0.49.0* |
| |
| Once a subproject has been fetched, Meson will not update it automatically. |
| For example if the wrap file tracks a git branch, it won't pull latest commits. |
| |
| To pull latest version of all your subprojects at once, just run the command: |
| `meson subprojects update`. |
| - If the wrap file comes from wrapdb, the latest version of the wrap file will |
| be pulled and used next time meson reconfigure the project. This can be |
| triggered using `meson --reconfigure`. Previous source tree is not deleted, to |
| prevent from any loss of local changes. *Since 0.58.0* If `--reset` is |
| specified, the source tree is deleted and new source is extracted. |
| - If subproject is currently in detached mode, a checkout of the revision from |
| wrap file is performed. *Since 0.56.0* a rebase is also performed in case the |
| revision already existed locally but was outdated. If `--reset` is specified, |
| a hard reset is performed instead of rebase. |
| - If subproject is currently at the same branch as specified by the wrap file, |
| a rebase on `origin` commit is performed. *Since 0.56.0* If `--reset` is |
| specified, a hard reset is performed instead of rebase. |
| - If subproject is currently in a different branch as specified by the wrap file, |
| it is skipped unless `--rebase` option is passed in which case a rebase on |
| `origin` commit is performed. *Since 0.56.0* the `--rebase` argument is |
| deprecated and has no effect. Instead, a checkout of the revision from wrap file |
| file is performed and a rebase is also performed in case the revision already |
| existed locally by was outdated. If `--reset` is specified, a hard reset is |
| performed instead of rebase. |
| - *Since 0.56.0* if the `url` specified in wrap file is different to the URL set |
| on `origin` for a git repository it will not be updated, unless `--reset` is |
| specified in which case the URL of `origin` will be reset first. |
| - *Since 0.56.0* If the subproject directory is not a git repository but has a |
| `[wrap-git]` the subproject is ignored, unless `--reset` is specified in which |
| case the directory is deleted and the new repository is cloned. |
| |
| ### Start a topic branch across all git subprojects |
| |
| *Since 0.49.0* |
| |
| The command-line `meson subprojects checkout <branch_name>` will |
| checkout a branch, or create one with `-b` argument, in every git |
| subprojects. This is useful when starting local changes across |
| multiple subprojects. It is still your responsibility to commit and |
| push in each repository where you made local changes. |
| |
| To come back to the revision set in wrap file (i.e. master), just run |
| `meson subprojects checkout` with no branch name. |
| |
| *Since 0.56.0* any pending changes are now stashed before checkout a new branch. |
| |
| ### Execute a command on all subprojects |
| |
| *Since 0.51.0* |
| |
| The command-line `meson subprojects foreach <command> [...]` will |
| execute a command in each subproject directory. For example this can |
| be useful to check the status of subprojects (e.g. with `git status` |
| or `git diff`) before performing other actions on them. |
| |
| ## 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. |