Skip to content

Commit 3e3c23b

Browse files
committed
[WIP] Native library linking changes for crater testing
- Enable `-Zpacked-bundled-libs` by default - Preserve order of `-l` options from upstream crates, including dynamic libraries
1 parent c078410 commit 3e3c23b

File tree

13 files changed

+114
-168
lines changed

13 files changed

+114
-168
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 83 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,15 +2031,6 @@ fn linker_with_args<'a>(
20312031
tmpdir,
20322032
);
20332033

2034-
// Dynamic native libraries from upstream crates.
2035-
//
2036-
// FIXME: Merge this to `add_upstream_rust_crates` so that all native libraries are linked
2037-
// together with their respective upstream crates, and in their originally specified order.
2038-
// This may be slightly breaking due to our use of `--as-needed` and needs a crater run.
2039-
if sess.opts.unstable_opts.link_native_libraries {
2040-
add_upstream_native_libraries(cmd, sess, codegen_results);
2041-
}
2042-
20432034
// Link with the import library generated for any raw-dylib functions.
20442035
for (raw_dylib_name, raw_dylib_imports) in
20452036
collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
@@ -2375,7 +2366,8 @@ fn add_upstream_rust_crates<'a>(
23752366
// appear statically in an existing dylib, meaning we'll pick up all the
23762367
// symbols from the dylib.
23772368
let src = &codegen_results.crate_info.used_crate_source[&cnum];
2378-
match data[cnum.as_usize() - 1] {
2369+
let linkage = data[cnum.as_usize() - 1];
2370+
match linkage {
23792371
_ if codegen_results.crate_info.profiler_runtime == Some(cnum) => {
23802372
add_static_crate(
23812373
cmd,
@@ -2412,89 +2404,96 @@ fn add_upstream_rust_crates<'a>(
24122404
cnum,
24132405
&bundled_libs,
24142406
);
2407+
}
2408+
Linkage::Dynamic => add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0),
2409+
}
24152410

2416-
// Link static native libs with "-bundle" modifier only if the crate they originate from
2417-
// is being linked statically to the current crate. If it's linked dynamically
2418-
// or is an rlib already included via some other dylib crate, the symbols from
2419-
// native libs will have already been included in that dylib.
2420-
//
2421-
// If `-Zlink-native-libraries=false` is set, then the assumption is that an
2422-
// external build system already has the native dependencies defined, and it
2423-
// will provide them to the linker itself.
2424-
if sess.opts.unstable_opts.link_native_libraries {
2425-
if sess.opts.unstable_opts.packed_bundled_libs {
2426-
// If rlib contains native libs as archives, unpack them to tmpdir.
2427-
let rlib = &src.rlib.as_ref().unwrap().0;
2428-
archive_builder_builder
2429-
.extract_bundled_libs(rlib, tmpdir, &bundled_libs)
2430-
.unwrap_or_else(|e| sess.fatal(e));
2431-
}
2411+
if sess.opts.unstable_opts.link_native_libraries {
2412+
if linkage == Linkage::Static && sess.opts.unstable_opts.packed_bundled_libs {
2413+
let bundled_libs = if sess.opts.unstable_opts.packed_bundled_libs {
2414+
codegen_results.crate_info.native_libraries[&cnum]
2415+
.iter()
2416+
.filter_map(|lib| lib.filename)
2417+
.collect::<FxHashSet<_>>()
2418+
} else {
2419+
Default::default()
2420+
};
2421+
// If rlib contains native libs as archives, unpack them to tmpdir.
2422+
let rlib = &src.rlib.as_ref().unwrap().0;
2423+
archive_builder_builder
2424+
.extract_bundled_libs(rlib, tmpdir, &bundled_libs)
2425+
.unwrap_or_else(|e| sess.fatal(e));
2426+
}
24322427

2433-
let mut last = (None, NativeLibKind::Unspecified, None);
2434-
for lib in &codegen_results.crate_info.native_libraries[&cnum] {
2435-
let Some(name) = lib.name else {
2436-
continue;
2437-
};
2438-
let name = name.as_str();
2439-
if !relevant_lib(sess, lib) {
2440-
continue;
2441-
}
2428+
let mut last = (None, NativeLibKind::Unspecified, None);
2429+
for lib in &codegen_results.crate_info.native_libraries[&cnum] {
2430+
let Some(name) = lib.name else {
2431+
continue;
2432+
};
2433+
let name = name.as_str();
2434+
if !relevant_lib(sess, lib) {
2435+
continue;
2436+
}
24422437

2443-
// Skip if this library is the same as the last.
2444-
last = if (lib.name, lib.kind, lib.verbatim) == last {
2445-
continue;
2446-
} else {
2447-
(lib.name, lib.kind, lib.verbatim)
2448-
};
2449-
2450-
match lib.kind {
2451-
NativeLibKind::Static {
2452-
bundle: Some(false),
2453-
whole_archive: Some(true),
2454-
} => {
2455-
cmd.link_whole_staticlib(
2456-
name,
2457-
lib.verbatim.unwrap_or(false),
2458-
search_path.get_or_init(|| archive_search_paths(sess)),
2459-
);
2460-
}
2461-
NativeLibKind::Static {
2462-
bundle: Some(false),
2463-
whole_archive: Some(false) | None,
2464-
} => {
2465-
// HACK/FIXME: Fixup a circular dependency between libgcc and libc
2466-
// with glibc. This logic should be moved to the libc crate.
2467-
if sess.target.os == "linux"
2468-
&& sess.target.env == "gnu"
2469-
&& name == "c"
2470-
{
2471-
cmd.link_staticlib("gcc", false);
2472-
}
2473-
cmd.link_staticlib(name, lib.verbatim.unwrap_or(false));
2474-
}
2475-
NativeLibKind::LinkArg => {
2476-
cmd.arg(name);
2438+
// Skip if this library is the same as the last.
2439+
last = if (lib.name, lib.kind, lib.verbatim) == last {
2440+
continue;
2441+
} else {
2442+
(lib.name, lib.kind, lib.verbatim)
2443+
};
2444+
2445+
let verbatim = lib.verbatim.unwrap_or(false);
2446+
match lib.kind {
2447+
NativeLibKind::Static { bundle: Some(false), whole_archive: Some(true) } => {
2448+
if linkage == Linkage::Static {
2449+
cmd.link_whole_staticlib(
2450+
name,
2451+
verbatim,
2452+
search_path.get_or_init(|| archive_search_paths(sess)),
2453+
);
2454+
}
2455+
}
2456+
NativeLibKind::Static {
2457+
bundle: Some(false),
2458+
whole_archive: Some(false) | None,
2459+
} => {
2460+
if linkage == Linkage::Static {
2461+
// HACK/FIXME: Fixup a circular dependency between libgcc and libc
2462+
// with glibc. This logic should be moved to the libc crate.
2463+
if sess.target.os == "linux" && sess.target.env == "gnu" && name == "c"
2464+
{
2465+
cmd.link_staticlib("gcc", false);
24772466
}
2478-
NativeLibKind::Dylib { .. }
2479-
| NativeLibKind::Framework { .. }
2480-
| NativeLibKind::Unspecified
2481-
| NativeLibKind::RawDylib => {}
2482-
NativeLibKind::Static { bundle: Some(true) | None, whole_archive } => {
2483-
if sess.opts.unstable_opts.packed_bundled_libs {
2484-
// If rlib contains native libs as archives, they are unpacked to tmpdir.
2485-
let path = tmpdir.join(lib.filename.unwrap().as_str());
2486-
if whole_archive == Some(true) {
2487-
cmd.link_whole_rlib(&path);
2488-
} else {
2489-
cmd.link_rlib(&path);
2490-
}
2491-
}
2467+
cmd.link_staticlib(name, verbatim);
2468+
}
2469+
}
2470+
NativeLibKind::Static { bundle: Some(true) | None, whole_archive } => {
2471+
if linkage == Linkage::Static && sess.opts.unstable_opts.packed_bundled_libs
2472+
{
2473+
// If rlib contains native libs as archives, they are unpacked to tmpdir.
2474+
let path = tmpdir.join(lib.filename.unwrap().as_str());
2475+
if whole_archive == Some(true) {
2476+
cmd.link_whole_rlib(&path);
2477+
} else {
2478+
cmd.link_rlib(&path);
24922479
}
24932480
}
24942481
}
2482+
NativeLibKind::Dylib { as_needed } => {
2483+
cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
2484+
}
2485+
NativeLibKind::RawDylib => {}
2486+
NativeLibKind::Framework { as_needed } => {
2487+
cmd.link_framework(name, as_needed.unwrap_or(true))
2488+
}
2489+
NativeLibKind::LinkArg => {
2490+
if linkage == Linkage::Static {
2491+
cmd.arg(name);
2492+
}
2493+
}
2494+
NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true),
24952495
}
24962496
}
2497-
Linkage::Dynamic => add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0),
24982497
}
24992498
}
25002499

@@ -2648,63 +2647,6 @@ fn add_upstream_rust_crates<'a>(
26482647
}
26492648
}
26502649

2651-
/// Link in all of our upstream crates' native dependencies. Remember that all of these upstream
2652-
/// native dependencies are all non-static dependencies. We've got two cases then:
2653-
///
2654-
/// 1. The upstream crate is an rlib. In this case we *must* link in the native dependency because
2655-
/// the rlib is just an archive.
2656-
///
2657-
/// 2. The upstream crate is a dylib. In order to use the dylib, we have to have the dependency
2658-
/// present on the system somewhere. Thus, we don't gain a whole lot from not linking in the
2659-
/// dynamic dependency to this crate as well.
2660-
///
2661-
/// The use case for this is a little subtle. In theory the native dependencies of a crate are
2662-
/// purely an implementation detail of the crate itself, but the problem arises with generic and
2663-
/// inlined functions. If a generic function calls a native function, then the generic function
2664-
/// must be instantiated in the target crate, meaning that the native symbol must also be resolved
2665-
/// in the target crate.
2666-
fn add_upstream_native_libraries(
2667-
cmd: &mut dyn Linker,
2668-
sess: &Session,
2669-
codegen_results: &CodegenResults,
2670-
) {
2671-
let mut last = (None, NativeLibKind::Unspecified, None);
2672-
for &cnum in &codegen_results.crate_info.used_crates {
2673-
for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
2674-
let Some(name) = lib.name else {
2675-
continue;
2676-
};
2677-
let name = name.as_str();
2678-
if !relevant_lib(sess, &lib) {
2679-
continue;
2680-
}
2681-
2682-
// Skip if this library is the same as the last.
2683-
last = if (lib.name, lib.kind, lib.verbatim) == last {
2684-
continue;
2685-
} else {
2686-
(lib.name, lib.kind, lib.verbatim)
2687-
};
2688-
2689-
let verbatim = lib.verbatim.unwrap_or(false);
2690-
match lib.kind {
2691-
NativeLibKind::Dylib { as_needed } => {
2692-
cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
2693-
}
2694-
NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true),
2695-
NativeLibKind::Framework { as_needed } => {
2696-
cmd.link_framework(name, as_needed.unwrap_or(true))
2697-
}
2698-
// ignore static native libraries here as we've
2699-
// already included them in add_local_native_libraries and
2700-
// add_upstream_rust_crates
2701-
NativeLibKind::Static { .. } => {}
2702-
NativeLibKind::RawDylib | NativeLibKind::LinkArg => {}
2703-
}
2704-
}
2705-
}
2706-
}
2707-
27082650
fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
27092651
match lib.cfg {
27102652
Some(ref cfg) => rustc_attr::cfg_matches(cfg, &sess.parse_sess, CRATE_NODE_ID, None),

compiler/rustc_interface/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ fn test_unstable_options_tracking_hash() {
763763
tracked!(no_profiler_runtime, true);
764764
tracked!(oom, OomStrategy::Panic);
765765
tracked!(osx_rpath_install_name, true);
766-
tracked!(packed_bundled_libs, true);
766+
tracked!(packed_bundled_libs, false);
767767
tracked!(panic_abort_tests, true);
768768
tracked!(panic_in_drop, PanicStrategy::Abort);
769769
tracked!(pick_stable_methods_before_any_unstable, false);

compiler/rustc_metadata/src/native_libs.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,14 @@ impl<'tcx> Collector<'tcx> {
471471
lib.name = Some(Symbol::intern(new_name));
472472
}
473473
lib.verbatim = passed_lib.verbatim;
474+
if lib.filename.is_none() {
475+
lib.filename = find_bundled_library(
476+
lib.name,
477+
lib.verbatim,
478+
lib.kind,
479+
self.tcx.sess,
480+
);
481+
}
474482
return true;
475483
}
476484
}

compiler/rustc_session/src/options.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1431,7 +1431,7 @@ options! {
14311431
"pass `-install_name @rpath/...` to the macOS linker (default: no)"),
14321432
diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
14331433
"set the current output width for diagnostic truncation"),
1434-
packed_bundled_libs: bool = (false, parse_bool, [TRACKED],
1434+
packed_bundled_libs: bool = (true, parse_bool, [TRACKED],
14351435
"change rlib format to store native libraries as archives"),
14361436
panic_abort_tests: bool = (false, parse_bool, [TRACKED],
14371437
"support compiling tests with panic=abort (default: no)"),
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
# Staticlib format is no longer checked during bundling
2+
13
include ../tools.mk
24

35
all:
46
touch $(TMPDIR)/libfoo.a
5-
echo | $(RUSTC) - --crate-type=rlib -lstatic=foo 2>&1 | $(CGREP) "failed to add native library"
7+
$(RUSTC) lib.rs --crate-type=rlib -lstatic=foo
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// intentionally empty

src/test/run-make-fulldeps/link-dedup/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ all:
66
$(RUSTC) depa.rs
77
$(RUSTC) depb.rs
88
$(RUSTC) depc.rs
9-
$(RUSTC) empty.rs --cfg bar 2>&1 | $(CGREP) '"-ltesta" "-ltestb" "-ltesta"'
9+
$(RUSTC) empty.rs --cfg bar 2>&1 | $(CGREP) -e '"-ltesta".*"-ltestb".*"-ltesta"'
1010
$(RUSTC) empty.rs 2>&1 | $(CGREP) '"-ltesta"'
1111
$(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltestb"'
1212
$(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltesta" "-ltesta"'

src/test/run-make/native-link-modifier-bundle/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ all: $(call NATIVE_STATICLIB,native-staticlib)
1212
$(RUSTC) bundled.rs --crate-type=staticlib --crate-type=rlib
1313
$(NM) $(TMPDIR)/libbundled.a | $(CGREP) -e "T _*native_func"
1414
$(NM) $(TMPDIR)/libbundled.a | $(CGREP) -e "U _*native_func"
15-
$(NM) $(TMPDIR)/libbundled.rlib | $(CGREP) -e "T _*native_func"
15+
$(NM) $(TMPDIR)/libbundled.rlib | $(CGREP) -ve "T _*native_func"
1616
$(NM) $(TMPDIR)/libbundled.rlib | $(CGREP) -e "U _*native_func"
1717

1818
# Build a staticlib and a rlib, the `native_func` symbol will not be bundled into it
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// no-prefer-dynamic
2+
3+
#![crate_type = "staticlib"]
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
// compile-flags: -Zunstable-options --crate-type rlib
2-
// build-fail
3-
// error-pattern: the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs
1+
// Mixing +bundle and +whole-archive is now allowed
2+
3+
// build-pass
4+
// compile-flags: --crate-type rlib
5+
// aux-build:mylib.rs
46

57
#[link(name = "mylib", kind = "static", modifiers = "+bundle,+whole-archive")]
6-
extern "C" { }
8+
extern "C" {}
79

8-
fn main() { }
10+
fn main() {}

src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.stderr

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
// Mixing +bundle and +whole-archive is not allowed
1+
// Mixing +bundle and +whole-archive is now allowed
22

3-
// compile-flags: -l static:+bundle,+whole-archive=mylib -Zunstable-options --crate-type rlib
4-
// build-fail
5-
// error-pattern: the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs
3+
// build-pass
4+
// compile-flags: --crate-type rlib -l static:+bundle,+whole-archive=mylib
5+
// aux-build:mylib.rs
66

7-
fn main() { }
7+
fn main() {}

src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive.stderr

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)