From 6e466e54d933ad052a2321df576a0a985a7f29a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Wed, 7 Feb 2024 13:23:39 +0100 Subject: [PATCH] [WIP] SQUASHME --- mesonbuild/build.py | 27 +++++++++---- mesonbuild/coredata.py | 22 +++++++++++ mesonbuild/environment.py | 39 +++++++++++++++++++ mesonbuild/interpreter/dependencyfallbacks.py | 1 + mesonbuild/interpreter/interpreter.py | 33 ++++++++++------ mesonbuild/interpreter/mesonmain.py | 7 +++- 6 files changed, 107 insertions(+), 22 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 863b5aaa3e8b..fe94d87a717d 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -291,12 +291,22 @@ def get_custom_targets(self): def copy(self) -> Build: other = Build(self.environment) + self._copy_to(other) + return other + + def copy_to_native(self) -> Build: + other = Build(self.environment.copy_to_native()) + self._copy_to(other) + return other + + def _copy_to(self, other: Build) -> None: for k, v in self.__dict__.items(): + if k == 'environment': + continue if isinstance(v, (list, dict, set, OrderedDict)): other.__dict__[k] = v.copy() else: other.__dict__[k] = v - return other def merge(self, other: Build) -> None: for k, v in other.__dict__.items(): @@ -307,7 +317,7 @@ def ensure_static_linker(self, compiler: Compiler) -> None: self.static_linker[compiler.for_machine] = detect_static_linker(self.environment, compiler) def get_project(self): - return self.projects[''] + return self.projects[('', MachineChoice.HOST)] def get_subproject_dir(self): return self.subproject_dir @@ -596,7 +606,7 @@ def get_basename(self) -> str: return self.name def get_subdir(self) -> str: - return self.subdir + return self.environment.build_output_rpath(self.subdir) def get_typename(self) -> str: return self.typename @@ -612,7 +622,7 @@ def _get_id_hash(target_id: str) -> str: return h.hexdigest()[:7] @staticmethod - def construct_id_from_path(subdir: str, name: str, type_suffix: str) -> str: + def construct_id_from_path(subdir: str, name: str, type_suffix: str, extra_suffix: str = '') -> str: """Construct target ID from subdir, name and type suffix. This helper function is made public mostly for tests.""" @@ -623,7 +633,7 @@ def construct_id_from_path(subdir: str, name: str, type_suffix: str) -> str: # FIXME replace with assert when slash in names is prohibited name_part = name.replace('/', '@').replace('\\', '@') assert not has_path_sep(type_suffix) - my_id = name_part + type_suffix + my_id = name_part + type_suffix + extra_suffix if subdir: subdir_part = Target._get_id_hash(subdir) # preserve myid for better debuggability @@ -635,7 +645,7 @@ 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()) + self.subdir, name, self.type_suffix(), '@native' if self.environment.is_native_clone else '') def process_kwargs_base(self, kwargs: T.Dict[str, T.Any]) -> None: if 'build_by_default' in kwargs: @@ -1481,8 +1491,9 @@ 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 t.subproject and not self.environment.is_cross_build(): - return + # XXX: Do we still need this? + #if 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(): diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index a6a14c8abf56..573822c9c1ae 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -586,6 +586,28 @@ def __init__(self, options: argparse.Namespace, scratch_dir: str, meson_command: self.builtin_options_libdir_cross_fixup() self.init_builtins('') + def copy_to_native(self) -> CoreData: + other = CoreData.__new__(CoreData) + for k, v in self.__dict__.items(): + other.__dict__[k] = v + + # TODO: Copy options + + other.cross_files = [] + + other.compilers = PerMachine(OrderedDict(), OrderedDict()) + other.compilers.build = self.compilers.build + + other.deps = PerMachineDefaultable.default( + is_cross=False, + build=self.deps.build, + host=self.deps.host) + + self.compiler_check_cache.clear() + self.run_check_cache.clear() + + return other + @staticmethod def __load_config_files(options: argparse.Namespace, scratch_dir: str, ftype: str) -> T.List[str]: # Need to try and make the passed filenames absolute because when the diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 326a1c9ede52..08c4abb6497c 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -620,6 +620,39 @@ def __init__(self, source_dir: str, build_dir: str, options: 'argparse.Namespace self.default_pkgconfig = ['pkg-config'] self.wrap_resolver: T.Optional['Resolver'] = None + self.is_native_clone = False + + def copy_to_native(self) -> Build: + other = Environment.__new__(Environment) + for k, v in self.__dict__.items(): + other.__dict__[k] = v + + other.coredata = self.coredata.copy_to_native() + + machines: PerThreeMachineDefaultable[MachineInfo] = PerThreeMachineDefaultable() + machines.build = self.machines.build + other.machines = machines.default_missing() + + binaries: PerMachineDefaultable[BinaryTable] = PerMachineDefaultable() + binaries.build = self.binaries.build + other.binaries = binaries.default_missing() + + properties: PerMachineDefaultable[Properties] = PerMachineDefaultable() + properties.build = self.properties.build + other.properties = properties.default_missing() + + cmakevars: PerMachineDefaultable[CMakeVariables] = PerMachineDefaultable() + cmakevars.build = self.cmakevars.build + other.cmakevars = cmakevars.default_missing() + + # TODO: Copy options + + other.exe_wrapper = None + + other.is_native_clone = True + + return other + def _load_machine_file_options(self, config: 'ConfigParser', properties: Properties, machine: MachineChoice) -> None: """Read the contents of a Machine file and put it in the options store.""" @@ -841,6 +874,12 @@ def get_source_dir(self) -> str: 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.is_native_clone: + result += '-native' + return os.path.join(result, *parts) + def get_import_lib_dir(self) -> str: "Install dir for the import library (library used for linking)" return self.get_libdir() diff --git a/mesonbuild/interpreter/dependencyfallbacks.py b/mesonbuild/interpreter/dependencyfallbacks.py index 544bba1c0670..239d5e37ec16 100644 --- a/mesonbuild/interpreter/dependencyfallbacks.py +++ b/mesonbuild/interpreter/dependencyfallbacks.py @@ -127,6 +127,7 @@ def _do_subproject(self, kwargs: TYPE_nkwargs, func_args: TYPE_nvar, func_kwargs func_kwargs.setdefault('version', []) if 'default_options' in kwargs and isinstance(kwargs['default_options'], str): func_kwargs['default_options'] = listify(kwargs['default_options']) + func_kwargs.setdefault('native', kwargs.get('native', False)) self.interpreter.do_subproject(subp_name, func_kwargs) return self._get_subproject_dep(subp_name, varname, kwargs) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index e7f4b809c958..81da6550e328 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -17,7 +17,7 @@ from .. import mesonlib from ..mesonlib import (EnvironmentVariables, ExecutableSerialisation, MesonBugException, MesonException, HoldableObject, FileMode, MachineChoice, OptionKey, listify, - extract_as_list, has_path_sep, path_is_in_root, PerMachine) + extract_as_list, has_path_sep, path_is_in_root, PerMachine, PerThreeMachineDefaultable) from ..programs import ExternalProgram, NonExistingExternalProgram from ..dependencies import Dependency from ..depfile import DepFile @@ -271,7 +271,7 @@ def __init__( _build: build.Build, backend: T.Optional[Backend] = None, subp_name: str = '', - subp_id: str = '', + subp_id: T.Tuple[str, MachineChoice] = ('', MachineChoice.HOST), subdir: str = '', subproject_dir: str = 'subprojects', default_project_options: T.Optional[T.Dict[OptionKey, str]] = None, @@ -966,7 +966,8 @@ def _do_subproject_meson(self, subp_name: str, subp_id: str, subdir: str, 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)) + native = kwargs.get('native', False) + subp_id = self._make_subproject_id(subp_name, native) with mlog.nested(subp_name): if ast: @@ -982,7 +983,10 @@ 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) - new_build = self.build.copy() + if native and self.coredata.is_cross_build(): + new_build = self.build.copy_to_native() + else: + new_build = self.build.copy() 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, @@ -1274,7 +1278,7 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str proj_license_files.append((ifname, i)) self.build.dep_manifest[proj_name] = build.DepManifest(self.project_version, proj_license, proj_license_files, self.subproject) - if self.subproject in self.build.projects: + if self.subp_id in self.build.projects: raise InvalidCode('Second call to project().') # spdirname is the subproject_dir for this project, relative to self.subdir. @@ -1302,7 +1306,7 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str else: self.environment.wrap_resolver = r - self.build.projects[self.subproject] = proj_name + self.build.projects[self.subp_id] = proj_name mlog.log('Project name:', mlog.bold(proj_name)) mlog.log('Project version:', mlog.bold(self.project_version)) @@ -1424,7 +1428,7 @@ def _print_summary(self) -> None: self.summary_impl('User defined options', values, {'bool_yn': False, 'list_sep': None}) # Print all summaries, main project last. mlog.log('') # newline - main_summary = self.summary.pop('', None) + main_summary = self.summary.pop(('', MachineChoice.HOST), None) is_cross_build = self.coredata.is_cross_build() for subp_id, summary in sorted(self.summary.items()): if self.subprojects[subp_id].found(): @@ -2644,7 +2648,7 @@ def func_configure_file(self, node: mparser.BaseNode, args: T.List[TYPE_var], output = outputs[0] if depfile: depfile = mesonlib.substitute_values([depfile], values)[0] - ofile_rpath = os.path.join(self.subdir, output) + ofile_rpath = self.environment.build_output_rpath(self.subdir, output) if ofile_rpath in self.configure_file_outputs: mesonbuildfile = os.path.join(self.subdir, 'meson.build') current_call = f"{mesonbuildfile}:{self.current_lineno}" @@ -2652,9 +2656,11 @@ def func_configure_file(self, node: mparser.BaseNode, args: T.List[TYPE_var], mlog.warning('Output file', mlog.bold(ofile_rpath, True), 'for configure_file() at', current_call, 'overwrites configure_file() output at', first_call) else: self.configure_file_outputs[ofile_rpath] = self.current_lineno - (ofile_path, ofile_fname) = os.path.split(os.path.join(self.subdir, output)) + (ofile_path, ofile_fname) = os.path.split(ofile_rpath) ofile_abs = os.path.join(self.environment.build_dir, ofile_path, ofile_fname) + output_subdir = self.environment.build_output_rpath(self.subdir) + # Perform the appropriate action if kwargs['configuration'] is not None: conf = kwargs['configuration'] @@ -2668,8 +2674,8 @@ def func_configure_file(self, node: mparser.BaseNode, args: T.List[TYPE_var], mlog.log('Configuring', mlog.bold(output), 'using configuration') if len(inputs) > 1: raise InterpreterException('At most one input file can given in configuration mode') + os.makedirs(os.path.join(self.environment.build_dir, output_subdir), exist_ok=True) if inputs: - os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True) file_encoding = kwargs['encoding'] missing_variables, confdata_useless = \ mesonlib.do_conf_file(inputs_abs[0], ofile_abs, conf, @@ -2727,7 +2733,7 @@ def func_configure_file(self, node: mparser.BaseNode, args: T.List[TYPE_var], elif kwargs['copy']: if len(inputs_abs) != 1: raise InterpreterException('Exactly one input file must be given in copy mode') - os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True) + os.makedirs(os.path.join(self.environment.build_dir, output_subdir), exist_ok=True) shutil.copy2(inputs_abs[0], ofile_abs) # Install file if requested, we check for the empty string @@ -2750,7 +2756,7 @@ def func_configure_file(self, node: mparser.BaseNode, args: T.List[TYPE_var], install_tag = kwargs['install_tag'] self.build.data.append(build.Data([cfile], idir, idir_name, install_mode, self.subproject, install_tag=install_tag, data_type='configure')) - return mesonlib.File.from_built_file(self.subdir, output) + return mesonlib.File.from_built_file(output_subdir, output) def extract_incdirs(self, kwargs, key: str = 'include_directories') -> T.List[build.IncludeDirs]: prospectives = extract_as_list(kwargs, key) @@ -3186,6 +3192,9 @@ def add_target(self, name: str, tobj: build.Target) -> None: FeatureNew.single_use(f'multiple executables with the same name, "{tobj.name}", but different suffixes in the same directory', '1.3.0', self.subproject, location=self.current_node) + if self.environment.is_native_clone and hasattr(tobj, 'for_machine'): + tobj.for_machine = MachineChoice.BUILD + if isinstance(tobj, build.BuildTarget): self.add_languages(tobj.missing_languages, True, tobj.for_machine) tobj.process_compilers_late() diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index 4d1f427da210..ea0123538d88 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -220,7 +220,7 @@ def current_build_dir_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwarg sub = self.interpreter.subdir if sub == '': return src - return os.path.join(src, sub) + return os.path.join(src, self.interpreter.environment.build_output_rpath(sub)) @noPosargs @noKwargs @@ -384,7 +384,10 @@ def _override_dependency_impl(self, name: str, dep: dependencies.Dependency, kwa else: nkwargs['static'] = static identifier = dependencies.get_dep_identifier(name, nkwargs) - for_machine = kwargs['native'] + if self.interpreter.environment.is_native_clone: + for_machine = MachineChoice.BUILD + else: + for_machine = kwargs['native'] override = self.build.dependency_overrides[for_machine].get(identifier) if override: if permissive: