1
Fork 0

linker: Stop using whole-archive on dependencies of dylibs

https://github.com/rust-lang/rust/pull/95604 implemented a better and more fine-grained way of keeping exported symbols alive.
This commit is contained in:
Vadim Petrochenkov 2022-04-26 16:56:38 +03:00
parent 082e4ca497
commit 73317f8b0d
3 changed files with 8 additions and 44 deletions

View file

@ -1920,7 +1920,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
// This change is somewhat breaking in practice due to local static libraries being linked // This change is somewhat breaking in practice due to local static libraries being linked
// as whole-archive (#85144), so removing whole-archive may be a pre-requisite. // as whole-archive (#85144), so removing whole-archive may be a pre-requisite.
if sess.opts.debugging_opts.link_native_libraries { if sess.opts.debugging_opts.link_native_libraries {
add_local_native_libraries(cmd, sess, codegen_results, crate_type); add_local_native_libraries(cmd, sess, codegen_results);
} }
// Upstream rust libraries and their nobundle static libraries // Upstream rust libraries and their nobundle static libraries
@ -2092,16 +2092,6 @@ fn add_order_independent_options(
add_rpath_args(cmd, sess, codegen_results, out_filename); add_rpath_args(cmd, sess, codegen_results, out_filename);
} }
// A dylib may reexport symbols from the linked rlib or native static library.
// Even if some symbol is reexported it's still not necessarily counted as used and may be
// dropped, at least with `ld`-like ELF linkers. So we have to link some rlibs and static
// libraries as whole-archive to avoid losing reexported symbols.
// FIXME: Find a way to mark reexported symbols as used and avoid this use of whole-archive.
fn default_to_whole_archive(sess: &Session, crate_type: CrateType, cmd: &dyn Linker) -> bool {
crate_type == CrateType::Dylib
&& !(sess.target.limit_rdylib_exports && cmd.exported_symbol_means_used_symbol())
}
/// # Native library linking /// # Native library linking
/// ///
/// User-supplied library search paths (-L on the command line). These are the same paths used to /// User-supplied library search paths (-L on the command line). These are the same paths used to
@ -2115,7 +2105,6 @@ fn add_local_native_libraries(
cmd: &mut dyn Linker, cmd: &mut dyn Linker,
sess: &Session, sess: &Session,
codegen_results: &CodegenResults, codegen_results: &CodegenResults,
crate_type: CrateType,
) { ) {
let filesearch = sess.target_filesearch(PathKind::All); let filesearch = sess.target_filesearch(PathKind::All);
for search_path in filesearch.search_paths() { for search_path in filesearch.search_paths() {
@ -2157,7 +2146,6 @@ fn add_local_native_libraries(
} }
NativeLibKind::Static { whole_archive, bundle, .. } => { NativeLibKind::Static { whole_archive, bundle, .. } => {
if whole_archive == Some(true) if whole_archive == Some(true)
|| (whole_archive == None && default_to_whole_archive(sess, crate_type, cmd))
// Backward compatibility case: this can be a rlib (so `+whole-archive` cannot // Backward compatibility case: this can be a rlib (so `+whole-archive` cannot
// be added explicitly if necessary, see the error in `fn link_rlib`) compiled // be added explicitly if necessary, see the error in `fn link_rlib`) compiled
// as an executable due to `--test`. Use whole-archive implicitly, like before // as an executable due to `--test`. Use whole-archive implicitly, like before
@ -2276,7 +2264,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
let src = &codegen_results.crate_info.used_crate_source[&cnum]; let src = &codegen_results.crate_info.used_crate_source[&cnum];
match data[cnum.as_usize() - 1] { match data[cnum.as_usize() - 1] {
_ if codegen_results.crate_info.profiler_runtime == Some(cnum) => { _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => {
add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum); add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, cnum);
} }
// compiler-builtins are always placed last to ensure that they're // compiler-builtins are always placed last to ensure that they're
// linked correctly. // linked correctly.
@ -2286,7 +2274,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
} }
Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::NotLinked | Linkage::IncludedFromDylib => {}
Linkage::Static => { Linkage::Static => {
add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum); add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, cnum);
// Link static native libs with "-bundle" modifier only if the crate they originate from // Link static native libs with "-bundle" modifier only if the crate they originate from
// is being linked statically to the current crate. If it's linked dynamically // is being linked statically to the current crate. If it's linked dynamically
@ -2317,10 +2305,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
lib.kind lib.kind
{ {
let verbatim = lib.verbatim.unwrap_or(false); let verbatim = lib.verbatim.unwrap_or(false);
if whole_archive == Some(true) if whole_archive == Some(true) {
|| (whole_archive == None
&& default_to_whole_archive(sess, crate_type, cmd))
{
cmd.link_whole_staticlib( cmd.link_whole_staticlib(
name, name,
verbatim, verbatim,
@ -2347,7 +2332,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
// was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic` // was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic`
// is used) // is used)
if let Some(cnum) = compiler_builtins { if let Some(cnum) = compiler_builtins {
add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum); add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, cnum);
} }
// Converts a library file-stem into a cc -l argument // Converts a library file-stem into a cc -l argument
@ -2378,23 +2363,13 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
sess: &'a Session, sess: &'a Session,
codegen_results: &CodegenResults, codegen_results: &CodegenResults,
tmpdir: &Path, tmpdir: &Path,
crate_type: CrateType,
cnum: CrateNum, cnum: CrateNum,
) { ) {
let src = &codegen_results.crate_info.used_crate_source[&cnum]; let src = &codegen_results.crate_info.used_crate_source[&cnum];
let cratepath = &src.rlib.as_ref().unwrap().0; let cratepath = &src.rlib.as_ref().unwrap().0;
let mut link_upstream = |path: &Path| { let mut link_upstream = |path: &Path| {
// We don't want to include the whole compiler-builtins crate (e.g., compiler-rt) cmd.link_rlib(&fix_windows_verbatim_for_gcc(path));
// regardless of the default because it'll get repeatedly linked anyway.
let path = fix_windows_verbatim_for_gcc(path);
if default_to_whole_archive(sess, crate_type, cmd)
&& codegen_results.crate_info.compiler_builtins != Some(cnum)
{
cmd.link_whole_rlib(&path);
} else {
cmd.link_rlib(&path);
}
}; };
// See the comment above in `link_staticlib` and `link_rlib` for why if // See the comment above in `link_staticlib` and `link_rlib` for why if

View file

@ -187,9 +187,6 @@ pub trait Linker {
fn no_crt_objects(&mut self); fn no_crt_objects(&mut self);
fn no_default_libraries(&mut self); fn no_default_libraries(&mut self);
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
fn exported_symbol_means_used_symbol(&self) -> bool {
true
}
fn subsystem(&mut self, subsystem: &str); fn subsystem(&mut self, subsystem: &str);
fn group_start(&mut self); fn group_start(&mut self);
fn group_end(&mut self); fn group_end(&mut self);
@ -728,10 +725,6 @@ impl<'a> Linker for GccLinker<'a> {
} }
} }
fn exported_symbol_means_used_symbol(&self) -> bool {
self.sess.target.is_like_windows || self.sess.target.is_like_osx
}
fn subsystem(&mut self, subsystem: &str) { fn subsystem(&mut self, subsystem: &str) {
self.linker_arg("--subsystem"); self.linker_arg("--subsystem");
self.linker_arg(&subsystem); self.linker_arg(&subsystem);
@ -1479,10 +1472,6 @@ impl<'a> Linker for L4Bender<'a> {
return; return;
} }
fn exported_symbol_means_used_symbol(&self) -> bool {
false
}
fn subsystem(&mut self, subsystem: &str) { fn subsystem(&mut self, subsystem: &str) {
self.cmd.arg(&format!("--subsystem {}", subsystem)); self.cmd.arg(&format!("--subsystem {}", subsystem));
} }

View file

@ -80,8 +80,8 @@ to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`.
The modifier does nothing for linkers that don't support it. The modifier does nothing for linkers that don't support it.
The default for this modifier is `-whole-archive`. \ The default for this modifier is `-whole-archive`. \
NOTE: The default may currently be different when building dylibs for some targets, NOTE: The default may currently be different in some cases for backward compatibility,
but it is not guaranteed. but it is not guaranteed. If you need whole archive semantics use `+whole-archive` explicitly.
<a id="option-crate-type"></a> <a id="option-crate-type"></a>
## `--crate-type`: a list of types of crates for the compiler to emit ## `--crate-type`: a list of types of crates for the compiler to emit