diff options
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/dependencies/base.py | 6 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 73 |
2 files changed, 45 insertions, 34 deletions
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 14db6a5..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', 'force_fallback'): + 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 9f54b0a..ca1411e 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,31 +3700,41 @@ 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') return self.notfound_dependency() - has_fallback = 'fallback' in kwargs - if not has_fallback and name: + 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 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)): - kwargs['fallback'] = provider - has_fallback = True + if provider and (allow_fallback is True or required or self.get_subproject(dirname)): + fallback = provider - if 'default_options' in kwargs and not has_fallback: - mlog.warning('The "default_options" keyworg argument does nothing without a "fallback" keyword argument.', + if 'default_options' in kwargs and not fallback: + 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 - 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,31 +3743,31 @@ 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' 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 has_fallback: - dirname, varname = self.get_subproject_infos(kwargs) + 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 = has_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 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 +3779,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 +3807,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 +3816,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 |