From 862bc146a8f39c881c439d919b187b82c95f0871 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 14 Sep 2020 22:53:24 +0200 Subject: interpreter: refactor handling of dependency(fallback: ...) --- mesonbuild/interpreter.py | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) (limited to 'mesonbuild/interpreter.py') diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 9f54b0a..bbabd89 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -3707,8 +3707,10 @@ external dependencies (including libraries) must go to "dependencies".''') mlog.log('Dependency', mlog.bold(display_name), 'skipped: feature', mlog.bold(feature), 'disabled') return self.notfound_dependency() - has_fallback = 'fallback' in kwargs - if not has_fallback and name: + fallback = kwargs.get('fallback', None) + + # If "fallback" is absent, look for an implicit fallback. + if name and fallback is None: # 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 @@ -3717,15 +3719,14 @@ external dependencies (including libraries) must go to "dependencies".''') provider = self.environment.wrap_resolver.find_dep_provider(name) dirname = mesonlib.listify(provider)[0] if provider and (required or self.get_subproject(dirname)): - kwargs['fallback'] = provider - has_fallback = True + fallback = provider - if 'default_options' in kwargs and not has_fallback: + if 'default_options' in kwargs and not fallback: mlog.warning('The "default_options" keyworg argument does nothing without a "fallback" keyword argument.', location=self.current_node) # writing just "dependency('')" is an error, because it can only fail - if name == '' and required and not has_fallback: + if name == '' and required and not fallback: raise InvalidArguments('Dependency is both required and not-found') if '<' in name or '>' in name or '=' in name: @@ -3734,8 +3735,8 @@ external dependencies (including libraries) must go to "dependencies".''') identifier, cached_dep = self._find_cached_dep(name, display_name, kwargs) if cached_dep: - if has_fallback: - dirname, varname = self.get_subproject_infos(kwargs) + if fallback: + dirname, varname = self.get_subproject_infos(fallback) 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' @@ -3744,21 +3745,21 @@ external dependencies (including libraries) must go to "dependencies".''') # If the dependency has already been configured, possibly by # a higher level project, try to use it first. - if has_fallback: - dirname, varname = self.get_subproject_infos(kwargs) + if fallback: + dirname, varname = self.get_subproject_infos(fallback) if self.get_subproject(dirname): return self.get_subproject_dep(name, display_name, dirname, varname, kwargs) wrap_mode = self.coredata.get_builtin_option('wrap_mode') force_fallback_for = self.coredata.get_builtin_option('force_fallback_for') force_fallback = kwargs.get('force_fallback', False) - forcefallback = has_fallback and (wrap_mode == WrapMode.forcefallback or \ - name in force_fallback_for or \ - dirname in force_fallback_for or \ - force_fallback) + forcefallback = fallback and (wrap_mode == WrapMode.forcefallback or \ + name in force_fallback_for or \ + dirname in force_fallback_for or \ + force_fallback) if name != '' and not forcefallback: self._handle_featurenew_dependencies(name) - kwargs['required'] = required and not has_fallback + kwargs['required'] = required and not fallback dep = dependencies.find_external_dependency(name, self.environment, kwargs) kwargs['required'] = required # Only store found-deps in the cache @@ -3770,8 +3771,8 @@ external dependencies (including libraries) must go to "dependencies".''') self.coredata.deps[for_machine].put(identifier, dep) return DependencyHolder(dep, self.subproject) - if has_fallback: - return self.dependency_fallback(name, display_name, kwargs) + if fallback: + return self.dependency_fallback(name, display_name, fallback, kwargs) return self.notfound_dependency() @@ -3798,8 +3799,8 @@ external dependencies (including libraries) must go to "dependencies".''') message.append(mlog.bold(command_templ.format(l[len(self.source_root) + 1:]))) mlog.warning(*message, location=self.current_node) - def get_subproject_infos(self, kwargs): - fbinfo = mesonlib.stringlistify(kwargs['fallback']) + def get_subproject_infos(self, fbinfo): + fbinfo = mesonlib.stringlistify(fbinfo) if len(fbinfo) == 1: FeatureNew.single_use('Fallback without variable name', '0.53.0', self.subproject) return fbinfo[0], None @@ -3807,8 +3808,8 @@ external dependencies (including libraries) must go to "dependencies".''') raise InterpreterException('Fallback info must have one or two items.') return fbinfo - def dependency_fallback(self, name, display_name, kwargs): - dirname, varname = self.get_subproject_infos(kwargs) + def dependency_fallback(self, name, display_name, fallback, kwargs): + dirname, varname = self.get_subproject_infos(fallback) required = kwargs.get('required', True) # Explicitly listed fallback preferences for specific subprojects -- cgit v1.1 From 1eec5cf41f905c988af4be003a03d29fca7baef4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 8 Oct 2020 12:02:48 +0200 Subject: interpreter: clean up handling of force_fallback Force_fallback is not an interpreter keyword argument, and there is no reason to handle it as one since it is not used anywhere else (and in fact is explicitly ignored by get_dep_identifier). Use a Python keyword argument instead, which makes the code simpler. --- mesonbuild/interpreter.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'mesonbuild/interpreter.py') diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index bbabd89..07cf1e2 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2642,10 +2642,9 @@ class Interpreter(InterpreterBase): FeatureNew.single_use('stdlib without variable name', '0.56.0', self.subproject) kwargs = {'fallback': di, 'native': for_machine is MachineChoice.BUILD, - 'force_fallback': True, } name = display_name = l + '_stdlib' - dep = self.dependency_impl(name, display_name, kwargs) + dep = self.dependency_impl(name, display_name, kwargs, force_fallback=True) self.build.stdlibs[for_machine][l] = dep def import_module(self, modname): @@ -3701,7 +3700,7 @@ external dependencies (including libraries) must go to "dependencies".''') build.DependencyOverride(d.held_object, node, explicit=False) return d - def dependency_impl(self, name, display_name, kwargs): + def dependency_impl(self, name, display_name, kwargs, force_fallback=False): disabled, required, feature = extract_required_kwarg(kwargs, self.subproject) if disabled: mlog.log('Dependency', mlog.bold(display_name), 'skipped: feature', mlog.bold(feature), 'disabled') @@ -3743,21 +3742,21 @@ external dependencies (including libraries) must go to "dependencies".''') raise DependencyException(m.format(display_name)) return DependencyHolder(cached_dep, self.subproject) - # If the dependency has already been configured, possibly by - # a higher level project, try to use it first. if fallback: + # If the dependency has already been configured, possibly by + # a higher level project, try to use it first. dirname, varname = self.get_subproject_infos(fallback) if self.get_subproject(dirname): return self.get_subproject_dep(name, display_name, dirname, varname, kwargs) - wrap_mode = self.coredata.get_builtin_option('wrap_mode') - force_fallback_for = self.coredata.get_builtin_option('force_fallback_for') - force_fallback = kwargs.get('force_fallback', False) - forcefallback = fallback and (wrap_mode == WrapMode.forcefallback or \ - name in force_fallback_for or \ - dirname in force_fallback_for or \ - force_fallback) - if name != '' and not forcefallback: + wrap_mode = self.coredata.get_builtin_option('wrap_mode') + force_fallback_for = self.coredata.get_builtin_option('force_fallback_for') + force_fallback = (force_fallback or + wrap_mode == WrapMode.forcefallback or + name in force_fallback_for or + dirname in force_fallback_for) + + if name != '' and (not fallback or not force_fallback): self._handle_featurenew_dependencies(name) kwargs['required'] = required and not fallback dep = dependencies.find_external_dependency(name, self.environment, kwargs) -- cgit v1.1 From 726b82205492a9e1f2dfd0fba96b237b51eeb428 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 8 Oct 2020 12:05:51 +0200 Subject: 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. --- mesonbuild/interpreter.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'mesonbuild/interpreter.py') 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 -- cgit v1.1