Skip to content

Commit 9d41058

Browse files
committed
WIP: Add weak native linkage modifier
Passing the `-weak-l` / `-weak_framework`, and makes the dynamic linker `dyld` wait with resolving symbols until they're actually used. This is somewhat niche, but I have at least three different reasons to do this: - If we ever want to support rust-lang#121293 in some shape or form, or just generally want `rustc` to have a more global view of the linking, we need to support the `-weak_framework` linker flag. Supporting `-weak_framework` natively - Never makes sense together with `as_needed`. https://github.com/denoland/deno/blob/ab18dac09d9e5b00afee55ae0108f7c98bb2e2d3/.cargo/config.toml#L14-L24
1 parent a30f915 commit 9d41058

27 files changed

+215
-72
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+25-10
Original file line numberDiff line numberDiff line change
@@ -1357,7 +1357,7 @@ fn link_sanitizer_runtime(
13571357
let path = find_sanitizer_runtime(sess, &filename);
13581358
let rpath = path.to_str().expect("non-utf8 component in path");
13591359
linker.link_args(&["-rpath", rpath]);
1360-
linker.link_dylib_by_name(&filename, false, true);
1360+
linker.link_dylib_by_name(&filename, false, true, false);
13611361
} else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" {
13621362
// MSVC provides the `/INFERASANLIBS` argument to automatically find the
13631363
// compatible ASAN library.
@@ -1543,6 +1543,7 @@ fn print_native_static_libs(
15431543
.filter_map(|lib| {
15441544
let name = lib.name;
15451545
match lib.kind {
1546+
NativeLibKind::Dylib { weak: Some(true), .. } => Some(format!("-weak-l{name}")),
15461547
NativeLibKind::Static { bundle: Some(false), .. }
15471548
| NativeLibKind::Dylib { .. }
15481549
| NativeLibKind::Unspecified => {
@@ -1555,9 +1556,13 @@ fn print_native_static_libs(
15551556
Some(format!("-l{name}"))
15561557
}
15571558
}
1558-
NativeLibKind::Framework { .. } => {
1559-
// ld-only syntax, since there are no frameworks in MSVC
1560-
Some(format!("-framework {name}"))
1559+
// ld-only syntax, since there are no frameworks in MSVC.
1560+
NativeLibKind::Framework { weak, .. } => {
1561+
if weak.unwrap_or(false) {
1562+
Some(format!("-weak_framework {name}"))
1563+
} else {
1564+
Some(format!("-framework {name}"))
1565+
}
15611566
}
15621567
// These are included, no need to print them
15631568
NativeLibKind::Static { bundle: None | Some(true), .. }
@@ -2638,9 +2643,14 @@ fn add_native_libs_from_crate(
26382643
}
26392644
}
26402645
}
2641-
NativeLibKind::Dylib { as_needed } => {
2646+
NativeLibKind::Dylib { as_needed, weak } => {
26422647
if link_dynamic {
2643-
cmd.link_dylib_by_name(name, verbatim, as_needed.unwrap_or(true))
2648+
cmd.link_dylib_by_name(
2649+
name,
2650+
verbatim,
2651+
as_needed.unwrap_or(true),
2652+
weak.unwrap_or(false),
2653+
)
26442654
}
26452655
}
26462656
NativeLibKind::Unspecified => {
@@ -2651,12 +2661,17 @@ fn add_native_libs_from_crate(
26512661
cmd.link_staticlib_by_name(name, verbatim, false);
26522662
}
26532663
} else if link_dynamic {
2654-
cmd.link_dylib_by_name(name, verbatim, true);
2664+
cmd.link_dylib_by_name(name, verbatim, true, false);
26552665
}
26562666
}
2657-
NativeLibKind::Framework { as_needed } => {
2667+
NativeLibKind::Framework { as_needed, weak } => {
26582668
if link_dynamic {
2659-
cmd.link_framework_by_name(name, verbatim, as_needed.unwrap_or(true))
2669+
cmd.link_framework_by_name(
2670+
name,
2671+
verbatim,
2672+
as_needed.unwrap_or(true),
2673+
weak.unwrap_or(false),
2674+
)
26602675
}
26612676
}
26622677
NativeLibKind::RawDylib => {
@@ -2963,7 +2978,7 @@ fn add_static_crate(
29632978

29642979
// Same thing as above, but for dynamic crates instead of static crates.
29652980
fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
2966-
cmd.link_dylib_by_path(&rehome_lib_path(sess, cratepath), true);
2981+
cmd.link_dylib_by_path(&rehome_lib_path(sess, cratepath), true, false);
29672982
}
29682983

29692984
fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {

compiler/rustc_codegen_ssa/src/back/linker.rs

+36-17
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,19 @@ pub(crate) trait Linker {
303303
crate_type: CrateType,
304304
out_filename: &Path,
305305
);
306-
fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
306+
fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool, _weak: bool) {
307307
bug!("dylib linked with unsupported linker")
308308
}
309-
fn link_dylib_by_path(&mut self, _path: &Path, _as_needed: bool) {
309+
fn link_dylib_by_path(&mut self, _path: &Path, _as_needed: bool, _weak: bool) {
310310
bug!("dylib linked with unsupported linker")
311311
}
312-
fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
312+
fn link_framework_by_name(
313+
&mut self,
314+
_name: &str,
315+
_verbatim: bool,
316+
_as_needed: bool,
317+
_weak: bool,
318+
) {
313319
bug!("framework linked with unsupported linker")
314320
}
315321
fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool);
@@ -569,7 +575,7 @@ impl<'a> Linker for GccLinker<'a> {
569575
}
570576
}
571577

572-
fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) {
578+
fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool, weak: bool) {
573579
if self.sess.target.os == "illumos" && name == "c" {
574580
// libc will be added via late_link_args on illumos so that it will
575581
// appear last in the library search order.
@@ -581,26 +587,39 @@ impl<'a> Linker for GccLinker<'a> {
581587
self.hint_dynamic();
582588
self.with_as_needed(as_needed, |this| {
583589
let colon = if verbatim && this.is_gnu { ":" } else { "" };
584-
this.link_or_cc_arg(format!("-l{colon}{name}"));
590+
if weak {
591+
this.link_or_cc_arg(format!("-weak-l{colon}{name}"));
592+
} else {
593+
this.link_or_cc_arg(format!("-l{colon}{name}"));
594+
}
585595
});
586596
}
587597

588-
fn link_dylib_by_path(&mut self, path: &Path, as_needed: bool) {
598+
fn link_dylib_by_path(&mut self, path: &Path, as_needed: bool, weak: bool) {
589599
self.hint_dynamic();
590600
self.with_as_needed(as_needed, |this| {
591-
this.link_or_cc_arg(path);
601+
if weak {
602+
this.link_or_cc_arg("-weak_library");
603+
this.link_or_cc_arg(path);
604+
} else {
605+
this.link_or_cc_arg(path);
606+
}
592607
})
593608
}
594609

595-
fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) {
610+
fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool, weak: bool) {
596611
self.hint_dynamic();
597612
if !as_needed {
598613
// FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
599614
// flag but we have no way to detect that here.
600615
// self.link_or_cc_arg("-needed_framework").link_or_cc_arg(name);
601616
self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
602617
}
603-
self.link_or_cc_args(&["-framework", name]);
618+
if weak {
619+
self.link_or_cc_args(&["-weak_framework", name]);
620+
} else {
621+
self.link_or_cc_args(&["-framework", name]);
622+
}
604623
}
605624

606625
fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
@@ -923,7 +942,7 @@ impl<'a> Linker for MsvcLinker<'a> {
923942
}
924943
}
925944

926-
fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
945+
fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool, _weak: bool) {
927946
// On MSVC-like targets rustc supports import libraries using alternative naming
928947
// scheme (`libfoo.a`) unsupported by linker, search for such libraries manually.
929948
if let Some(path) = try_find_native_dynamic_library(self.sess, name, verbatim) {
@@ -933,7 +952,7 @@ impl<'a> Linker for MsvcLinker<'a> {
933952
}
934953
}
935954

936-
fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
955+
fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool, _weak: bool) {
937956
// When producing a dll, MSVC linker may not emit an implib file if the dll doesn't export
938957
// any symbols, so we skip linking if the implib file is not present.
939958
let implib_path = path.with_extension("dll.lib");
@@ -1171,12 +1190,12 @@ impl<'a> Linker for EmLinker<'a> {
11711190
) {
11721191
}
11731192

1174-
fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1193+
fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool, _weak: bool) {
11751194
// Emscripten always links statically
11761195
self.link_or_cc_args(&["-l", name]);
11771196
}
11781197

1179-
fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1198+
fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool, _weak: bool) {
11801199
self.link_or_cc_arg(path);
11811200
}
11821201

@@ -1338,11 +1357,11 @@ impl<'a> Linker for WasmLd<'a> {
13381357
}
13391358
}
13401359

1341-
fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1360+
fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool, _weak: bool) {
13421361
self.link_or_cc_args(&["-l", name]);
13431362
}
13441363

1345-
fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1364+
fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool, _weak: bool) {
13461365
self.link_or_cc_arg(path);
13471366
}
13481367

@@ -1643,12 +1662,12 @@ impl<'a> Linker for AixLinker<'a> {
16431662
}
16441663
}
16451664

1646-
fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1665+
fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool, _weak: bool) {
16471666
self.hint_dynamic();
16481667
self.link_or_cc_arg(format!("-l{name}"));
16491668
}
16501669

1651-
fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1670+
fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool, _weak: bool) {
16521671
self.hint_dynamic();
16531672
self.link_or_cc_arg(path);
16541673
}

compiler/rustc_error_codes/src/error_codes/E0455.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
Some linking kinds are target-specific and not supported on all platforms.
22

3-
Linking with `kind=framework` is only supported when targeting macOS,
4-
as frameworks are specific to that operating system.
3+
Linking with `kind=framework`, `kind=weak_framework` or `kind=weak_dylib` is
4+
only supported when targeting macOS, as frameworks are specific to that
5+
operating system.
56

67
Similarly, `kind=raw-dylib` is only supported when targeting Windows-like
78
platforms.

compiler/rustc_error_codes/src/error_codes/E0458.md

+2
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@ Please specify a valid "kind" value, from one of the following:
1111

1212
* static
1313
* dylib
14+
* weak_dylib
1415
* framework
16+
* weak_framework
1517
* raw-dylib

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,8 @@ declare_features! (
560560
(unstable, naked_functions, "1.9.0", Some(90957)),
561561
/// Allows specifying the as-needed link modifier
562562
(unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490)),
563+
/// Allows specifying the weak link modifier.
564+
(unstable, native_link_modifiers_weak, "CURRENT_RUSTC_VERSION", None),
563565
/// Allow negative trait implementations.
564566
(unstable, negative_impls, "1.44.0", Some(68318)),
565567
/// Allows the `!` pattern.

compiler/rustc_interface/src/tests.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ fn test_native_libs_tracking_hash_different_values() {
382382
NativeLib {
383383
name: String::from("b"),
384384
new_name: None,
385-
kind: NativeLibKind::Framework { as_needed: None },
385+
kind: NativeLibKind::Framework { as_needed: None, weak: None },
386386
verbatim: None,
387387
},
388388
NativeLib {
@@ -404,7 +404,7 @@ fn test_native_libs_tracking_hash_different_values() {
404404
NativeLib {
405405
name: String::from("X"),
406406
new_name: None,
407-
kind: NativeLibKind::Framework { as_needed: None },
407+
kind: NativeLibKind::Framework { as_needed: None, weak: None },
408408
verbatim: None,
409409
},
410410
NativeLib {
@@ -448,7 +448,7 @@ fn test_native_libs_tracking_hash_different_values() {
448448
NativeLib {
449449
name: String::from("b"),
450450
new_name: Some(String::from("X")),
451-
kind: NativeLibKind::Framework { as_needed: None },
451+
kind: NativeLibKind::Framework { as_needed: None, weak: None },
452452
verbatim: None,
453453
},
454454
NativeLib {
@@ -470,7 +470,7 @@ fn test_native_libs_tracking_hash_different_values() {
470470
NativeLib {
471471
name: String::from("b"),
472472
new_name: None,
473-
kind: NativeLibKind::Framework { as_needed: None },
473+
kind: NativeLibKind::Framework { as_needed: None, weak: None },
474474
verbatim: Some(true),
475475
},
476476
NativeLib {
@@ -504,7 +504,7 @@ fn test_native_libs_tracking_hash_different_order() {
504504
NativeLib {
505505
name: String::from("b"),
506506
new_name: None,
507-
kind: NativeLibKind::Framework { as_needed: None },
507+
kind: NativeLibKind::Framework { as_needed: None, weak: None },
508508
verbatim: None,
509509
},
510510
NativeLib {
@@ -519,7 +519,7 @@ fn test_native_libs_tracking_hash_different_order() {
519519
NativeLib {
520520
name: String::from("b"),
521521
new_name: None,
522-
kind: NativeLibKind::Framework { as_needed: None },
522+
kind: NativeLibKind::Framework { as_needed: None, weak: None },
523523
verbatim: None,
524524
},
525525
NativeLib {
@@ -552,7 +552,7 @@ fn test_native_libs_tracking_hash_different_order() {
552552
NativeLib {
553553
name: String::from("b"),
554554
new_name: None,
555-
kind: NativeLibKind::Framework { as_needed: None },
555+
kind: NativeLibKind::Framework { as_needed: None, weak: None },
556556
verbatim: None,
557557
},
558558
];

compiler/rustc_metadata/messages.ftl

+11-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ metadata_install_missing_components =
120120
maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`
121121
122122
metadata_invalid_link_modifier =
123-
invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
123+
invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed, weak
124124
125125
metadata_invalid_meta_files =
126126
found invalid metadata files for crate `{$crate_name}`{$add_info}
@@ -134,6 +134,9 @@ metadata_lib_framework_apple =
134134
metadata_lib_required =
135135
crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
136136
137+
metadata_lib_weak_apple =
138+
library modifier `weak` is only supported on Apple targets
139+
137140
metadata_link_arg_unstable =
138141
link kind `link-arg` is unstable
139142
@@ -165,6 +168,9 @@ metadata_link_requires_name =
165168
`#[link]` attribute requires a `name = "string"` argument
166169
.label = missing `name` argument
167170
171+
metadata_link_weak_apple =
172+
link modifier `weak` is only supported on Apple targets
173+
168174
metadata_missing_native_library =
169175
could not find native static library `{$libname}`, perhaps an -L flag is missing?
170176
@@ -282,7 +288,7 @@ metadata_unknown_link_kind =
282288
.label = unknown link kind
283289
284290
metadata_unknown_link_modifier =
285-
unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
291+
unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed, weak
286292
287293
metadata_unsupported_abi =
288294
ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
@@ -293,5 +299,8 @@ metadata_unsupported_abi_i686 =
293299
metadata_wasm_import_form =
294300
wasm import module must be of the form `wasm_import_module = "string"`
295301
302+
metadata_weak_compatibility =
303+
linking modifier `weak` is only compatible with `dylib` and `framework` linking kinds
304+
296305
metadata_whole_archive_needs_static =
297306
linking modifier `whole-archive` is only compatible with `static` linking kind

compiler/rustc_metadata/src/errors.rs

+18
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,13 @@ pub struct LinkFrameworkApple {
146146
pub span: Span,
147147
}
148148

149+
#[derive(Diagnostic)]
150+
#[diag(metadata_link_weak_apple, code = E0455)]
151+
pub struct LinkWeakApple {
152+
#[primary_span]
153+
pub span: Span,
154+
}
155+
149156
#[derive(Diagnostic)]
150157
#[diag(metadata_raw_dylib_only_windows, code = E0455)]
151158
pub struct RawDylibOnlyWindows {
@@ -233,6 +240,13 @@ pub struct AsNeededCompatibility {
233240
pub span: Span,
234241
}
235242

243+
#[derive(Diagnostic)]
244+
#[diag(metadata_weak_compatibility)]
245+
pub struct WeakCompatibility {
246+
#[primary_span]
247+
pub span: Span,
248+
}
249+
236250
#[derive(Diagnostic)]
237251
#[diag(metadata_unknown_link_modifier)]
238252
pub struct UnknownLinkModifier<'a> {
@@ -274,6 +288,10 @@ pub struct LinkOrdinalRawDylib {
274288
#[diag(metadata_lib_framework_apple)]
275289
pub struct LibFrameworkApple;
276290

291+
#[derive(Diagnostic)]
292+
#[diag(metadata_lib_weak_apple)]
293+
pub struct LibWeakApple;
294+
277295
#[derive(Diagnostic)]
278296
#[diag(metadata_empty_renaming_target)]
279297
pub struct EmptyRenamingTarget<'a> {

0 commit comments

Comments
 (0)