aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2020-10-08 12:05:51 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2020-10-08 12:24:07 +0200
commit726b82205492a9e1f2dfd0fba96b237b51eeb428 (patch)
treedf49508fe8547d69b232e90fa2cf6fc17dcc8b2b
parent1eec5cf41f905c988af4be003a03d29fca7baef4 (diff)
downloadmeson-726b82205492a9e1f2dfd0fba96b237b51eeb428.zip
meson-726b82205492a9e1f2dfd0fba96b237b51eeb428.tar.gz
meson-726b82205492a9e1f2dfd0fba96b237b51eeb428.tar.bz2
dependency: support boolean argument "allow_fallback"
Sometimes, distros want to configure a project so that it does not use any bundled library. In this case, meson.build might want to do something like this, where slirp is a combo option with values auto/system/internal: slirp = dependency('', required: false) if get_option('slirp') != 'internal' slirp = dependency('slirp', required: get_option('slirp') == 'system') endif if not slirp.found() slirp = subproject('libslirp', ...) .variable('...') endif and we cannot use "fallback" because the "system" value should never look for a subproject. This worked until 0.54.x, but in 0.55.x this breaks because of the automatic subproject search. Note that the desired effect here is backwards compared to the policy of doing an automatic search on "required: true"; we only want to do the search if "required" is false! It would be possible to look for the dependency with `required: false` and issue the error manually, but it's ugly and it may produce an error message that looks "different" from Meson's. Instead, with this change it is possible to achieve this effect in an even simpler way: slirp = dependency('slirp', required: get_option('slirp') != 'auto', allow_fallback: get_option('slirp') == 'system' ? false : ['slirp', 'libslirp_dep']) The patch also adds support for "allow_fallback: true", which is simple and enables automatic fallback to a wrap even for non-required dependencies.
-rw-r--r--docs/markdown/Reference-manual.md17
-rw-r--r--docs/markdown/Wrap-dependency-system-manual.md10
-rw-r--r--docs/markdown/snippets/fallback_bool.md8
-rw-r--r--mesonbuild/dependencies/base.py6
-rw-r--r--mesonbuild/interpreter.py15
-rw-r--r--test cases/common/239 dependency allow_fallback/meson.build12
-rw-r--r--test cases/common/239 dependency allow_fallback/subprojects/foob/meson.build2
-rw-r--r--test cases/common/239 dependency allow_fallback/subprojects/foob3/meson.build2
-rw-r--r--test cases/failing/110 no fallback/meson.build2
-rw-r--r--test cases/failing/110 no fallback/subprojects/foob/meson.build2
-rw-r--r--test cases/failing/110 no fallback/test.json8
11 files changed, 71 insertions, 13 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index b6ca743..38ae558 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -454,15 +454,15 @@ Dependencies can also be resolved in two other ways:
* by a fallback subproject which, if needed, will be brought into the current
build specification as if [`subproject()`](#subproject) had been called.
The subproject can be specified with the `fallback` argument. Alternatively,
- if the `fallback` argument is absent and `required` is `true` or
- [`enabled`](Build-options.md#features), *since 0.55.0* Meson will
+ if the `fallback` argument is absent, *since 0.55.0* Meson can
automatically identify a subproject as a fallback if a wrap file
[provides](Wrap-dependency-system-manual.md#provide-section) the
dependency, or if a subproject has the same name as the dependency.
In the latter case, the subproject must use `meson.override_dependency` to
specify the replacement, or Meson will report a hard error. See the
[Wrap documentation](Wrap-dependency-system-manual.md#provide-section)
- for more details.
+ for more details. This automatic search can be controlled using the
+ `allow_fallback` keyword argument.
This function supports the following keyword arguments:
@@ -471,7 +471,16 @@ This function supports the following keyword arguments:
(like `default_options` in [`project()`](#project), they only have
effect when Meson is run for the first time, and command line
arguments override any default options in build files)
-- `fallback`: manually specifies a subproject
+- `allow_fallback` (boolean argument, *since 0.56.0*): specifies whether Meson
+ should automatically pick a fallback subproject in case the dependency
+ is not found in the system. If `true` and the dependency is not found
+ on the system, Meson will fallback to a subproject that provides this
+ dependency. If `false`, Meson will not fallback even if a subproject
+ provides this dependency. By default, Meson will do so if `required`
+ is `true` or [`enabled`](Build-options.md#features); see the [Wrap
+ documentation](Wrap-dependency-system-manual.md#provide-section)
+ for more details.
+- `fallback` (string or array argument): manually specifies a subproject
fallback to use in case the dependency is not found in the system.
This is useful if the automatic search is not applicable or if you
want to support versions of Meson older than 0.55.0. If the value is an
diff --git a/docs/markdown/Wrap-dependency-system-manual.md b/docs/markdown/Wrap-dependency-system-manual.md
index 8e6282e..4189709 100644
--- a/docs/markdown/Wrap-dependency-system-manual.md
+++ b/docs/markdown/Wrap-dependency-system-manual.md
@@ -182,10 +182,12 @@ endif
`dependency('foo-1.0', required: get_option('foo_opt'))` will only fallback
when the user sets `foo_opt` to `enabled` instead of `auto`.
-If it is desired to fallback for an optional dependency, the `fallback` keyword
-argument must be passed explicitly. For example
-`dependency('foo-1.0', required: get_option('foo_opt'), fallback: 'foo')` will
-use the fallback even when `foo_opt` is set to `auto`.
+If it is desired to fallback for an optional dependency, the `fallback`
+or `allow_fallback` keyword arguments must be passed explicitly. *Since
+0.56.0*, `dependency('foo-1.0', required: get_option('foo_opt'),
+allow_fallback: true)` will use the fallback even when `foo_opt` is set
+to `auto`. On version *0.55.0* the same effect could be achieved with
+`dependency('foo-1.0', required: get_option('foo_opt'), fallback: 'foo')`.
This mechanism assumes the subproject calls `meson.override_dependency('foo-1.0', foo_dep)`
so Meson knows which dependency object should be used as fallback. Since that
diff --git a/docs/markdown/snippets/fallback_bool.md b/docs/markdown/snippets/fallback_bool.md
new file mode 100644
index 0000000..14bef50
--- /dev/null
+++ b/docs/markdown/snippets/fallback_bool.md
@@ -0,0 +1,8 @@
+## Controlling subproject dependencies with `dependency(allow_fallback: ...)`
+
+As an alternative to the `fallback` keyword argument to `dependency`,
+you may use `allow_fallback`, which accepts a boolean value. If `true`
+and the dependency is not found on the system, Meson will fallback
+to a subproject that provides this dependency, even if the dependency
+is optional. If `false`, Meson will not fallback even if a subproject
+provides this dependency.
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 7c64b9c..95202fe 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -2320,9 +2320,11 @@ def get_dep_identifier(name, kwargs) -> T.Tuple:
# 'version' is irrelevant for caching; the caller must check version matches
# 'native' is handled above with `for_machine`
# 'required' is irrelevant for caching; the caller handles it separately
- # 'fallback' subprojects cannot be cached -- they must be initialized
+ # 'fallback' and 'allow_fallback' is not part of the cache because,
+ # once a dependency has been found through a fallback, it should
+ # be used for the rest of the Meson run.
# 'default_options' is only used in fallback case
- if key in ('version', 'native', 'required', 'fallback', 'default_options'):
+ if key in ('version', 'native', 'required', 'fallback', 'allow_fallback', 'default_options'):
continue
# All keyword arguments are strings, ints, or lists (or lists of lists)
if isinstance(value, list):
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 07cf1e2..ca1411e 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -3707,21 +3707,30 @@ external dependencies (including libraries) must go to "dependencies".''')
return self.notfound_dependency()
fallback = kwargs.get('fallback', None)
+ allow_fallback = kwargs.get('allow_fallback', None)
+ if allow_fallback is not None:
+ FeatureNew.single_use('"allow_fallback" keyword argument for dependency', '0.56.0', self.subproject)
+ if fallback is not None:
+ raise InvalidArguments('"fallback" and "allow_fallback" arguments are mutually exclusive')
+ if not isinstance(allow_fallback, bool):
+ raise InvalidArguments('"allow_fallback" argument must be boolean')
# If "fallback" is absent, look for an implicit fallback.
- if name and fallback is None:
+ if name and fallback is None and allow_fallback is not False:
# Add an implicit fallback if we have a wrap file or a directory with the same name,
# but only if this dependency is required. It is common to first check for a pkg-config,
# then fallback to use find_library() and only afterward check again the dependency
# with a fallback. If the fallback has already been configured then we have to use it
# even if the dependency is not required.
provider = self.environment.wrap_resolver.find_dep_provider(name)
+ if not provider and allow_fallback is True:
+ raise InvalidArguments('Fallback wrap or subproject not found for dependency \'%s\'' % name)
dirname = mesonlib.listify(provider)[0]
- if provider and (required or self.get_subproject(dirname)):
+ if provider and (allow_fallback is True or required or self.get_subproject(dirname)):
fallback = provider
if 'default_options' in kwargs and not fallback:
- mlog.warning('The "default_options" keyworg argument does nothing without a "fallback" keyword argument.',
+ mlog.warning('The "default_options" keyword argument does nothing without a fallback subproject.',
location=self.current_node)
# writing just "dependency('')" is an error, because it can only fail
diff --git a/test cases/common/239 dependency allow_fallback/meson.build b/test cases/common/239 dependency allow_fallback/meson.build
new file mode 100644
index 0000000..b189faf
--- /dev/null
+++ b/test cases/common/239 dependency allow_fallback/meson.build
@@ -0,0 +1,12 @@
+project('subproject fallback', 'c')
+
+foob_dep = dependency('foob', allow_fallback: true, required: false)
+assert(foob_dep.found())
+
+# Careful! Once a submodule has been triggered and it has
+# overridden the dependency, it sticks.
+foob_dep = dependency('foob', allow_fallback: false, required: false)
+assert(foob_dep.found())
+
+foob3_dep = dependency('foob3', allow_fallback: false, required: false)
+assert(not foob3_dep.found())
diff --git a/test cases/common/239 dependency allow_fallback/subprojects/foob/meson.build b/test cases/common/239 dependency allow_fallback/subprojects/foob/meson.build
new file mode 100644
index 0000000..b2c4814
--- /dev/null
+++ b/test cases/common/239 dependency allow_fallback/subprojects/foob/meson.build
@@ -0,0 +1,2 @@
+project('foob', 'c')
+meson.override_dependency('foob', declare_dependency())
diff --git a/test cases/common/239 dependency allow_fallback/subprojects/foob3/meson.build b/test cases/common/239 dependency allow_fallback/subprojects/foob3/meson.build
new file mode 100644
index 0000000..9fdb188
--- /dev/null
+++ b/test cases/common/239 dependency allow_fallback/subprojects/foob3/meson.build
@@ -0,0 +1,2 @@
+project('foob3', 'c')
+# Note that there is no override_dependency here
diff --git a/test cases/failing/110 no fallback/meson.build b/test cases/failing/110 no fallback/meson.build
new file mode 100644
index 0000000..0101bb8
--- /dev/null
+++ b/test cases/failing/110 no fallback/meson.build
@@ -0,0 +1,2 @@
+project('no fallback', 'c')
+foob_dep = dependency('foob', allow_fallback: false, required: true)
diff --git a/test cases/failing/110 no fallback/subprojects/foob/meson.build b/test cases/failing/110 no fallback/subprojects/foob/meson.build
new file mode 100644
index 0000000..b2c4814
--- /dev/null
+++ b/test cases/failing/110 no fallback/subprojects/foob/meson.build
@@ -0,0 +1,2 @@
+project('foob', 'c')
+meson.override_dependency('foob', declare_dependency())
diff --git a/test cases/failing/110 no fallback/test.json b/test cases/failing/110 no fallback/test.json
new file mode 100644
index 0000000..e034061
--- /dev/null
+++ b/test cases/failing/110 no fallback/test.json
@@ -0,0 +1,8 @@
+{
+ "stdout": [
+ {
+ "match": "re",
+ "line": ".*/meson\\.build:2:0: ERROR: (Pkg-config binary for machine MachineChoice\\.HOST not found\\. Giving up\\.|Dependency \"foob\" not found, tried .*)"
+ }
+ ]
+}