diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 7d1511633e2b..cd7f45e0ac4c 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -1128,3 +1128,10 @@ def add_lang_args(self, lang: str, comp: T.Type['Compiler'], # This is how autotools works, and the env vars feature is for # autotools compatibility. largs.extend_value(comp_options) + + def can_run_host_binaries(self) -> bool: + return not ( + self.is_cross_build() and + self.need_exe_wrapper() and + self.exe_wrapper is None + ) diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index 602575c57d03..4c46e883106f 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -258,21 +258,14 @@ def global_build_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwarg @FeatureDeprecated('meson.has_exe_wrapper', '0.55.0', 'use meson.can_run_host_binaries instead.') @InterpreterObject.method('has_exe_wrapper') def has_exe_wrapper_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: - return self._can_run_host_binaries_impl() + return self.build.environment.can_run_host_binaries() @noPosargs @noKwargs @FeatureNew('meson.can_run_host_binaries', '0.55.0') @InterpreterObject.method('can_run_host_binaries') def can_run_host_binaries_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: - return self._can_run_host_binaries_impl() - - def _can_run_host_binaries_impl(self) -> bool: - return not ( - self.build.environment.is_cross_build() and - self.build.environment.need_exe_wrapper() and - self.build.environment.exe_wrapper is None - ) + return self.build.environment.can_run_host_binaries() @noPosargs @noKwargs diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index a905f0667bff..5d8d4592a6a5 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -561,11 +561,11 @@ def get_output_args(self, target: str) -> T.List[str]: def get_linker_always_args(self) -> T.List[str]: return ['-r'] -def prepare_rpaths(raw_rpaths: T.Tuple[str, ...], build_dir: str, from_dir: str) -> T.List[str]: +def prepare_rpaths(env: Environment, raw_rpaths: T.Tuple[str, ...], build_dir: str, from_dir: str) -> T.List[str]: # The rpaths we write must be relative if they point to the build dir, # because otherwise they have different length depending on the build # directory. This breaks reproducible builds. - internal_format_rpaths = [evaluate_rpath(p, build_dir, from_dir) for p in raw_rpaths] + internal_format_rpaths = [evaluate_rpath(env, p, build_dir, from_dir) for p in raw_rpaths] ordered_rpaths = order_rpaths(internal_format_rpaths) return ordered_rpaths @@ -582,11 +582,16 @@ def order_rpaths(rpath_list: T.List[str]) -> T.List[str]: return sorted(rpath_list, key=os.path.isabs) -def evaluate_rpath(p: str, build_dir: str, from_dir: str) -> str: +def evaluate_rpath(env: Environment, p: str, build_dir: str, from_dir: str) -> str: if p == from_dir: return '' # relpath errors out in this case elif os.path.isabs(p): - return p # These can be outside of build dir. + if env.can_run_host_binaries(): + return p # These can be outside of build dir. + # Skip external library if we can't run binaries on host system. + # (cross-compilation and no exe_wrapper) + else: + return '' else: return os.path.relpath(os.path.join(build_dir, p), os.path.join(build_dir, from_dir)) @@ -714,7 +719,7 @@ def build_rpath_args(self, env: Environment, build_dir: str, from_dir: str, return ([], set()) args: T.List[str] = [] origin_placeholder = '$ORIGIN' - processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir) + processed_rpaths = prepare_rpaths(env, rpath_paths, build_dir, from_dir) # Need to deduplicate rpaths, as macOS's install_name_tool # is *very* allergic to duplicate -delete_rpath arguments # when calling depfixer on installation. @@ -724,9 +729,13 @@ def build_rpath_args(self, env: Environment, build_dir: str, from_dir: str, rpath_dirs_to_remove.add(p.encode('utf8')) # Build_rpath is used as-is (it is usually absolute). if target.build_rpath != '': - all_paths.add(target.build_rpath) - for p in target.build_rpath.split(':'): - rpath_dirs_to_remove.add(p.encode('utf8')) + paths = target.build_rpath.split(':') + for p in paths: + # Only include relative paths if we can't run binaries on host system. + # (cross-compilation and no exe_wrapper) + if env.can_run_host_binaries() or not os.path.isabs(p): + all_paths.add(p) + rpath_dirs_to_remove.add(p.encode('utf8')) if extra_paths: all_paths.update(extra_paths) @@ -886,10 +895,15 @@ def build_rpath_args(self, env: Environment, build_dir: str, from_dir: str, # @loader_path is the equivalent of $ORIGIN on macOS # https://stackoverflow.com/q/26280738 origin_placeholder = '@loader_path' - processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir) + processed_rpaths = prepare_rpaths(env, rpath_paths, build_dir, from_dir) all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths]) if target.build_rpath != '': - all_paths.update(target.build_rpath.split(':')) + paths = target.build_rpath.split(':') + for p in paths: + # Only include relative paths if we can't run binaries on host system. + # (cross-compilation and no exe_wrapper) + if env.can_run_host_binaries() or not os.path.isabs(p): + all_paths.add(p) if extra_paths: all_paths.update(extra_paths) for rp in all_paths: @@ -1268,10 +1282,15 @@ def build_rpath_args(self, env: Environment, build_dir: str, from_dir: str, return ([], set()) args: T.List[str] = [] origin_placeholder = '$ORIGIN' - processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir) + processed_rpaths = prepare_rpaths(env, rpath_paths, build_dir, from_dir) all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths]) if target.build_rpath != '': - all_paths.add(target.build_rpath) + paths = target.build_rpath.split(':') + for p in paths: + # Only include relative paths if we can't run binaries on host system. + # (cross-compilation and no exe_wrapper) + if env.can_run_host_binaries() or not os.path.isabs(p): + all_paths.add(p) if extra_paths: all_paths.update(extra_paths) for rp in all_paths: @@ -1524,15 +1543,19 @@ def build_rpath_args(self, env: Environment, build_dir: str, from_dir: str, rpath_paths = target.determine_rpath_dirs() if not rpath_paths and not target.install_rpath and not target.build_rpath and not extra_paths: return ([], set()) - processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir) + processed_rpaths = prepare_rpaths(env, rpath_paths, build_dir, from_dir) all_paths = mesonlib.OrderedSet([os.path.join('$ORIGIN', p) for p in processed_rpaths]) rpath_dirs_to_remove: T.Set[bytes] = set() for p in all_paths: rpath_dirs_to_remove.add(p.encode('utf8')) if target.build_rpath != '': - all_paths.add(target.build_rpath) - for p in target.build_rpath.split(':'): - rpath_dirs_to_remove.add(p.encode('utf8')) + paths = target.build_rpath.split(':') + for p in paths: + # Only include relative paths if we can't run binaries on host system. + # (cross-compilation and no exe_wrapper) + if env.can_run_host_binaries() or not os.path.isabs(p): + all_paths.add(p) + rpath_dirs_to_remove.add(p.encode('utf8')) if extra_paths: all_paths.update(extra_paths) @@ -1598,7 +1621,12 @@ def build_rpath_args(self, env: Environment, build_dir: str, from_dir: str, if target.install_rpath != '': all_paths.add(target.install_rpath) if target.build_rpath != '': - all_paths.add(target.build_rpath) + paths = target.build_rpath.split(':') + for p in paths: + # Only include relative paths if we can't run binaries on host system. + # (cross-compilation and no exe_wrapper) + if env.can_run_host_binaries() or not os.path.isabs(p): + all_paths.add(p) for p in target.determine_rpath_dirs(): all_paths.add(os.path.join(build_dir, p)) # We should consider allowing the $LIBPATH environment variable