From d4ddf9afb52660cbdd0954fdcb22c540d5ef55d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Tue, 6 Feb 2024 16:05:30 +0100 Subject: [PATCH] [WIP] Fix subprojects logic in cross-scenarios --- mesonbuild/interpreter/dependencyfallbacks.py | 20 ++++--- mesonbuild/interpreter/interpreter.py | 57 ++++++++++++------- mesonbuild/wrap/wrap.py | 1 + 3 files changed, 48 insertions(+), 30 deletions(-) diff --git a/mesonbuild/interpreter/dependencyfallbacks.py b/mesonbuild/interpreter/dependencyfallbacks.py index eca6a2c71796..72b43c624afc 100644 --- a/mesonbuild/interpreter/dependencyfallbacks.py +++ b/mesonbuild/interpreter/dependencyfallbacks.py @@ -74,7 +74,7 @@ def _do_dependency_cache(self, kwargs: TYPE_nkwargs, func_args: TYPE_nvar, func_ name = func_args[0] cached_dep = self._get_cached_dep(name, kwargs) if cached_dep: - self._verify_fallback_consistency(cached_dep) + self._verify_fallback_consistency(cached_dep, kwargs.get('native', False)) return cached_dep def _do_dependency(self, kwargs: TYPE_nkwargs, func_args: TYPE_nvar, func_kwargs: TYPE_nkwargs) -> T.Optional[Dependency]: @@ -95,7 +95,7 @@ def _do_dependency(self, kwargs: TYPE_nkwargs, func_args: TYPE_nvar, func_kwargs def _do_existing_subproject(self, kwargs: TYPE_nkwargs, func_args: TYPE_nvar, func_kwargs: TYPE_nkwargs) -> T.Optional[Dependency]: subp_name = func_args[0] varname = self.subproject_varname - if subp_name and self._get_subproject(subp_name): + if subp_name and self._get_subproject(subp_name, kwargs.get('native', False)): return self._get_subproject_dep(subp_name, varname, kwargs) return None @@ -130,15 +130,17 @@ def _do_subproject(self, kwargs: TYPE_nkwargs, func_args: TYPE_nvar, func_kwargs self.interpreter.do_subproject(subp_name, func_kwargs) return self._get_subproject_dep(subp_name, varname, kwargs) - def _get_subproject(self, subp_name: str) -> T.Optional[SubprojectHolder]: - sub = self.interpreter.subprojects.get(subp_name) + def _get_subproject(self, subp_name: str, native: bool) -> T.Optional[SubprojectHolder]: + sub = self.interpreter.find_subproject(subp_name, native) if sub and sub.found(): return sub return None def _get_subproject_dep(self, subp_name: str, varname: str, kwargs: TYPE_nkwargs) -> T.Optional[Dependency]: + native = kwargs.get('native', False) + # Verify the subproject is found - subproject = self._get_subproject(subp_name) + subproject = self._get_subproject(subp_name, native) if not subproject: mlog.log('Dependency', mlog.bold(self._display_name), 'from subproject', mlog.bold(subp_name), 'found:', mlog.red('NO'), @@ -160,7 +162,7 @@ def _get_subproject_dep(self, subp_name: str, varname: str, kwargs: TYPE_nkwargs # If we have cached_dep we did all the checks and logging already in # self._get_cached_dep(). if cached_dep: - self._verify_fallback_consistency(cached_dep) + self._verify_fallback_consistency(cached_dep, native) return cached_dep # Legacy: Use the variable name if provided instead of relying on the @@ -256,10 +258,12 @@ def _get_subproject_variable(self, subproject: SubprojectHolder, varname: str) - return None return var_dep - def _verify_fallback_consistency(self, cached_dep: Dependency) -> None: + def _verify_fallback_consistency(self, cached_dep: Dependency, native: bool) -> None: subp_name = self.subproject_name + if subp_name is None: + return varname = self.subproject_varname - subproject = self._get_subproject(subp_name) + subproject = self._get_subproject(subp_name, native) if subproject and varname: var_dep = self._get_subproject_variable(subproject, varname) if var_dep and cached_dep.found() and var_dep != cached_dep: diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index bee64aa94ba4..ba383b4edca6 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -859,18 +859,29 @@ def func_subproject(self, nodes: mparser.BaseNode, args: T.Tuple[str], kwargs: k } return self.do_subproject(args[0], kw) - def disabled_subproject(self, subp_name: str, disabled_feature: T.Optional[str] = None, + def find_subproject(self, subp_name: str, native: bool) -> Optional[SubprojectHolder]: + return self.subprojects.get(self._make_subproject_id(subp_name, native)) + + def _make_subproject_id(self, subp_name: str, native: bool) -> str: + if not self.coredata.is_cross_build(): + return subp_name + tag = 'build' if native else 'host' + return ':'.join([subp_name, tag]) + + def disabled_subproject(self, subp_name: str, subp_id: str, disabled_feature: T.Optional[str] = None, exception: T.Optional[Exception] = None) -> SubprojectHolder: sub = SubprojectHolder(NullSubprojectInterpreter(), os.path.join(self.subproject_dir, subp_name), disabled_feature=disabled_feature, exception=exception) - self.subprojects[subp_name] = sub + self.subprojects[subp_id] = sub return sub def do_subproject(self, subp_name: str, kwargs: kwtypes.DoSubproject, force_method: T.Optional[wrap.Method] = None) -> SubprojectHolder: + subp_id = self._make_subproject_id(subp_name, kwargs.get('native', False)) + disabled, required, feature = extract_required_kwarg(kwargs, self.subproject) if disabled: mlog.log('Subproject', mlog.bold(subp_name), ':', 'skipped: feature', mlog.bold(feature), 'disabled') - return self.disabled_subproject(subp_name, disabled_feature=feature) + return self.disabled_subproject(subp_name, subp_id, disabled_feature=feature) default_options = {k.evolve(subproject=subp_name): v for k, v in kwargs['default_options'].items()} @@ -889,8 +900,8 @@ def do_subproject(self, subp_name: str, kwargs: kwtypes.DoSubproject, force_meth fullstack = self.subproject_stack + [subp_name] incpath = ' => '.join(fullstack) raise InvalidCode(f'Recursive include of subprojects: {incpath}.') - if subp_name in self.subprojects: - subproject = self.subprojects[subp_name] + if subp_id in self.subprojects: + subproject = self.subprojects[subp_id] if required and not subproject.found(): raise InterpreterException(f'Subproject "{subproject.subdir}" required but not found.') if kwargs['version']: @@ -907,7 +918,7 @@ def do_subproject(self, subp_name: str, kwargs: kwtypes.DoSubproject, force_meth if not required: mlog.log(e) mlog.log('Subproject ', mlog.bold(subp_name), 'is buildable:', mlog.red('NO'), '(disabling)') - return self.disabled_subproject(subp_name, exception=e) + return self.disabled_subproject(subp_name, subp_id, exception=e) raise e os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True) @@ -919,14 +930,14 @@ def do_subproject(self, subp_name: str, kwargs: kwtypes.DoSubproject, force_meth m += ['method', mlog.bold(method)] mlog.log(*m, '\n', nested=False) - methods_map: T.Dict[wrap.Method, T.Callable[[str, str, T.Dict[OptionKey, str, kwtypes.DoSubproject]], SubprojectHolder]] = { + methods_map: T.Dict[wrap.Method, T.Callable[[str, str, T.Dict[OptionKey, str, str, kwtypes.DoSubproject]], SubprojectHolder]] = { 'meson': self._do_subproject_meson, 'cmake': self._do_subproject_cmake, 'cargo': self._do_subproject_cargo, } try: - return methods_map[method](subp_name, subdir, default_options, kwargs) + return methods_map[method](subp_name, subp_id, subdir, default_options, kwargs) # Invalid code is always an error except InvalidCode: raise @@ -937,15 +948,17 @@ def do_subproject(self, subp_name: str, kwargs: kwtypes.DoSubproject, force_meth # fatal and VS CI treat any logs with "ERROR:" as fatal. mlog.exception(e, prefix=mlog.yellow('Exception:')) mlog.log('\nSubproject', mlog.bold(subdir), 'is buildable:', mlog.red('NO'), '(disabling)') - return self.disabled_subproject(subp_name, exception=e) + return self.disabled_subproject(subp_name, subp_id, exception=e) raise e - def _do_subproject_meson(self, subp_name: str, subdir: str, + def _do_subproject_meson(self, subp_name: str, subp_id: str, subdir: str, default_options: T.Dict[OptionKey, str], kwargs: kwtypes.DoSubproject, ast: T.Optional[mparser.CodeBlockNode] = None, build_def_files: T.Optional[T.List[str]] = None, relaxations: T.Optional[T.Set[InterpreterRuleRelaxation]] = None) -> SubprojectHolder: + subp_id = self._make_subproject_id(subp_name, kwargs.get('native', False)) + with mlog.nested(subp_name): if ast: # Debug print the generated meson file @@ -961,7 +974,7 @@ def _do_subproject_meson(self, subp_name: str, subdir: str, mlog.cmd_ci_include(meson_filename) new_build = self.build.copy() - subi = Interpreter(new_build, self.backend, subp_name, subdir, self.subproject_dir, + subi = Interpreter(new_build, self.backend, subp_id, subdir, self.subproject_dir, default_options, ast=ast, is_translated=(ast is not None), relaxations=relaxations, user_defined_options=self.user_defined_options) @@ -990,8 +1003,8 @@ def _do_subproject_meson(self, subp_name: str, subdir: str, raise InterpreterException(f'Subproject {subp_name} version is {pv} but {wanted} required.') self.active_projectname = current_active self.subprojects.update(subi.subprojects) - self.subprojects[subp_name] = SubprojectHolder(subi, subdir, warnings=subi_warnings, - callstack=self.subproject_stack) + self.subprojects[subp_id] = SubprojectHolder(subi, subdir, warnings=subi_warnings, + callstack=self.subproject_stack) # Duplicates are possible when subproject uses files from project root if build_def_files: self.build_def_files.update(build_def_files) @@ -999,9 +1012,9 @@ def _do_subproject_meson(self, subp_name: str, subdir: str, self.build_def_files.update(subi.build_def_files) self.build.merge(subi.build) self.build.subprojects[subp_name] = subi.project_version - return self.subprojects[subp_name] + return self.subprojects[subp_id] - def _do_subproject_cmake(self, subp_name: str, subdir: str, + def _do_subproject_cmake(self, subp_name: str, subp_id: str, subdir: str, default_options: T.Dict[OptionKey, str], kwargs: kwtypes.DoSubproject) -> SubprojectHolder: from ..cmake import CMakeInterpreter @@ -1018,7 +1031,7 @@ def _do_subproject_cmake(self, subp_name: str, subdir: str, # Generate a meson ast and execute it with the normal do_subproject_meson ast = cm_int.pretend_to_be_meson(options.target_options) result = self._do_subproject_meson( - subp_name, subdir, default_options, + subp_name, subp_id, subdir, default_options, kwargs, ast, [str(f) for f in cm_int.bs_files], relaxations={ @@ -1028,7 +1041,7 @@ def _do_subproject_cmake(self, subp_name: str, subdir: str, result.cm_interpreter = cm_int return result - def _do_subproject_cargo(self, subp_name: str, subdir: str, + def _do_subproject_cargo(self, subp_name: str, subp_id: str, subdir: str, default_options: T.Dict[OptionKey, str], kwargs: kwtypes.DoSubproject) -> SubprojectHolder: from .. import cargo @@ -1036,7 +1049,7 @@ def _do_subproject_cargo(self, subp_name: str, subdir: str, with mlog.nested(subp_name): ast = cargo.interpret(subp_name, subdir, self.environment) return self._do_subproject_meson( - subp_name, subdir, default_options, kwargs, ast, + subp_name, subp_id, subdir, default_options, kwargs, ast, # FIXME: Are there other files used by cargo interpreter? [os.path.join(subdir, 'Cargo.toml')]) @@ -1372,7 +1385,7 @@ def summary_impl(self, section: str, values, kwargs: 'kwtypes.Summary') -> None: def _print_summary(self) -> None: # Add automatic 'Subprojects' section in main project. all_subprojects = collections.OrderedDict() - for name, subp in sorted(self.subprojects.items()): + for subp_id, subp in sorted(self.subprojects.items()): value = [subp.found()] if subp.disabled_feature: value += [f'Feature {subp.disabled_feature!r} disabled'] @@ -1383,7 +1396,7 @@ def _print_summary(self) -> None: if subp.callstack: stack = ' => '.join(subp.callstack) value += [f'(from {stack})'] - all_subprojects[name] = value + all_subprojects[subp_id] = value if all_subprojects: self.summary_impl('Subprojects', all_subprojects, {'bool_yn': True, @@ -1403,8 +1416,8 @@ def _print_summary(self) -> None: # Print all summaries, main project last. mlog.log('') # newline main_summary = self.summary.pop('', None) - for subp_name, summary in sorted(self.summary.items()): - if self.subprojects[subp_name].found(): + for subp_id, summary in sorted(self.summary.items()): + if self.subprojects[subp_id].found(): summary.dump() if main_summary: main_summary.dump() diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py index 9a310bc414f6..ee4c7e419378 100644 --- a/mesonbuild/wrap/wrap.py +++ b/mesonbuild/wrap/wrap.py @@ -389,6 +389,7 @@ def find_dep_provider(self, packagename: str) -> T.Tuple[T.Optional[str], T.Opti def get_varname(self, subp_name: str, depname: str) -> T.Optional[str]: wrap = self.wraps.get(subp_name) + print("got wrap:", wrap) return wrap.provided_deps.get(depname) if wrap else None def find_program_provider(self, names: T.List[str]) -> T.Optional[str]: