diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2020-03-07 21:04:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-07 21:04:29 +0200 |
commit | 18f5a197da982ec48473903c0e2defd2d7797eb2 (patch) | |
tree | b70a675ff658de8d4966bc013ff4555197830ab8 | |
parent | a0ce13d4e9bb066da4fe961215dee89019026bff (diff) | |
parent | 823c83b2696b517289dbfa0f524fd938bc4001e2 (diff) | |
download | meson-18f5a197da982ec48473903c0e2defd2d7797eb2.zip meson-18f5a197da982ec48473903c0e2defd2d7797eb2.tar.gz meson-18f5a197da982ec48473903c0e2defd2d7797eb2.tar.bz2 |
Merge pull request #6203 from xclaesse/override-dependency
Add meson.override_dependency()
15 files changed, 276 insertions, 43 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index e43ef57..9bb7911 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -445,6 +445,10 @@ arguments: [`dependency()`](#dependency), etc. Note that this means the fallback dependency may be a not-found dependency, in which case the value of the `required:` kwarg will be obeyed. + *Since 0.54.0* `'subproj_dep'` argument can be omitted in the case the + subproject used `meson.override_dependency('dependency_name', subproj_dep)`. + In that case, the `fallback` keyword argument can be a single string instead + of a list of 2 strings. - `language` *(added 0.42.0)* defines what language-specific dependency to find if it's available for multiple languages. - `method` defines the way the dependency is detected, the default is @@ -1825,12 +1829,21 @@ the following methods. - `override_find_program(progname, program)` [*(Added 0.46.0)*](Release-notes-for-0.46.0.md#can-override-find_program) specifies that whenever `find_program` is used to find a program - named `progname`, Meson should not not look it up on the system but + named `progname`, Meson should not look it up on the system but instead return `program`, which may either be the result of `find_program`, `configure_file` or `executable`. If `program` is an `executable`, it cannot be used during configure. +- `override_dependency(name, dep_object)` [*(Added + 0.54.0)*](Release-notes-for-0.54.0.md#override-dependency) + specifies that whenever `dependency(name, ...)` is used, Meson should not + look it up on the system but instead return `dep_object`, which may either be + the result of `dependency()` or `declare_dependency()`. It takes optional + `native` keyword arguments. Doing this in a subproject allows the parent + project to retrieve the dependency without having to know the dependency + variable name: `dependency(name, fallback : subproject_name)`. + - `project_version()` returns the version string specified in `project` function call. diff --git a/docs/markdown/snippets/override_dependency.md b/docs/markdown/snippets/override_dependency.md new file mode 100644 index 0000000..ca420bc --- /dev/null +++ b/docs/markdown/snippets/override_dependency.md @@ -0,0 +1,65 @@ +## `dependency()` consistency + +The first time a dependency is found, using `dependency('foo', ...)`, the return +value is now cached. Any subsequent call will return the same value as long as +version requested match, otherwise not-found dependency is returned. This means +that if a system dependency is first found, it won't fallback to a subproject +in a subsequent call any more and will rather return not-found instead if the +system version does not match. Similarly, if the first call returns the subproject +fallback dependency, it will also return the subproject dependency in a subsequent +call even if no fallback is provided. + +For example, if the system has `foo` version 1.0: +```meson +# d2 is set to foo_dep and not the system dependency, even without fallback argument. +d1 = dependency('foo', version : '>=2.0', required : false, + fallback : ['foo', 'foo_dep']) +d2 = dependency('foo', version : '>=1.0', required : false) +``` +```meson +# d2 is not-found because the first call returned the system dependency, but its version is too old for 2nd call. +d1 = dependency('foo', version : '>=1.0', required : false) +d2 = dependency('foo', version : '>=2.0', required : false, + fallback : ['foo', 'foo_dep']) +``` + +## Override `dependency()` + +It is now possible to override the result of `dependency()` to point +to any dependency object you want. The overriding is global and applies to +every subproject from there on. + +For example, this subproject provides 2 libraries with version 2.0: + +```meson +project(..., version : '2.0') + +libfoo = library('foo', ...) +foo_dep = declare_dependency(link_with : libfoo) +meson.override_dependency('foo', foo_dep) + +libbar = library('bar', ...) +bar_dep = declare_dependency(link_with : libbar) +meson.override_dependency('bar', bar_dep) +``` + +Assuming the system has `foo` and `bar` 1.0 installed, and master project does this: +```meson +foo_dep = dependency('foo', version : '>=2.0', fallback : ['foo', 'foo_dep']) +bar_dep = dependency('bar') +``` + +This used to mix system 1.0 version and subproject 2.0 dependencies, but thanks +to the override `bar_dep` is now set to the subproject's version instead. + +Another case this can be useful is to force a subproject to use a specific dependency. +If the subproject does `dependency('foo')` but the main project wants to provide +its own implementation of `foo`, it can for example call +`meson.override_dependency('foo', declare_dependency(...))` before configuring the +subproject. + +## Simplified `dependency()` fallback + +In the case a subproject `foo` calls `meson.override_dependency('foo-2.0', foo_dep)`, +the parent project can omit the dependency variable name in fallback keyword +argument: `dependency('foo-2.0', fallback : 'foo')`. diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 48d21b1..2b5c0ea 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -106,6 +106,12 @@ def get_target_macos_dylib_install_name(ld) -> str: class InvalidArguments(MesonException): pass +class DependencyOverride: + def __init__(self, dep, node, explicit=True): + self.dep = dep + self.node = node + self.explicit = explicit + class Build: """A class that holds the status of one build including all dependencies and so on. @@ -141,6 +147,7 @@ class Build: self.test_setup_default_name = None self.find_overrides = {} self.searched_programs = set() # The list of all programs that have been searched for. + self.dependency_overrides = PerMachine({}, {}) def copy(self): other = Build(self.environment) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 9e88975..77d64c4 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1857,6 +1857,7 @@ class MesonMain(InterpreterObject): 'add_postconf_script': self.add_postconf_script_method, 'add_dist_script': self.add_dist_script_method, 'install_dependency_manifest': self.install_dependency_manifest_method, + 'override_dependency': self.override_dependency_method, 'override_find_program': self.override_find_program_method, 'project_version': self.project_version_method, 'project_license': self.project_license_method, @@ -2013,6 +2014,29 @@ class MesonMain(InterpreterObject): raise InterpreterException('Second argument must be an external program or executable.') self.interpreter.add_find_program_override(name, exe) + @FeatureNew('meson.override_dependency', '0.53.0') + @permittedKwargs({'native'}) + def override_dependency_method(self, args, kwargs): + if len(args) != 2: + raise InterpreterException('Override needs two arguments') + name = args[0] + dep = args[1] + if not isinstance(name, str) or not name: + raise InterpreterException('First argument must be a string and cannot be empty') + if hasattr(dep, 'held_object'): + dep = dep.held_object + if not isinstance(dep, dependencies.Dependency): + raise InterpreterException('Second argument must be a dependency object') + identifier = dependencies.get_dep_identifier(name, kwargs) + for_machine = self.interpreter.machine_from_native_kwarg(kwargs) + override = self.build.dependency_overrides[for_machine].get(identifier) + if override: + m = 'Tried to override dependency {!r} which has already been resolved or overridden at {}' + location = mlog.get_error_location_string(override.node.filename, override.node.lineno) + raise InterpreterException(m.format(name, location)) + self.build.dependency_overrides[for_machine][identifier] = \ + build.DependencyOverride(dep, self.interpreter.current_node) + @noPosargs @permittedKwargs({}) def project_version_method(self, args, kwargs): @@ -3218,30 +3242,47 @@ external dependencies (including libraries) must go to "dependencies".''') # Check if we want this as a build-time / build machine or runt-time / # host machine dep. for_machine = self.machine_from_native_kwarg(kwargs) - identifier = dependencies.get_dep_identifier(name, kwargs) - cached_dep = self.coredata.deps[for_machine].get(identifier) - if cached_dep: + wanted_vers = mesonlib.stringlistify(kwargs.get('version', [])) + + override = self.build.dependency_overrides[for_machine].get(identifier) + if override: + info = [mlog.blue('(overridden)' if override.explicit else '(cached)')] + cached_dep = override.dep + # We don't implicitly override not-found dependencies, but user could + # have explicitly called meson.override_dependency() with a not-found + # dep. if not cached_dep.found(): mlog.log('Dependency', mlog.bold(name), - 'found:', mlog.red('NO'), mlog.blue('(cached)')) + 'found:', mlog.red('NO'), *info) return identifier, cached_dep - - # Verify the cached dep version match - wanted_vers = mesonlib.stringlistify(kwargs.get('version', [])) found_vers = cached_dep.get_version() - if not wanted_vers or mesonlib.version_compare_many(found_vers, wanted_vers)[0]: - info = [mlog.blue('(cached)')] - if found_vers: - info = [mlog.normal_cyan(found_vers), *info] + if not self.check_version(wanted_vers, found_vers): mlog.log('Dependency', mlog.bold(name), - 'found:', mlog.green('YES'), *info) - return identifier, cached_dep + 'found:', mlog.red('NO'), + 'found', mlog.normal_cyan(found_vers), 'but need:', + mlog.bold(', '.join(["'{}'".format(e) for e in wanted_vers])), + *info) + return identifier, NotFoundDependency(self.environment) + else: + info = [mlog.blue('(cached)')] + cached_dep = self.coredata.deps[for_machine].get(identifier) + if cached_dep: + found_vers = cached_dep.get_version() + if not self.check_version(wanted_vers, found_vers): + return identifier, None + + if cached_dep: + if found_vers: + info = [mlog.normal_cyan(found_vers), *info] + mlog.log('Dependency', mlog.bold(name), + 'found:', mlog.green('YES'), *info) + return identifier, cached_dep return identifier, None @staticmethod - def check_subproject_version(wanted, found): + def check_version(wanted, found): if not wanted: return True if found == 'undefined' or not mesonlib.version_compare_many(found, wanted)[0]: @@ -3251,11 +3292,35 @@ external dependencies (including libraries) must go to "dependencies".''') def notfound_dependency(self): return DependencyHolder(NotFoundDependency(self.environment), self.subproject) - def get_subproject_dep(self, display_name, dirname, varname, kwargs): + def verify_fallback_consistency(self, dirname, varname, cached_dep): + subi = self.subprojects.get(dirname) + if not cached_dep or not varname or not subi or not cached_dep.found(): + return + dep = subi.get_variable_method([varname], {}) + if dep.held_object != cached_dep: + m = 'Inconsistency: Subproject has overriden the dependency with another variable than {!r}' + raise DependencyException(m.format(varname)) + + def get_subproject_dep(self, name, display_name, dirname, varname, kwargs): + required = kwargs.get('required', True) + wanted = mesonlib.stringlistify(kwargs.get('version', [])) + subproj_path = os.path.join(self.subproject_dir, dirname) dep = self.notfound_dependency() try: subproject = self.subprojects[dirname] + _, cached_dep = self._find_cached_dep(name, kwargs) + if varname is None: + # Assuming the subproject overriden the dependency we want + if cached_dep: + if required and not cached_dep.found(): + m = 'Dependency {!r} is not satisfied' + raise DependencyException(m.format(display_name)) + return DependencyHolder(cached_dep, self.subproject) + else: + m = 'Subproject {} did not override dependency {}' + raise DependencyException(m.format(subproj_path, display_name)) if subproject.found(): + self.verify_fallback_consistency(dirname, varname, cached_dep) dep = self.subprojects[dirname].get_variable_method([varname], {}) except InvalidArguments: pass @@ -3264,10 +3329,6 @@ external dependencies (including libraries) must go to "dependencies".''') raise InvalidCode('Fetched variable {!r} in the subproject {!r} is ' 'not a dependency object.'.format(varname, dirname)) - required = kwargs.get('required', True) - wanted = mesonlib.stringlistify(kwargs.get('version', [])) - subproj_path = os.path.join(self.subproject_dir, dirname) - if not dep.found(): if required: raise DependencyException('Could not find dependency {} in subproject {}' @@ -3278,7 +3339,7 @@ external dependencies (including libraries) must go to "dependencies".''') return dep found = dep.held_object.get_version() - if not self.check_subproject_version(wanted, found): + if not self.check_version(wanted, found): if required: raise DependencyException('Version {} of subproject dependency {} already ' 'cached, requested incompatible version {} for ' @@ -3330,6 +3391,15 @@ external dependencies (including libraries) must go to "dependencies".''') raise if not d.found() and not_found_message: self.message_impl([not_found_message]) + self.message_impl([not_found_message]) + # Override this dependency to have consistent results in subsequent + # dependency lookups. + if name and d.found(): + for_machine = self.machine_from_native_kwarg(kwargs) + identifier = dependencies.get_dep_identifier(name, kwargs) + if identifier not in self.build.dependency_overrides[for_machine]: + self.build.dependency_overrides[for_machine][identifier] = \ + build.DependencyOverride(d.held_object, node, explicit=False) return d def dependency_impl(self, name, display_name, kwargs): @@ -3353,6 +3423,9 @@ external dependencies (including libraries) must go to "dependencies".''') identifier, cached_dep = self._find_cached_dep(name, kwargs) if cached_dep: + if has_fallback: + dirname, varname = self.get_subproject_infos(kwargs) + self.verify_fallback_consistency(dirname, varname, cached_dep) if required and not cached_dep.found(): m = 'Dependency {!r} was already checked and was not found' raise DependencyException(m.format(display_name)) @@ -3363,7 +3436,7 @@ external dependencies (including libraries) must go to "dependencies".''') if has_fallback: dirname, varname = self.get_subproject_infos(kwargs) if dirname in self.subprojects: - return self.get_subproject_dep(name, dirname, varname, kwargs) + return self.get_subproject_dep(name, display_name, dirname, varname, kwargs) wrap_mode = self.coredata.get_builtin_option('wrap_mode') forcefallback = wrap_mode == WrapMode.forcefallback and has_fallback @@ -3371,7 +3444,6 @@ external dependencies (including libraries) must go to "dependencies".''') self._handle_featurenew_dependencies(name) kwargs['required'] = required and not has_fallback dep = dependencies.find_external_dependency(name, self.environment, kwargs) - kwargs['required'] = required # Only store found-deps in the cache # Never add fallback deps to self.coredata.deps since we @@ -3383,7 +3455,7 @@ external dependencies (including libraries) must go to "dependencies".''') return DependencyHolder(dep, self.subproject) if has_fallback: - return self.dependency_fallback(display_name, kwargs) + return self.dependency_fallback(name, display_name, kwargs) return self.notfound_dependency() @@ -3411,13 +3483,15 @@ external dependencies (including libraries) must go to "dependencies".''') mlog.warning(*message, location=self.current_node) def get_subproject_infos(self, kwargs): - fbinfo = kwargs['fallback'] - check_stringlist(fbinfo) - if len(fbinfo) != 2: - raise InterpreterException('Fallback info must have exactly two items.') + fbinfo = mesonlib.stringlistify(kwargs['fallback']) + if len(fbinfo) == 1: + FeatureNew('Fallback without variable name', '0.53.0').use(self.subproject) + return fbinfo[0], None + elif len(fbinfo) != 2: + raise InterpreterException('Fallback info must have one or two items.') return fbinfo - def dependency_fallback(self, display_name, kwargs): + def dependency_fallback(self, name, display_name, kwargs): required = kwargs.get('required', True) if self.coredata.get_builtin_option('wrap_mode') == WrapMode.nofallback: mlog.log('Not looking for a fallback subproject for the dependency', @@ -3439,7 +3513,7 @@ external dependencies (including libraries) must go to "dependencies".''') 'required': required, } self.do_subproject(dirname, 'meson', sp_kwargs) - return self.get_subproject_dep(display_name, dirname, varname, kwargs) + return self.get_subproject_dep(name, display_name, dirname, varname, kwargs) @FeatureNewKwargs('executable', '0.42.0', ['implib']) @permittedKwargs(permitted_kwargs['executable']) diff --git a/run_unittests.py b/run_unittests.py index 658da37..9ebece6 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -3980,11 +3980,17 @@ recommended as it is not supported on some platforms''') { 'descriptive_name': 'sub', 'name': 'sub', - 'version': 'undefined' - } + 'version': '1.0' + }, + { + 'descriptive_name': 'sub-novar', + 'name': 'sub_novar', + 'version': '1.0', + }, ] } - self.assertDictEqual(res, expected) + res['subprojects'] = sorted(res['subprojects'], key=lambda i: i['name']) + self.assertDictEqual(expected, res) def test_introspection_target_subproject(self): testdir = os.path.join(self.common_test_dir, '45 subproject') @@ -4555,7 +4561,7 @@ class FailureTests(BasePlatformTests): raise unittest.SkipTest('zlib not found with pkg-config') a = (("dependency('zlib', method : 'fail')", "'fail' is invalid"), ("dependency('zlib', static : '1')", "[Ss]tatic.*boolean"), - ("dependency('zlib', version : 1)", "[Vv]ersion.*string or list"), + ("dependency('zlib', version : 1)", "Item must be a list or one of <class 'str'>"), ("dependency('zlib', required : 1)", "[Rr]equired.*boolean"), ("dependency('zlib', method : 1)", "[Mm]ethod.*string"), ("dependency('zlibfail')", self.dnf),) @@ -4772,6 +4778,17 @@ class FailureTests(BasePlatformTests): self.assertMesonOutputs("warning('Array:', ['a', 'b'])", r"WARNING:.* Array: \['a', 'b'\]") + def test_override_dependency_twice(self): + self.assertMesonRaises("meson.override_dependency('foo', declare_dependency())\n" + + "meson.override_dependency('foo', declare_dependency())", + """Tried to override dependency 'foo' which has already been resolved or overridden""") + + @unittest.skipIf(is_windows(), 'zlib is not available on Windows') + def test_override_resolved_dependency(self): + self.assertMesonRaises("dependency('zlib')\n" + + "meson.override_dependency('zlib', declare_dependency())", + """Tried to override dependency 'zlib' which has already been resolved or overridden""") + @unittest.skipUnless(is_windows() or is_cygwin(), "requires Windows (or Windows via Cygwin)") class WindowsTests(BasePlatformTests): ''' diff --git a/test cases/common/102 subproject subdir/meson.build b/test cases/common/102 subproject subdir/meson.build index ec9fad1..8299a37 100644 --- a/test cases/common/102 subproject subdir/meson.build +++ b/test cases/common/102 subproject subdir/meson.build @@ -4,3 +4,24 @@ libSub = dependency('sub', fallback: ['sub', 'libSub']) exe = executable('prog', 'prog.c', dependencies: libSub) test('subproject subdir', exe) + +# Verify the subproject has placed dependency override. +dependency('sub-1.0') + +# Verify we can now take 'sub' dependency without fallback, but only version 1.0. +dependency('sub') +d = dependency('sub', version : '>=2.0', required : false) +assert(not d.found(), 'version should not match') + +# Verify that not-found does not get cached, we can still fallback afterward. +dependency('sub2', required : false) +d = dependency('sub2', fallback: ['sub', 'libSub']) +assert(d.found(), 'Should fallback even if a previous call returned not-found') + +# Verify we can get a fallback dependency without specifying the variable name, +# because the subproject overridden 'sub-novar'. +dependency('sub-novar', fallback : 'sub_novar') + +# Verify a subproject can force a dependency to be not-found +d = dependency('sub-notfound', fallback : 'sub_novar', required : false) +assert(not d.found(), 'Dependency should be not-found') diff --git a/test cases/common/102 subproject subdir/subprojects/sub/lib/meson.build b/test cases/common/102 subproject subdir/subprojects/sub/lib/meson.build index 731d22b..53233ab 100644 --- a/test cases/common/102 subproject subdir/subprojects/sub/lib/meson.build +++ b/test cases/common/102 subproject subdir/subprojects/sub/lib/meson.build @@ -1,2 +1,3 @@ lib = static_library('sub', 'sub.c') libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib) +meson.override_dependency('sub-1.0', libSub) diff --git a/test cases/common/102 subproject subdir/subprojects/sub/meson.build b/test cases/common/102 subproject subdir/subprojects/sub/meson.build index bf69c25..d8c4dce 100644 --- a/test cases/common/102 subproject subdir/subprojects/sub/meson.build +++ b/test cases/common/102 subproject subdir/subprojects/sub/meson.build @@ -1,2 +1,2 @@ -project('sub', 'c') +project('sub', 'c', version : '1.0') subdir('lib') diff --git a/test cases/common/102 subproject subdir/subprojects/sub_novar/meson.build b/test cases/common/102 subproject subdir/subprojects/sub_novar/meson.build new file mode 100644 index 0000000..6450a10 --- /dev/null +++ b/test cases/common/102 subproject subdir/subprojects/sub_novar/meson.build @@ -0,0 +1,4 @@ +project('sub-novar', 'c', version : '1.0') + +meson.override_dependency('sub-novar', declare_dependency()) +meson.override_dependency('sub-notfound', dependency('', required : false)) diff --git a/test cases/failing/100 fallback consistency/meson.build b/test cases/failing/100 fallback consistency/meson.build new file mode 100644 index 0000000..ad2b226 --- /dev/null +++ b/test cases/failing/100 fallback consistency/meson.build @@ -0,0 +1,7 @@ +project('proj', 'c') + +# The first call succeed and cache the value of 'sub' dependency. The 2nd call +# should return the cached value, but still verify the fallback variable is +# consistent. +dependency('sub', fallback : ['sub', 'dep1']) +dependency('sub', fallback : ['sub', 'dep2']) diff --git a/test cases/failing/100 fallback consistency/subprojects/sub/meson.build b/test cases/failing/100 fallback consistency/subprojects/sub/meson.build new file mode 100644 index 0000000..12a6570 --- /dev/null +++ b/test cases/failing/100 fallback consistency/subprojects/sub/meson.build @@ -0,0 +1,5 @@ +project('proj', 'c') + +dep1 = declare_dependency() +dep2 = declare_dependency() +meson.override_dependency('sub', dep1) diff --git a/test cases/failing/99 fallback consistency/meson.build b/test cases/failing/99 fallback consistency/meson.build new file mode 100644 index 0000000..362459c --- /dev/null +++ b/test cases/failing/99 fallback consistency/meson.build @@ -0,0 +1,4 @@ +project('proj', 'c') + +# Subproject overrides 'sub' with another variable than dep2. This should fail. +dependency('sub', fallback : ['sub', 'dep2']) diff --git a/test cases/failing/99 fallback consistency/subprojects/sub/meson.build b/test cases/failing/99 fallback consistency/subprojects/sub/meson.build new file mode 100644 index 0000000..12a6570 --- /dev/null +++ b/test cases/failing/99 fallback consistency/subprojects/sub/meson.build @@ -0,0 +1,5 @@ +project('proj', 'c') + +dep1 = declare_dependency() +dep2 = declare_dependency() +meson.override_dependency('sub', dep1) diff --git a/test cases/linuxlike/5 dependency versions/meson.build b/test cases/linuxlike/5 dependency versions/meson.build index 087db5f..94f424d 100644 --- a/test cases/linuxlike/5 dependency versions/meson.build +++ b/test cases/linuxlike/5 dependency versions/meson.build @@ -38,32 +38,32 @@ somelibver = dependency('somelib', fallback : ['somelibnover', 'some_dep']) assert(somelibver.type_name() == 'internal', 'somelibver should be of type "internal", not ' + somelibver.type_name()) # Find an internal dependency again with the same name and a specific version -somelib = dependency('somelib', +somelib = dependency('somelib2', version : '== 0.1', fallback : ['somelib', 'some_dep']) # Find an internal dependency again even if required = false -somelib_reqfalse = dependency('somelib', +somelib_reqfalse = dependency('somelib3', required: false, fallback : ['somelib', 'some_dep']) assert(somelib_reqfalse.found(), 'somelib should have been found') # Find an internal dependency again with the same name and incompatible version -somelibver = dependency('somelib', +somelibver = dependency('somelib4', version : '>= 0.3', fallback : ['somelibver', 'some_dep']) # Find an internal dependency again with impossible multi-version -somelibver = dependency('somelib', +somelibver = dependency('somelib5', version : ['>= 0.3', '<0.3'], required : false, fallback : ['somelibver', 'some_dep']) assert(not somelibver.found(), 'Dependency should not be found') # Find somelib again, but with a fallback that will fail because subproject does not exist -somelibfail = dependency('somelib', +somelibfail = dependency('somelib6', version : '>= 0.2', required : false, fallback : ['somelibfail', 'some_dep']) assert(somelibfail.found() == false, 'somelibfail found via wrong fallback') # Find somelib again, but with a fallback that will fail because dependency does not exist -somefail_dep = dependency('somelib', +somefail_dep = dependency('somelib7', version : '>= 0.2', required : false, fallback : ['somelib', 'somefail_dep']) @@ -71,14 +71,21 @@ assert(somefail_dep.found() == false, 'somefail_dep found via wrong fallback') # Fallback should only be used if the primary was not found fallbackzlib_dep = dependency('zlib', - fallback : ['somelib', 'fakezlib_dep']) + fallback : ['fakezlib', 'fakezlib_dep']) assert(fallbackzlib_dep.type_name() == 'pkgconfig', 'fallbackzlib_dep should be of type "pkgconfig", not ' + fallbackzlib_dep.type_name()) # Check that the above dependency was pkgconfig because the fallback wasn't # checked, not because the fallback didn't work fakezlib_dep = dependency('fakezlib', - fallback : ['somelib', 'fakezlib_dep']) + fallback : ['fakezlib', 'fakezlib_dep']) assert(fakezlib_dep.type_name() == 'internal', 'fakezlib_dep should be of type "internal", not ' + fakezlib_dep.type_name()) +# Verify that once we got a system dependency, we won't fallback if a newer +# version is requested. +d = dependency('zlib', version: '>= 999', + fallback : ['donotexist', 'fakezlib_dep'], + required: false) +assert(not d.found(), 'version should not match and it should not fallback') + # Check that you can find a dependency by not specifying a version after not # finding it by specifying a version. We add `static: true` here so that the # previously cached zlib dependencies don't get checked. diff --git a/test cases/linuxlike/5 dependency versions/subprojects/fakezlib/meson.build b/test cases/linuxlike/5 dependency versions/subprojects/fakezlib/meson.build new file mode 100644 index 0000000..5a07763 --- /dev/null +++ b/test cases/linuxlike/5 dependency versions/subprojects/fakezlib/meson.build @@ -0,0 +1,3 @@ +project('some', 'c', version : '0.1') + +fakezlib_dep = declare_dependency() |