From a9432f120261641040f1cfbd07872992c31e9b63 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 20 Dec 2024 00:29:23 +0100 Subject: [PATCH 1/2] arglist: do not duplicate beginning and end of to_native Signed-off-by: Paolo Bonzini --- mesonbuild/arglist.py | 4 ++++ mesonbuild/compilers/mixins/clike.py | 24 +++++++----------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/mesonbuild/arglist.py b/mesonbuild/arglist.py index 54d7157e2ccf..413273b9aad3 100644 --- a/mesonbuild/arglist.py +++ b/mesonbuild/arglist.py @@ -219,6 +219,9 @@ def _can_dedup(cls, arg: str) -> Dedup: def _should_prepend(cls, arg: str) -> bool: return arg.startswith(cls.prepend_prefixes) + def to_native_inplace(self) -> None: + pass + def to_native(self, copy: bool = False) -> T.List[str]: # Check if we need to add --start/end-group for circular dependencies # between static libraries, and for recursively searching for symbols @@ -229,6 +232,7 @@ def to_native(self, copy: bool = False) -> T.List[str]: new = self.copy() else: new = self + new.to_native_inplace() return self.compiler.unix_args_to_native(new._container) def append_direct(self, arg: str) -> None: diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index d56547b475ed..823f4fde2a0a 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -57,26 +57,17 @@ class CLikeCompilerArgs(arglist.CompilerArgs): dedup1_suffixes = ('.lib', '.dll', '.so', '.dylib', '.a') dedup1_args = ('-c', '-S', '-E', '-pipe', '-pthread') - def to_native(self, copy: bool = False) -> T.List[str]: + def to_native_inplace(self) -> None: # This seems to be allowed, but could never work? assert isinstance(self.compiler, compilers.Compiler), 'How did you get here' - # Check if we need to add --start/end-group for circular dependencies - # between static libraries, and for recursively searching for symbols - # needed by static libraries that are provided by object files or - # shared libraries. - self.flush_pre_post() - if copy: - new = self.copy() - else: - new = self # This covers all ld.bfd, ld.gold, ld.gold, and xild on Linux, which # all act like (or are) gnu ld # TODO: this could probably be added to the DynamicLinker instead if isinstance(self.compiler.linker, (GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker)): group_start = -1 group_end = -1 - for i, each in enumerate(new): + for i, each in enumerate(self): if not GROUP_FLAGS.search(each): continue group_end = i @@ -86,20 +77,20 @@ def to_native(self, copy: bool = False) -> T.List[str]: # Only add groups if there are multiple libraries. if group_end > group_start >= 0: # Last occurrence of a library - new.insert(group_end + 1, '-Wl,--end-group') - new.insert(group_start, '-Wl,--start-group') + self.insert(group_end + 1, '-Wl,--end-group') + self.insert(group_start, '-Wl,--start-group') # Remove system/default include paths added with -isystem default_dirs = self.compiler.get_default_include_dirs() if default_dirs: real_default_dirs = [self._cached_realpath(i) for i in default_dirs] bad_idx_list: T.List[int] = [] - for i, each in enumerate(new): + for i, each in enumerate(self): if not each.startswith('-isystem'): continue # Remove the -isystem and the path if the path is a default path if each == '-isystem': - if i < (len(new) - 1) and self._cached_realpath(new[i + 1]) in real_default_dirs: + if i < (len(self) - 1) and self._cached_realpath(self[i + 1]) in real_default_dirs: bad_idx_list += [i, i + 1] elif each.startswith('-isystem='): if self._cached_realpath(each[9:]) in real_default_dirs: @@ -107,8 +98,7 @@ def to_native(self, copy: bool = False) -> T.List[str]: elif self._cached_realpath(each[8:]) in real_default_dirs: bad_idx_list += [i] for i in reversed(bad_idx_list): - new.pop(i) - return self.compiler.unix_args_to_native(new._container) + self.pop(i) @staticmethod @functools.lru_cache(maxsize=None) From ad185307e36a2e6319e023c77111c97f88cc38ad Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 20 Dec 2024 00:35:24 +0100 Subject: [PATCH 2/2] rust: add start-group/end-group arguments for libraries Signed-off-by: Paolo Bonzini --- mesonbuild/compilers/rust.py | 38 +++++++++++++++++++ test cases/rust/27 staticlib group/lib1.c | 11 ++++++ test cases/rust/27 staticlib group/lib1.h | 4 ++ test cases/rust/27 staticlib group/lib2.c | 8 ++++ test cases/rust/27 staticlib group/lib2.h | 3 ++ test cases/rust/27 staticlib group/main.c | 6 +++ test cases/rust/27 staticlib group/main.rs | 9 +++++ .../rust/27 staticlib group/meson.build | 13 +++++++ 8 files changed, 92 insertions(+) create mode 100644 test cases/rust/27 staticlib group/lib1.c create mode 100644 test cases/rust/27 staticlib group/lib1.h create mode 100644 test cases/rust/27 staticlib group/lib2.c create mode 100644 test cases/rust/27 staticlib group/lib2.h create mode 100644 test cases/rust/27 staticlib group/main.c create mode 100644 test cases/rust/27 staticlib group/main.rs create mode 100644 test cases/rust/27 staticlib group/meson.build diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index 717d5635f842..5a64e09279bd 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -9,10 +9,13 @@ import re import typing as T +from .. import arglist from .. import options +from ..linkers.linkers import GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker from ..mesonlib import EnvironmentException, MesonException, Popen_safe_logged from ..options import OptionKey from .compilers import Compiler, clike_debug_args +from .mixins.clike import GROUP_FLAGS if T.TYPE_CHECKING: from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType @@ -62,6 +65,37 @@ def get_rustup_run_and_args(exelist: T.List[str]) -> T.Optional[T.Tuple[T.List[s except StopIteration: return None + +class RustcCompilerArgs(arglist.CompilerArgs): + def to_native_inplace(self) -> None: + assert isinstance(self.compiler, RustCompiler), 'How did you get here' + + # Check if we need to add --start/end-group for circular dependencies + # between static libraries, and for recursively searching for symbols + # needed by static libraries that are provided by object files or + # shared libraries. + # This covers all ld.bfd, ld.gold, ld.gold, and xild on Linux, which + # all act like (or are) gnu ld + if isinstance(self.compiler.linker, (GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker)): + group_start = -1 + group_end = -1 + last_rustc_arg = -1 + for i, each in enumerate(self): + if each in {'--emit', '-o', '--extern'}: + last_rustc_arg = i + if last_rustc_arg == i - 1 or not GROUP_FLAGS.search(each): + continue + group_end = i + if group_start < 0: + # First occurrence of a library + group_start = i + # Only add groups if there are multiple libraries. + if group_end > group_start >= 0: + # Last occurrence of a library + self.insert(group_end + 1, '-Clink-arg=-Wl,--end-group') + self.insert(group_start, '-Clink-arg=-Wl,--start-group') + + class RustCompiler(Compiler): # rustc doesn't invoke the compiler itself, it doesn't need a LINKER_PREFIX @@ -100,6 +134,10 @@ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoic self.base_options.add(OptionKey('b_vscrt')) self.native_static_libs: T.List[str] = [] + def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> RustcCompilerArgs: + # This is correct, mypy just doesn't understand co-operative inheritance + return RustcCompilerArgs(self, args) + def needs_static_linker(self) -> bool: return False diff --git a/test cases/rust/27 staticlib group/lib1.c b/test cases/rust/27 staticlib group/lib1.c new file mode 100644 index 000000000000..8e759852e190 --- /dev/null +++ b/test cases/rust/27 staticlib group/lib1.c @@ -0,0 +1,11 @@ +#include +#include "lib1.h" +#include "lib2.h" + +void from_lib2(void) { + printf("hello world"); +} + +void c_func(void) { + from_lib1(); +} diff --git a/test cases/rust/27 staticlib group/lib1.h b/test cases/rust/27 staticlib group/lib1.h new file mode 100644 index 000000000000..8bb18d4bbe4e --- /dev/null +++ b/test cases/rust/27 staticlib group/lib1.h @@ -0,0 +1,4 @@ +#pragma once + +void from_lib2(void); +void c_func(void); diff --git a/test cases/rust/27 staticlib group/lib2.c b/test cases/rust/27 staticlib group/lib2.c new file mode 100644 index 000000000000..a61d5349f878 --- /dev/null +++ b/test cases/rust/27 staticlib group/lib2.c @@ -0,0 +1,8 @@ +#include +#include "lib1.h" +#include "lib2.h" + +void from_lib1(void) +{ + from_lib2(); +} diff --git a/test cases/rust/27 staticlib group/lib2.h b/test cases/rust/27 staticlib group/lib2.h new file mode 100644 index 000000000000..08c4cd30ad1e --- /dev/null +++ b/test cases/rust/27 staticlib group/lib2.h @@ -0,0 +1,3 @@ +#pragma once + +void from_lib1(void); diff --git a/test cases/rust/27 staticlib group/main.c b/test cases/rust/27 staticlib group/main.c new file mode 100644 index 000000000000..f96ba6687221 --- /dev/null +++ b/test cases/rust/27 staticlib group/main.c @@ -0,0 +1,6 @@ +#include "lib1.h" +#include "lib2.h" + +void main() { + c_func(); +} diff --git a/test cases/rust/27 staticlib group/main.rs b/test cases/rust/27 staticlib group/main.rs new file mode 100644 index 000000000000..538359943271 --- /dev/null +++ b/test cases/rust/27 staticlib group/main.rs @@ -0,0 +1,9 @@ +extern "C" { + fn c_func(); +} + +fn main() { + unsafe { + c_func(); + } +} diff --git a/test cases/rust/27 staticlib group/meson.build b/test cases/rust/27 staticlib group/meson.build new file mode 100644 index 000000000000..a83f0834c5fe --- /dev/null +++ b/test cases/rust/27 staticlib group/meson.build @@ -0,0 +1,13 @@ +project('staticlib group', 'c', 'rust') + +ld_bfd = find_program('ld.bfd') +if not ld_bfd.found() + error('MESON_SKIP_TEST ld.bfd not found') +endif + +lib1 = static_library('lib1', 'lib1.c') +lib2 = static_library('lib2', 'lib2.c') +executable('lib1first', 'main.rs', link_with : [lib1, lib2], + rust_args: ['-C', 'lto=n', '-C', 'linker-plugin-lto=n', '-Clink-arg=-fuse-ld=bfd']) +executable('lib2first', 'main.rs', link_with : [lib2, lib1], + rust_args: ['-C', 'lto=n', '-C', 'linker-plugin-lto=n', '-Clink-arg=-fuse-ld=bfd'])