Merge pull request #6203 from xclaesse/override-dependency
Add meson.override_dependency()
This commit is contained in:
commit
18f5a197da
|
@ -445,6 +445,10 @@ arguments:
|
||||||
[`dependency()`](#dependency), etc. Note that this means the
|
[`dependency()`](#dependency), etc. Note that this means the
|
||||||
fallback dependency may be a not-found dependency, in which
|
fallback dependency may be a not-found dependency, in which
|
||||||
case the value of the `required:` kwarg will be obeyed.
|
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
|
- `language` *(added 0.42.0)* defines what language-specific
|
||||||
dependency to find if it's available for multiple languages.
|
dependency to find if it's available for multiple languages.
|
||||||
- `method` defines the way the dependency is detected, the default is
|
- `method` defines the way the dependency is detected, the default is
|
||||||
|
@ -1825,12 +1829,21 @@ the following methods.
|
||||||
- `override_find_program(progname, program)` [*(Added
|
- `override_find_program(progname, program)` [*(Added
|
||||||
0.46.0)*](Release-notes-for-0.46.0.md#can-override-find_program)
|
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
|
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
|
instead return `program`, which may either be the result of
|
||||||
`find_program`, `configure_file` or `executable`.
|
`find_program`, `configure_file` or `executable`.
|
||||||
|
|
||||||
If `program` is an `executable`, it cannot be used during configure.
|
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_version()` returns the version string specified in
|
||||||
`project` function call.
|
`project` function call.
|
||||||
|
|
||||||
|
|
|
@ -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')`.
|
|
@ -106,6 +106,12 @@ def get_target_macos_dylib_install_name(ld) -> str:
|
||||||
class InvalidArguments(MesonException):
|
class InvalidArguments(MesonException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class DependencyOverride:
|
||||||
|
def __init__(self, dep, node, explicit=True):
|
||||||
|
self.dep = dep
|
||||||
|
self.node = node
|
||||||
|
self.explicit = explicit
|
||||||
|
|
||||||
class Build:
|
class Build:
|
||||||
"""A class that holds the status of one build including
|
"""A class that holds the status of one build including
|
||||||
all dependencies and so on.
|
all dependencies and so on.
|
||||||
|
@ -141,6 +147,7 @@ class Build:
|
||||||
self.test_setup_default_name = None
|
self.test_setup_default_name = None
|
||||||
self.find_overrides = {}
|
self.find_overrides = {}
|
||||||
self.searched_programs = set() # The list of all programs that have been searched for.
|
self.searched_programs = set() # The list of all programs that have been searched for.
|
||||||
|
self.dependency_overrides = PerMachine({}, {})
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
other = Build(self.environment)
|
other = Build(self.environment)
|
||||||
|
|
|
@ -1857,6 +1857,7 @@ class MesonMain(InterpreterObject):
|
||||||
'add_postconf_script': self.add_postconf_script_method,
|
'add_postconf_script': self.add_postconf_script_method,
|
||||||
'add_dist_script': self.add_dist_script_method,
|
'add_dist_script': self.add_dist_script_method,
|
||||||
'install_dependency_manifest': self.install_dependency_manifest_method,
|
'install_dependency_manifest': self.install_dependency_manifest_method,
|
||||||
|
'override_dependency': self.override_dependency_method,
|
||||||
'override_find_program': self.override_find_program_method,
|
'override_find_program': self.override_find_program_method,
|
||||||
'project_version': self.project_version_method,
|
'project_version': self.project_version_method,
|
||||||
'project_license': self.project_license_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.')
|
raise InterpreterException('Second argument must be an external program or executable.')
|
||||||
self.interpreter.add_find_program_override(name, exe)
|
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
|
@noPosargs
|
||||||
@permittedKwargs({})
|
@permittedKwargs({})
|
||||||
def project_version_method(self, args, kwargs):
|
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 /
|
# Check if we want this as a build-time / build machine or runt-time /
|
||||||
# host machine dep.
|
# host machine dep.
|
||||||
for_machine = self.machine_from_native_kwarg(kwargs)
|
for_machine = self.machine_from_native_kwarg(kwargs)
|
||||||
|
|
||||||
identifier = dependencies.get_dep_identifier(name, kwargs)
|
identifier = dependencies.get_dep_identifier(name, kwargs)
|
||||||
cached_dep = self.coredata.deps[for_machine].get(identifier)
|
wanted_vers = mesonlib.stringlistify(kwargs.get('version', []))
|
||||||
if cached_dep:
|
|
||||||
|
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():
|
if not cached_dep.found():
|
||||||
mlog.log('Dependency', mlog.bold(name),
|
mlog.log('Dependency', mlog.bold(name),
|
||||||
'found:', mlog.red('NO'), mlog.blue('(cached)'))
|
'found:', mlog.red('NO'), *info)
|
||||||
return identifier, cached_dep
|
return identifier, cached_dep
|
||||||
|
|
||||||
# Verify the cached dep version match
|
|
||||||
wanted_vers = mesonlib.stringlistify(kwargs.get('version', []))
|
|
||||||
found_vers = cached_dep.get_version()
|
found_vers = cached_dep.get_version()
|
||||||
if not wanted_vers or mesonlib.version_compare_many(found_vers, wanted_vers)[0]:
|
if not self.check_version(wanted_vers, found_vers):
|
||||||
info = [mlog.blue('(cached)')]
|
|
||||||
if found_vers:
|
|
||||||
info = [mlog.normal_cyan(found_vers), *info]
|
|
||||||
mlog.log('Dependency', mlog.bold(name),
|
mlog.log('Dependency', mlog.bold(name),
|
||||||
'found:', mlog.green('YES'), *info)
|
'found:', mlog.red('NO'),
|
||||||
return identifier, cached_dep
|
'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
|
return identifier, None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_subproject_version(wanted, found):
|
def check_version(wanted, found):
|
||||||
if not wanted:
|
if not wanted:
|
||||||
return True
|
return True
|
||||||
if found == 'undefined' or not mesonlib.version_compare_many(found, wanted)[0]:
|
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):
|
def notfound_dependency(self):
|
||||||
return DependencyHolder(NotFoundDependency(self.environment), self.subproject)
|
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()
|
dep = self.notfound_dependency()
|
||||||
try:
|
try:
|
||||||
subproject = self.subprojects[dirname]
|
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():
|
if subproject.found():
|
||||||
|
self.verify_fallback_consistency(dirname, varname, cached_dep)
|
||||||
dep = self.subprojects[dirname].get_variable_method([varname], {})
|
dep = self.subprojects[dirname].get_variable_method([varname], {})
|
||||||
except InvalidArguments:
|
except InvalidArguments:
|
||||||
pass
|
pass
|
||||||
|
@ -3264,10 +3329,6 @@ external dependencies (including libraries) must go to "dependencies".''')
|
||||||
raise InvalidCode('Fetched variable {!r} in the subproject {!r} is '
|
raise InvalidCode('Fetched variable {!r} in the subproject {!r} is '
|
||||||
'not a dependency object.'.format(varname, dirname))
|
'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 not dep.found():
|
||||||
if required:
|
if required:
|
||||||
raise DependencyException('Could not find dependency {} in subproject {}'
|
raise DependencyException('Could not find dependency {} in subproject {}'
|
||||||
|
@ -3278,7 +3339,7 @@ external dependencies (including libraries) must go to "dependencies".''')
|
||||||
return dep
|
return dep
|
||||||
|
|
||||||
found = dep.held_object.get_version()
|
found = dep.held_object.get_version()
|
||||||
if not self.check_subproject_version(wanted, found):
|
if not self.check_version(wanted, found):
|
||||||
if required:
|
if required:
|
||||||
raise DependencyException('Version {} of subproject dependency {} already '
|
raise DependencyException('Version {} of subproject dependency {} already '
|
||||||
'cached, requested incompatible version {} for '
|
'cached, requested incompatible version {} for '
|
||||||
|
@ -3330,6 +3391,15 @@ external dependencies (including libraries) must go to "dependencies".''')
|
||||||
raise
|
raise
|
||||||
if not d.found() and not_found_message:
|
if not d.found() and not_found_message:
|
||||||
self.message_impl([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
|
return d
|
||||||
|
|
||||||
def dependency_impl(self, name, display_name, kwargs):
|
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)
|
identifier, cached_dep = self._find_cached_dep(name, kwargs)
|
||||||
if cached_dep:
|
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():
|
if required and not cached_dep.found():
|
||||||
m = 'Dependency {!r} was already checked and was not found'
|
m = 'Dependency {!r} was already checked and was not found'
|
||||||
raise DependencyException(m.format(display_name))
|
raise DependencyException(m.format(display_name))
|
||||||
|
@ -3363,7 +3436,7 @@ external dependencies (including libraries) must go to "dependencies".''')
|
||||||
if has_fallback:
|
if has_fallback:
|
||||||
dirname, varname = self.get_subproject_infos(kwargs)
|
dirname, varname = self.get_subproject_infos(kwargs)
|
||||||
if dirname in self.subprojects:
|
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')
|
wrap_mode = self.coredata.get_builtin_option('wrap_mode')
|
||||||
forcefallback = wrap_mode == WrapMode.forcefallback and has_fallback
|
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)
|
self._handle_featurenew_dependencies(name)
|
||||||
kwargs['required'] = required and not has_fallback
|
kwargs['required'] = required and not has_fallback
|
||||||
dep = dependencies.find_external_dependency(name, self.environment, kwargs)
|
dep = dependencies.find_external_dependency(name, self.environment, kwargs)
|
||||||
|
|
||||||
kwargs['required'] = required
|
kwargs['required'] = required
|
||||||
# Only store found-deps in the cache
|
# Only store found-deps in the cache
|
||||||
# Never add fallback deps to self.coredata.deps since we
|
# 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)
|
return DependencyHolder(dep, self.subproject)
|
||||||
|
|
||||||
if has_fallback:
|
if has_fallback:
|
||||||
return self.dependency_fallback(display_name, kwargs)
|
return self.dependency_fallback(name, display_name, kwargs)
|
||||||
|
|
||||||
return self.notfound_dependency()
|
return self.notfound_dependency()
|
||||||
|
|
||||||
|
@ -3411,13 +3483,15 @@ external dependencies (including libraries) must go to "dependencies".''')
|
||||||
mlog.warning(*message, location=self.current_node)
|
mlog.warning(*message, location=self.current_node)
|
||||||
|
|
||||||
def get_subproject_infos(self, kwargs):
|
def get_subproject_infos(self, kwargs):
|
||||||
fbinfo = kwargs['fallback']
|
fbinfo = mesonlib.stringlistify(kwargs['fallback'])
|
||||||
check_stringlist(fbinfo)
|
if len(fbinfo) == 1:
|
||||||
if len(fbinfo) != 2:
|
FeatureNew('Fallback without variable name', '0.53.0').use(self.subproject)
|
||||||
raise InterpreterException('Fallback info must have exactly two items.')
|
return fbinfo[0], None
|
||||||
|
elif len(fbinfo) != 2:
|
||||||
|
raise InterpreterException('Fallback info must have one or two items.')
|
||||||
return fbinfo
|
return fbinfo
|
||||||
|
|
||||||
def dependency_fallback(self, display_name, kwargs):
|
def dependency_fallback(self, name, display_name, kwargs):
|
||||||
required = kwargs.get('required', True)
|
required = kwargs.get('required', True)
|
||||||
if self.coredata.get_builtin_option('wrap_mode') == WrapMode.nofallback:
|
if self.coredata.get_builtin_option('wrap_mode') == WrapMode.nofallback:
|
||||||
mlog.log('Not looking for a fallback subproject for the dependency',
|
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,
|
'required': required,
|
||||||
}
|
}
|
||||||
self.do_subproject(dirname, 'meson', sp_kwargs)
|
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'])
|
@FeatureNewKwargs('executable', '0.42.0', ['implib'])
|
||||||
@permittedKwargs(permitted_kwargs['executable'])
|
@permittedKwargs(permitted_kwargs['executable'])
|
||||||
|
|
|
@ -3980,11 +3980,17 @@ recommended as it is not supported on some platforms''')
|
||||||
{
|
{
|
||||||
'descriptive_name': 'sub',
|
'descriptive_name': 'sub',
|
||||||
'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):
|
def test_introspection_target_subproject(self):
|
||||||
testdir = os.path.join(self.common_test_dir, '45 subproject')
|
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')
|
raise unittest.SkipTest('zlib not found with pkg-config')
|
||||||
a = (("dependency('zlib', method : 'fail')", "'fail' is invalid"),
|
a = (("dependency('zlib', method : 'fail')", "'fail' is invalid"),
|
||||||
("dependency('zlib', static : '1')", "[Ss]tatic.*boolean"),
|
("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', required : 1)", "[Rr]equired.*boolean"),
|
||||||
("dependency('zlib', method : 1)", "[Mm]ethod.*string"),
|
("dependency('zlib', method : 1)", "[Mm]ethod.*string"),
|
||||||
("dependency('zlibfail')", self.dnf),)
|
("dependency('zlibfail')", self.dnf),)
|
||||||
|
@ -4772,6 +4778,17 @@ class FailureTests(BasePlatformTests):
|
||||||
self.assertMesonOutputs("warning('Array:', ['a', 'b'])",
|
self.assertMesonOutputs("warning('Array:', ['a', 'b'])",
|
||||||
r"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)")
|
@unittest.skipUnless(is_windows() or is_cygwin(), "requires Windows (or Windows via Cygwin)")
|
||||||
class WindowsTests(BasePlatformTests):
|
class WindowsTests(BasePlatformTests):
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -4,3 +4,24 @@ libSub = dependency('sub', fallback: ['sub', 'libSub'])
|
||||||
|
|
||||||
exe = executable('prog', 'prog.c', dependencies: libSub)
|
exe = executable('prog', 'prog.c', dependencies: libSub)
|
||||||
test('subproject subdir', exe)
|
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')
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
lib = static_library('sub', 'sub.c')
|
lib = static_library('sub', 'sub.c')
|
||||||
libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib)
|
libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib)
|
||||||
|
meson.override_dependency('sub-1.0', libSub)
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
project('sub', 'c')
|
project('sub', 'c', version : '1.0')
|
||||||
subdir('lib')
|
subdir('lib')
|
||||||
|
|
|
@ -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))
|
|
@ -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'])
|
|
@ -0,0 +1,5 @@
|
||||||
|
project('proj', 'c')
|
||||||
|
|
||||||
|
dep1 = declare_dependency()
|
||||||
|
dep2 = declare_dependency()
|
||||||
|
meson.override_dependency('sub', dep1)
|
|
@ -0,0 +1,4 @@
|
||||||
|
project('proj', 'c')
|
||||||
|
|
||||||
|
# Subproject overrides 'sub' with another variable than dep2. This should fail.
|
||||||
|
dependency('sub', fallback : ['sub', 'dep2'])
|
|
@ -0,0 +1,5 @@
|
||||||
|
project('proj', 'c')
|
||||||
|
|
||||||
|
dep1 = declare_dependency()
|
||||||
|
dep2 = declare_dependency()
|
||||||
|
meson.override_dependency('sub', dep1)
|
|
@ -38,32 +38,32 @@ somelibver = dependency('somelib',
|
||||||
fallback : ['somelibnover', 'some_dep'])
|
fallback : ['somelibnover', 'some_dep'])
|
||||||
assert(somelibver.type_name() == 'internal', 'somelibver should be of type "internal", not ' + somelibver.type_name())
|
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
|
# Find an internal dependency again with the same name and a specific version
|
||||||
somelib = dependency('somelib',
|
somelib = dependency('somelib2',
|
||||||
version : '== 0.1',
|
version : '== 0.1',
|
||||||
fallback : ['somelib', 'some_dep'])
|
fallback : ['somelib', 'some_dep'])
|
||||||
# Find an internal dependency again even if required = false
|
# Find an internal dependency again even if required = false
|
||||||
somelib_reqfalse = dependency('somelib',
|
somelib_reqfalse = dependency('somelib3',
|
||||||
required: false,
|
required: false,
|
||||||
fallback : ['somelib', 'some_dep'])
|
fallback : ['somelib', 'some_dep'])
|
||||||
assert(somelib_reqfalse.found(), 'somelib should have been found')
|
assert(somelib_reqfalse.found(), 'somelib should have been found')
|
||||||
# Find an internal dependency again with the same name and incompatible version
|
# Find an internal dependency again with the same name and incompatible version
|
||||||
somelibver = dependency('somelib',
|
somelibver = dependency('somelib4',
|
||||||
version : '>= 0.3',
|
version : '>= 0.3',
|
||||||
fallback : ['somelibver', 'some_dep'])
|
fallback : ['somelibver', 'some_dep'])
|
||||||
# Find an internal dependency again with impossible multi-version
|
# Find an internal dependency again with impossible multi-version
|
||||||
somelibver = dependency('somelib',
|
somelibver = dependency('somelib5',
|
||||||
version : ['>= 0.3', '<0.3'],
|
version : ['>= 0.3', '<0.3'],
|
||||||
required : false,
|
required : false,
|
||||||
fallback : ['somelibver', 'some_dep'])
|
fallback : ['somelibver', 'some_dep'])
|
||||||
assert(not somelibver.found(), 'Dependency should not be found')
|
assert(not somelibver.found(), 'Dependency should not be found')
|
||||||
# Find somelib again, but with a fallback that will fail because subproject does not exist
|
# Find somelib again, but with a fallback that will fail because subproject does not exist
|
||||||
somelibfail = dependency('somelib',
|
somelibfail = dependency('somelib6',
|
||||||
version : '>= 0.2',
|
version : '>= 0.2',
|
||||||
required : false,
|
required : false,
|
||||||
fallback : ['somelibfail', 'some_dep'])
|
fallback : ['somelibfail', 'some_dep'])
|
||||||
assert(somelibfail.found() == false, 'somelibfail found via wrong fallback')
|
assert(somelibfail.found() == false, 'somelibfail found via wrong fallback')
|
||||||
# Find somelib again, but with a fallback that will fail because dependency does not exist
|
# 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',
|
version : '>= 0.2',
|
||||||
required : false,
|
required : false,
|
||||||
fallback : ['somelib', 'somefail_dep'])
|
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
|
# Fallback should only be used if the primary was not found
|
||||||
fallbackzlib_dep = dependency('zlib',
|
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())
|
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
|
# Check that the above dependency was pkgconfig because the fallback wasn't
|
||||||
# checked, not because the fallback didn't work
|
# checked, not because the fallback didn't work
|
||||||
fakezlib_dep = dependency('fakezlib',
|
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())
|
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
|
# 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
|
# finding it by specifying a version. We add `static: true` here so that the
|
||||||
# previously cached zlib dependencies don't get checked.
|
# previously cached zlib dependencies don't get checked.
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
project('some', 'c', version : '0.1')
|
||||||
|
|
||||||
|
fakezlib_dep = declare_dependency()
|
Loading…
Reference in New Issue