From 4c1701caa9f6961892b828adcf90e6aedd6a6aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Wed, 13 Mar 2024 22:42:35 +0100 Subject: [PATCH] Further fix subprojects logic in cross build scenarios --- mesonbuild/backend/backends.py | 20 +++- mesonbuild/backend/ninjabackend.py | 9 +- mesonbuild/build.py | 32 ++++- mesonbuild/coredata.py | 12 +- mesonbuild/environment.py | 8 +- mesonbuild/interpreter/dependencyfallbacks.py | 3 +- mesonbuild/interpreter/interpreter.py | 110 +++++++++++++----- mesonbuild/interpreter/interpreterobjects.py | 13 ++- mesonbuild/interpreter/mesonmain.py | 2 +- mesonbuild/modules/__init__.py | 3 + mesonbuild/modules/gnome.py | 2 +- mesonbuild/modules/pkgconfig.py | 3 + mesonbuild/modules/windows.py | 3 +- mesonbuild/utils/universal.py | 8 +- 14 files changed, 172 insertions(+), 56 deletions(-) diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 5b947991577a..6e008a6c357b 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -330,10 +330,11 @@ def get_source_dir_include_args(self, target: build.BuildTarget, compiler: 'Comp return compiler.get_include_args(tmppath, False) def get_build_dir_include_args(self, target: build.BuildTarget, compiler: 'Compiler', *, absolute_path: bool = False) -> T.List[str]: + subdir = self.compute_build_subdir(target.get_subdir(), target.is_native_cross()) if absolute_path: - curdir = os.path.join(self.build_dir, target.get_subdir()) + curdir = os.path.join(self.build_dir, subdir) else: - curdir = target.get_subdir() + curdir = subdir if curdir == '': curdir = '.' return compiler.get_include_args(curdir, False) @@ -368,9 +369,11 @@ def get_target_dir(self, target: T.Union[build.Target, build.CustomTargetIndex]) # this produces no output, only a dummy top-level name dirname = '' elif self.environment.coredata.get_option(OptionKey('layout')) == 'mirror': - dirname = target.get_subdir() + dirname = self.compute_build_subdir(target.get_subdir(), target.is_native_cross()) else: dirname = 'meson-out' + if target.is_native_cross(): + dirname += '-native' return dirname def get_target_dir_relative_to(self, t: build.Target, o: build.Target) -> str: @@ -409,6 +412,10 @@ def get_target_generated_dir( # target that the GeneratedList is used in return os.path.join(self.get_target_private_dir(target), src) + @classmethod + def compute_build_subdir(cls, subdir: str, is_native_cross: bool) -> str: + return compute_build_subdir(subdir, is_native_cross) + def get_unity_source_file(self, target: T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex], suffix: str, number: int) -> mesonlib.File: # There is a potential conflict here, but it is unlikely that @@ -2043,3 +2050,10 @@ def compile_target_to_generator(self, target: build.CompileTarget) -> build.Gene all_sources = T.cast('_ALL_SOURCES_TYPE', target.sources) + T.cast('_ALL_SOURCES_TYPE', target.generated) return self.compiler_to_generator(target, target.compiler, all_sources, target.output_templ, target.depends) + + +def compute_build_subdir(subdir: str, is_native_cross: bool) -> str: + if is_native_cross: + assert subdir.startswith('subprojects') + return 'subprojects-native' + subdir[11:] + return subdir diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 782b264acc90..aed40f2aa2a6 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2778,7 +2778,7 @@ def generate_llvm_ir_compile(self, target, src): return (rel_obj, rel_src) @lru_cache(maxsize=None) - def generate_inc_dir(self, compiler: 'Compiler', d: str, basedir: str, is_system: bool) -> \ + def generate_inc_dir(self, compiler: 'Compiler', d: str, basedir: str, is_system: bool, is_native_cross: bool) -> \ T.Tuple['ImmutableListProtocol[str]', 'ImmutableListProtocol[str]']: # Avoid superfluous '/.' at the end of paths when d is '.' if d not in ('', '.'): @@ -2793,8 +2793,9 @@ def generate_inc_dir(self, compiler: 'Compiler', d: str, basedir: str, is_system # inc = include_directories('foo/bar/baz') # # But never subdir()s into the actual dir. - if os.path.isdir(os.path.join(self.environment.get_build_dir(), expdir)): - bargs = compiler.get_include_args(expdir, is_system) + subdir = self.compute_build_subdir(expdir, is_native_cross) + if os.path.isdir(os.path.join(self.environment.get_build_dir(), subdir)): + bargs = compiler.get_include_args(subdir, is_system) else: bargs = [] return (sargs, bargs) @@ -2843,7 +2844,7 @@ def _generate_single_compile_target_args(self, target: build.BuildTarget, compil # flags will be added in reversed order. for d in reversed(i.get_incdirs()): # Add source subdir first so that the build subdir overrides it - (compile_obj, includeargs) = self.generate_inc_dir(compiler, d, basedir, i.is_system) + (compile_obj, includeargs) = self.generate_inc_dir(compiler, d, basedir, i.is_system, i.is_native_cross) commands += compile_obj commands += includeargs for d in i.get_extra_build_dirs(): diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 6fc6804125d3..85b8d65da593 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -297,6 +297,18 @@ def copy(self) -> Build: def copy_to_native(self) -> Build: other = Build(self.environment.copy_to_native()) self._copy_to(other) + + other.tests = [] + other.benchmarks = [] + other.test_setups = {} + other.test_setup_default_name = None + other.find_overrides = {} + other.searched_programs = set() + + other.dependency_overrides = PerMachineDefaultable.default(False, self.dependency_overrides.build, {}) + other.devenv = [] + other.modules = [] + return other def _copy_to(self, other: Build) -> None: @@ -309,9 +321,13 @@ def _copy_to(self, other: Build) -> None: other.__dict__[k] = v def merge(self, other: Build) -> None: + is_native_cross = other.environment.coredata.is_native_cross() + for k, v in other.__dict__.items(): if k == 'environment': continue + if is_native_cross and k == 'dependency_overrides': + continue self.__dict__[k] = v def ensure_static_linker(self, compiler: Compiler) -> None: @@ -391,6 +407,7 @@ class IncludeDirs(HoldableObject): curdir: str incdirs: T.List[str] is_system: bool + is_native_cross: bool # Interpreter has validated that all given directories # actually exist. extra_build_dirs: T.List[str] = field(default_factory=list) @@ -616,7 +633,7 @@ def get_basename(self) -> str: return self.name def get_subdir(self) -> str: - return self.environment.build_output_rpath(self.subdir) + return self.subdir def get_typename(self) -> str: return self.typename @@ -655,7 +672,10 @@ def get_id(self) -> str: if getattr(self, 'name_suffix_set', False): name += '.' + self.suffix return self.construct_id_from_path( - self.subdir, name, self.type_suffix(), '@native' if self.environment.coredata.is_native_clone else '') + self.subdir, name, self.type_suffix(), '@native' if self.is_native_cross() else '') + + def is_native_cross(self) -> bool: + return self.environment.coredata.is_native_cross() def process_kwargs_base(self, kwargs: T.Dict[str, T.Any]) -> None: if 'build_by_default' in kwargs: @@ -1501,8 +1521,6 @@ def check_can_link_together(self, t: BuildTargetTypes) -> None: links_with_rust_abi = isinstance(t, BuildTarget) and t.uses_rust_abi() if not self.uses_rust() and links_with_rust_abi: raise InvalidArguments(f'Try to link Rust ABI library {t.name!r} with a non-Rust target {self.name!r}') - if isinstance(t, Target) and t.subproject and not self.environment.is_cross_build(): - return if self.for_machine is not t.for_machine and (not links_with_rust_abi or t.rust_crate_type != 'proc-macro'): msg = f'Tried to mix libraries for machines {self.for_machine} and {t.for_machine} in target {self.name!r}' if self.environment.is_cross_build(): @@ -1551,7 +1569,8 @@ def add_include_dirs(self, args: T.Sequence['IncludeDirs'], set_is_system: T.Opt set_is_system = 'preserve' if set_is_system != 'preserve': is_system = set_is_system == 'system' - ids = [IncludeDirs(x.get_curdir(), x.get_incdirs(), is_system, x.get_extra_build_dirs()) for x in ids] + ids = [IncludeDirs(x.get_curdir(), x.get_incdirs(), is_system, + self.is_native_cross(), x.get_extra_build_dirs()) for x in ids] self.include_dirs += ids def get_aliases(self) -> T.List[T.Tuple[str, str, str]]: @@ -2982,6 +3001,9 @@ def get_filename(self) -> str: def get_id(self) -> str: return self.target.get_id() + def is_native_cross(self) -> bool: + return self.target.is_native_cross() + def get_all_link_deps(self): return self.target.get_all_link_deps() diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 7b8859df015f..6e228badabbf 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -586,7 +586,7 @@ def __init__(self, options: argparse.Namespace, scratch_dir: str, meson_command: self.builtin_options_libdir_cross_fixup() self.init_builtins('') - self.is_native_clone = False + self._is_native_clone = False def copy_to_native(self) -> CoreData: other = CoreData.__new__(CoreData) @@ -597,13 +597,14 @@ def copy_to_native(self) -> CoreData: other.compilers = PerMachine(OrderedDict(), OrderedDict()) other.compilers.build = self.compilers.build + other.compilers.host = self.compilers.build other.deps = PerMachineDefaultable.default( is_cross=False, build=self.deps.build, host=self.deps.host) - other.is_native_clone = True + other._is_native_clone = True return other @@ -928,6 +929,9 @@ def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) return False return len(self.cross_files) > 0 + def is_native_cross(self) -> bool: + return self._is_native_clone + def copy_build_options_from_regular_ones(self) -> bool: dirty = False assert not self.is_cross_build() @@ -948,7 +952,7 @@ def copy_build_options_from_regular_ones(self) -> bool: def set_options(self, options: T.Dict[OptionKey, T.Any], subproject: str = '', first_invocation: bool = False) -> bool: dirty = False if not self.is_cross_build(): - other_machine = MachineChoice.HOST if self.is_native_clone else MachineChoice.BUILD + other_machine = MachineChoice.HOST if self.is_native_cross() else MachineChoice.BUILD options = {k: v for k, v in options.items() if k.machine is not other_machine} # Set prefix first because it's needed to sanitize other options @@ -973,7 +977,7 @@ def set_options(self, options: T.Dict[OptionKey, T.Any], subproject: str = '', f sub = f'In subproject {subproject}: ' if subproject else '' raise MesonException(f'{sub}Unknown options: "{unknown_options_str}"') - if not self.is_cross_build() and not self.is_native_clone: + if not self.is_cross_build() and not self.is_native_cross(): dirty |= self.copy_build_options_from_regular_ones() return dirty diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index e51cf4482243..663487262f80 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -869,9 +869,11 @@ def get_build_dir(self) -> str: return self.build_dir def build_output_rpath(self, subdir: str, *parts: T.Sequence[str]) -> str: - result = subdir - if self.coredata.is_native_clone: - result += '-native' + if self.coredata.is_native_cross(): + assert subdir.startswith('subprojects') + result = 'subprojects-native' + subdir[11:] + else: + result = subdir return os.path.join(result, *parts) def get_import_lib_dir(self) -> str: diff --git a/mesonbuild/interpreter/dependencyfallbacks.py b/mesonbuild/interpreter/dependencyfallbacks.py index 239d5e37ec16..c85ce420d595 100644 --- a/mesonbuild/interpreter/dependencyfallbacks.py +++ b/mesonbuild/interpreter/dependencyfallbacks.py @@ -95,7 +95,8 @@ 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, kwargs.get('native', False)): + native = kwargs.get('native', False) + if subp_name and self._get_subproject(subp_name, native): return self._get_subproject_dep(subp_name, varname, kwargs) return None diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 3d1f5d61b72c..17ec25486497 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -19,6 +19,7 @@ FileMode, MachineChoice, OptionKey, listify, extract_as_list, has_path_sep, path_is_in_root, PerMachine) from ..programs import ExternalProgram, NonExistingExternalProgram +from ..backend.backends import compute_build_subdir from ..dependencies import Dependency from ..depfile import DepFile from ..interpreterbase import ContainerTypeInfo, InterpreterBase, KwargInfo, typed_kwargs, typed_pos_args @@ -853,7 +854,9 @@ def run_command_impl(self, return RunProcess(cmd, expanded_args, env, srcdir, builddir, self.subdir, self.environment.get_build_command() + ['introspect'], - in_builddir=in_builddir, check=check, capture=capture) + in_builddir=in_builddir, + is_native_cross=self.coredata.is_native_cross(), + check=check, capture=capture) def func_option(self, nodes, args, kwargs): raise InterpreterException('Tried to call option() in build description file. All options must be in the option file.') @@ -879,7 +882,10 @@ def find_subproject(self, subp_name: str, native: bool) -> T.Optional[Subproject return self.subprojects.get(self._make_subproject_id(subp_name, native)) def _make_subproject_id(self, subp_name: str, native: bool) -> T.Tuple[str, MachineChoice]: - for_machine = MachineChoice.BUILD if native else MachineChoice.HOST + if self.coredata.is_native_cross(): + for_machine = MachineChoice.BUILD + else: + for_machine = MachineChoice.BUILD if native else MachineChoice.HOST return (subp_name, for_machine) def disabled_subproject(self, subp_name: str, subp_id: str, disabled_feature: T.Optional[str] = None, @@ -941,7 +947,7 @@ def do_subproject(self, subp_name: str, kwargs: kwtypes.DoSubproject, force_meth stack = ':'.join(self.subproject_stack + [subp_name]) m = ['\nExecuting subproject', mlog.bold(stack)] - if native and self.coredata.is_cross_build(): + if (native and self.coredata.is_cross_build()) or self.coredata.is_native_cross(): m += [mlog.normal_green('(native)')] if method != 'meson': m += ['method', mlog.bold(method)] @@ -991,11 +997,22 @@ def _do_subproject_meson(self, subp_name: str, subp_id: str, subdir: str, mlog.log('Generated Meson AST:', meson_filename) mlog.cmd_ci_include(meson_filename) - if native and self.coredata.is_cross_build(): + is_native_cross = native and self.coredata.is_cross_build() + is_native_cross_boundary = is_native_cross and not self.coredata.is_native_cross() + + if is_native_cross_boundary: new_build = self.build.copy_to_native() - default_options = {k.as_build(): v for k, v in default_options.items()} + new_subprojects = {k: v for k, v in self.subprojects.items() if k[1] is MachineChoice.BUILD} + for (name, for_machine), v in list(new_subprojects.items()): + new_subprojects[(name, MachineChoice.HOST)] = v + prev_subproject_ids = set(new_subprojects.keys()) else: new_build = self.build.copy() + new_subprojects = self.subprojects + + if new_build.environment.coredata.is_native_cross(): + default_options = {k.as_native_cross(): v for k, v in default_options.items()} + subi = Interpreter(new_build, self.backend, subp_name, subp_id, subdir, self.subproject_dir, default_options, ast=ast, is_translated=(ast is not None), relaxations=relaxations, @@ -1003,7 +1020,7 @@ def _do_subproject_meson(self, subp_name: str, subp_id: str, subdir: str, # Those lists are shared by all interpreters. That means that # even if the subproject fails, any modification that the subproject # made to those lists will affect the parent project. - subi.subprojects = self.subprojects + subi.subprojects = new_subprojects subi.modules = self.modules subi.holder_map = self.holder_map subi.bound_holder_map = self.bound_holder_map @@ -1012,7 +1029,11 @@ def _do_subproject_meson(self, subp_name: str, subp_id: str, subdir: str, subi.subproject_stack = self.subproject_stack + [subp_name] current_active = self.active_projectname with mlog.nested_warnings(): - subi.run() + try: + subi.run() + finally: + if is_native_cross_boundary: + self._merge_native_cross_subprojects(new_subprojects, prev_subproject_ids) subi_warnings = mlog.get_warning_count() mlog.log('Subproject', mlog.bold(subp_name), 'finished.') @@ -1024,7 +1045,6 @@ def _do_subproject_meson(self, subp_name: str, subp_id: str, subdir: str, if pv == 'undefined' or not mesonlib.version_compare_many(pv, wanted)[0]: 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_id] = SubprojectHolder(subi, subdir, warnings=subi_warnings, callstack=self.subproject_stack) # Duplicates are possible when subproject uses files from project root @@ -1036,6 +1056,13 @@ def _do_subproject_meson(self, subp_name: str, subp_id: str, subdir: str, self.build.subprojects[subp_name] = subi.project_version return self.subprojects[subp_id] + def _merge_native_cross_subprojects(self, new_subprojects, prev_subproject_ids): + for subp_id, v in new_subprojects.items(): + if subp_id in prev_subproject_ids: + continue + (subp_name, _) = subp_id + self.subprojects[(subp_name, MachineChoice.BUILD)] = v + def _do_subproject_cmake(self, subp_name: str, subp_id: str, subdir: str, default_options: T.Dict[OptionKey, str], kwargs: kwtypes.DoSubproject) -> SubprojectHolder: @@ -1078,22 +1105,42 @@ def _do_subproject_cargo(self, subp_name: str, subp_id: str, subdir: str, def get_option_internal(self, optname: str) -> coredata.UserOption: key = OptionKey.from_string(optname).evolve(subproject=self.subproject) - if self.coredata.is_native_clone: - key = key.as_build() + is_native_cross = self.coredata.is_native_cross() + if is_native_cross: + key = key.as_native_cross() + + key_for_host = key.as_host() + is_machine_neutral_builtin = key.is_builtin() and key_for_host not in coredata.BUILTIN_OPTIONS_PER_MACHINE if not key.is_project(): - for opts in [self.coredata.options, compilers.base_options]: - v = opts.get(key) + if is_native_cross: + candidates = [(self.coredata.options, key)] + if is_machine_neutral_builtin: + candidates += [(self.coredata.options, key_for_host)] + candidates += [(compilers.base_options, key_for_host)] + else: + candidates = [ + (self.coredata.options, key), + (compilers.base_options, key), + ] + for opts, k in candidates: + v = opts.get(k) if v is None or v.yielding: - v = opts.get(key.as_root()) + v = opts.get(k.as_root()) if v is not None: assert isinstance(v, coredata.UserOption), 'for mypy' return v try: - opt = self.coredata.options[key] - if opt.yielding and key.subproject and key.as_root() in self.coredata.options: - popt = self.coredata.options[key.as_root()] + if is_native_cross: + k = key_for_host if is_machine_neutral_builtin else key + else: + k = key + opt = self.coredata.options[k] + if opt.yielding and k.subproject \ + and (k.machine is MachineChoice.HOST or not k.is_project()) \ + and k.as_root() in self.coredata.options: + popt = self.coredata.options[k.as_root()] if type(opt) is type(popt): opt = popt else: @@ -1227,8 +1274,8 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str oi = optinterpreter.OptionInterpreter(self.subproject) oi.process(option_file) opts = oi.options - if self.coredata.is_native_clone: - opts = {k.as_build(): v for k, v in opts.items()} + if self.coredata.is_native_cross(): + opts = {k.as_native_cross(): v for k, v in opts.items()} self.coredata.update_project_options(opts) self.add_build_def_file(option_file) @@ -1353,8 +1400,11 @@ def func_add_languages(self, node: mparser.FunctionNode, args: T.Tuple[T.List[st for lang in sorted(langs, key=compilers.sort_clink): mlog.log('Compiler for language', mlog.bold(lang), 'skipped: feature', mlog.bold(feature), 'disabled') return False + if self.coredata.is_native_cross(): + return self.add_languages(langs, required, MachineChoice.BUILD) if native is not None: - return self.add_languages(langs, required, self.machine_from_native_kwarg(kwargs)) + for_machine = self.machine_from_native_kwarg(kwargs) + return self.add_languages(langs, required, for_machine) else: # absent 'native' means 'both' for backwards compatibility tv = FeatureNew.get_target_version(self.subproject) @@ -1506,7 +1556,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): def add_languages(self, args: T.List[str], required: bool, for_machine: MachineChoice) -> bool: success = self.add_languages_for(args, required, for_machine) - if not self.coredata.is_cross_build() and not self.coredata.is_native_clone: + if not self.coredata.is_cross_build() and not self.coredata.is_native_cross(): self.coredata.copy_build_options_from_regular_ones() self._redetect_machines() return success @@ -1789,7 +1839,7 @@ def func_find_program(self, node: mparser.BaseNode, args: T.Tuple[T.List[mesonli search_dirs = extract_search_dirs(kwargs) default_options = kwargs['default_options'] - return self.find_program_impl(args[0], self.kwarg_options_to_machine(kwargs), default_options=default_options, + return self.find_program_impl(args[0], kwargs['native'], default_options=default_options, required=required, silent=False, wanted=kwargs['version'], search_dirs=search_dirs) @@ -2434,7 +2484,9 @@ def func_subdir(self, node: mparser.BaseNode, args: T.Tuple[str], kwargs: 'kwtyp raise InvalidArguments(f'Tried to enter directory "{subdir}", which has already been visited.') self.processed_buildfiles.add(build_file) self.subdir = subdir - os.makedirs(os.path.join(self.environment.build_dir, subdir), exist_ok=True) + os.makedirs(os.path.join(self.environment.build_dir, + compute_build_subdir(subdir, self.coredata.is_native_cross())), + exist_ok=True) buildfilename = os.path.join(self.subdir, environment.build_filename) self.build_def_files.add(buildfilename) absname = os.path.join(self.environment.get_source_dir(), buildfilename) @@ -2861,7 +2913,7 @@ def build_incdir_object(self, incdir_strings: T.List[str], is_system: bool = Fal absdir_build = os.path.join(absbase_build, a) if not os.path.isdir(absdir_src) and not os.path.isdir(absdir_build): raise InvalidArguments(f'Include dir {a} does not exist.') - i = build.IncludeDirs(self.subdir, incdir_strings, is_system) + i = build.IncludeDirs(self.subdir, incdir_strings, is_system, self.coredata.is_native_cross()) return i @typed_pos_args('add_test_setup', str) @@ -2926,7 +2978,7 @@ def func_add_project_link_arguments(self, node: mparser.FunctionNode, args: T.Tu @typed_pos_args('add_project_dependencies', varargs=dependencies.Dependency) @typed_kwargs('add_project_dependencies', NATIVE_KW, LANGUAGE_KW) def func_add_project_dependencies(self, node: mparser.FunctionNode, args: T.Tuple[T.List[dependencies.Dependency]], kwargs: 'kwtypes.FuncAddProjectArgs') -> None: - for_machine = self.kwarg_options_to_machine(kwargs) + for_machine = kwargs['native'] for lang in kwargs['language']: if lang not in self.compilers[for_machine]: raise InvalidCode(f'add_project_dependencies() called before add_language() for language "{lang}"') @@ -3196,7 +3248,7 @@ def add_target(self, name: str, tobj: build.Target) -> None: # To permit an executable and a shared library to have the # same name, such as "foo.exe" and "libfoo.a". idname = tobj.get_id() - subdir = tobj.get_subdir() + subdir = compute_build_subdir(tobj.get_subdir(), self.coredata.is_native_cross()) namedir = (name, subdir) if idname in self.build.targets: @@ -3332,9 +3384,11 @@ def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargs targetclass: T.Type[T.Union[build.Executable, build.StaticLibrary, build.SharedModule, build.SharedLibrary, build.Jar]] ) -> T.Union[build.Executable, build.StaticLibrary, build.SharedModule, build.SharedLibrary, build.Jar]: name, sources = args - for_machine = self.kwarg_options_to_machine(kwargs) - if self.coredata.is_native_clone: + if self.coredata.is_native_cross(): + for_machine = MachineChoice.BUILD kwargs['install'] = False + else: + for_machine = kwargs['native'] if kwargs.get('rust_crate_type') == 'proc-macro': # Silently force to native because that's the only sensible value # and rust_crate_type is deprecated any way. @@ -3454,7 +3508,7 @@ def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargs return target def kwarg_options_to_machine(self, kwargs: kwtypes.FuncWithNativeArg) -> MachineChoice: - if self.coredata.is_native_clone: + if self.coredata.is_native_cross(): return MachineChoice.BUILD return kwargs['native'] diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index 4320cf52e924..9a20eb7b98df 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -13,7 +13,7 @@ from .. import mlog from ..modules import ModuleReturnValue, ModuleObject, ModuleState, ExtensionModule -from ..backend.backends import TestProtocol +from ..backend.backends import TestProtocol, compute_build_subdir from ..interpreterbase import ( ContainerTypeInfo, KwargInfo, MesonOperator, MesonInterpreterObject, ObjectHolder, MutableInterpreterObject, @@ -209,13 +209,16 @@ def __init__(self, subdir: str, mesonintrospect: T.List[str], in_builddir: bool = False, + is_native_cross: bool = False, check: bool = False, capture: bool = True) -> None: super().__init__() if not isinstance(cmd, ExternalProgram): raise AssertionError('BUG: RunProcess must be passed an ExternalProgram') self.capture = capture - self.returncode, self.stdout, self.stderr = self.run_command(cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check) + self.returncode, self.stdout, self.stderr = self.run_command(cmd, args, env, source_dir, build_dir, + subdir, mesonintrospect, in_builddir, + is_native_cross, check) self.methods.update({'returncode': self.returncode_method, 'stdout': self.stdout_method, 'stderr': self.stderr_method, @@ -230,6 +233,7 @@ def run_command(self, subdir: str, mesonintrospect: T.List[str], in_builddir: bool, + is_native_cross: bool, check: bool = False) -> T.Tuple[int, str, str]: command_array = cmd.get_command() + args menv = {'MESON_SOURCE_ROOT': source_dir, @@ -238,7 +242,7 @@ def run_command(self, 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in mesonintrospect]), } if in_builddir: - cwd = os.path.join(build_dir, subdir) + cwd = os.path.join(build_dir, compute_build_subdir(subdir, is_native_cross)) else: cwd = os.path.join(source_dir, subdir) child_env = os.environ.copy() @@ -891,7 +895,8 @@ def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: @noPosargs @noKwargs def private_dir_include_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> build.IncludeDirs: - return build.IncludeDirs('', [], False, [self.interpreter.backend.get_target_private_dir(self._target_object)]) + return build.IncludeDirs('', [], False, self.interpreter.coredata.is_native_cross(), + [self.interpreter.backend.get_target_private_dir(self._target_object)]) @noPosargs @noKwargs diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index 430d734c0eb3..b829cdfedeab 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -384,7 +384,7 @@ def _override_dependency_impl(self, name: str, dep: dependencies.Dependency, kwa else: nkwargs['static'] = static identifier = dependencies.get_dep_identifier(name, nkwargs) - for_machine = self.interpreter.kwarg_options_to_machine(kwargs) + for_machine = kwargs['native'] override = self.build.dependency_overrides[for_machine].get(identifier) if override: if permissive: diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index e7aeb8af1fb0..df34a60bf85f 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -53,6 +53,9 @@ def __init__(self, interpreter: 'Interpreter') -> None: self.project_args = interpreter.build.projects_args.host.get(interpreter.subproject, {}) self.current_node = interpreter.current_node + def is_native_cross(self) -> bool: + return self._interpreter.coredata.is_native_cross() + def get_include_args(self, include_dirs: T.Iterable[T.Union[str, build.IncludeDirs]], prefix: str = '-I') -> T.List[str]: if not include_dirs: return [] diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 9d6c1320991a..441762fb7342 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -2183,7 +2183,7 @@ def generate_vapi(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'Gener # - link with the correct library # - include the vapi and dependent vapi files in sources # - add relevant directories to include dirs - incs = [build.IncludeDirs(state.subdir, ['.'] + vapi_includes, False)] + incs = [build.IncludeDirs(state.subdir, ['.'] + vapi_includes, False, state.is_native_cross())] sources = [vapi_target] + vapi_depends rv = InternalDependency(None, incs, [], [], link_with, [], sources, [], [], {}, [], [], []) created_values.append(rv) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 3f9ce7b71e10..5107a4e439a3 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -610,6 +610,9 @@ def generate_libs_flags(libs: T.List[LIBS]) -> T.Iterable[str]: def generate(self, state: ModuleState, args: T.Tuple[T.Optional[T.Union[build.SharedLibrary, build.StaticLibrary]]], kwargs: GenerateKw) -> ModuleReturnValue: + if state.is_native_cross(): + return ModuleReturnValue(None, []) + default_version = state.project_version default_install_dir: T.Optional[str] = None default_description: T.Optional[str] = None diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index 29ae96b08548..b9e6079e850b 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -119,7 +119,8 @@ def compile_resources(self, state: 'ModuleState', for d in wrc_depends: if isinstance(d, build.CustomTarget): extra_args += state.get_include_args([ - build.IncludeDirs('', [], False, [os.path.join('@BUILD_ROOT@', self.interpreter.backend.get_target_dir(d))]) + build.IncludeDirs('', [], False, state.is_native_cross(), + [os.path.join('@BUILD_ROOT@', self.interpreter.backend.get_target_dir(d))]) ]) extra_args += state.get_include_args(kwargs['include_directories']) diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 4d7e0b52de3c..a73378eab1f3 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -2191,7 +2191,7 @@ def _classify_argument(key: 'OptionKey') -> OptionType: assert key.machine is MachineChoice.HOST, str(key) return OptionType.BACKEND else: - assert key.subproject or key.machine is MachineChoice.HOST, str(key) + assert key.machine is MachineChoice.HOST or key.subproject, str(key) return OptionType.PROJECT @@ -2355,6 +2355,12 @@ def as_host(self) -> 'OptionKey': """Convenience method for key.evolve(machine=MachineChoice.HOST).""" return self.evolve(machine=MachineChoice.HOST) + def as_native_cross(self) -> 'OptionKey': + """Transform to the appropriate key for the native machine in a cross scenario.""" + if self.is_backend(): + return self.as_host() + return self.as_build() + def is_backend(self) -> bool: """Convenience method to check if this is a backend option.""" return self.type is OptionType.BACKEND