Skip to content

Commit d22d979

Browse files
committed
linker: Link dylib crates by path
1 parent 1be24d7 commit d22d979

File tree

3 files changed

+79
-56
lines changed

3 files changed

+79
-56
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+13-20
Original file line numberDiff line numberDiff line change
@@ -2816,6 +2816,15 @@ fn rehome_sysroot_lib_dir(sess: &Session, lib_dir: &Path) -> PathBuf {
28162816
}
28172817
}
28182818

2819+
fn rehome_lib_path(sess: &Session, path: &Path) -> PathBuf {
2820+
if let Some(dir) = path.parent() {
2821+
let file_name = path.file_name().expect("library path has no file name component");
2822+
rehome_sysroot_lib_dir(sess, dir).join(file_name)
2823+
} else {
2824+
fix_windows_verbatim_for_gcc(path)
2825+
}
2826+
}
2827+
28192828
// Adds the static "rlib" versions of all crates to the command line.
28202829
// There's a bit of magic which happens here specifically related to LTO,
28212830
// namely that we remove upstream object files.
@@ -2847,12 +2856,7 @@ fn add_static_crate(
28472856
let cratepath = &src.rlib.as_ref().unwrap().0;
28482857

28492858
let mut link_upstream = |path: &Path| {
2850-
let rlib_path = if let Some(dir) = path.parent() {
2851-
let file_name = path.file_name().expect("rlib path has no file name path component");
2852-
rehome_sysroot_lib_dir(sess, dir).join(file_name)
2853-
} else {
2854-
fix_windows_verbatim_for_gcc(path)
2855-
};
2859+
let rlib_path = rehome_lib_path(sess, path);
28562860
cmd.link_staticlib_by_path(&rlib_path, false);
28572861
};
28582862

@@ -2918,27 +2922,16 @@ fn add_static_crate(
29182922

29192923
// Same thing as above, but for dynamic crates instead of static crates.
29202924
fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
2921-
// Just need to tell the linker about where the library lives and
2922-
// what its name is
2923-
let parent = cratepath.parent();
29242925
// When producing a dll, the MSVC linker may not actually emit a
29252926
// `foo.lib` file if the dll doesn't actually export any symbols, so we
29262927
// check to see if the file is there and just omit linking to it if it's
29272928
// not present.
29282929
if sess.target.is_like_msvc && !cratepath.with_extension("dll.lib").exists() {
29292930
return;
29302931
}
2931-
if let Some(dir) = parent {
2932-
cmd.include_path(&rehome_sysroot_lib_dir(sess, dir));
2933-
}
2934-
// "<dir>/name.dll -> name.dll" on windows-msvc
2935-
// "<dir>/name.dll -> name" on windows-gnu
2936-
// "<dir>/libname.<ext> -> name" elsewhere
2937-
let stem = if sess.target.is_like_msvc { cratepath.file_name() } else { cratepath.file_stem() };
2938-
let stem = stem.unwrap().to_str().unwrap();
2939-
// Convert library file-stem into a cc -l argument.
2940-
let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 };
2941-
cmd.link_dylib_by_name(&stem[prefix..], false, true);
2932+
2933+
let dylib_path = rehome_lib_path(sess, cratepath);
2934+
cmd.link_dylib_by_path(&dylib_path, true);
29422935
}
29432936

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

compiler/rustc_codegen_ssa/src/back/linker.rs

+61-36
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ pub trait Linker {
170170
fn cmd(&mut self) -> &mut Command;
171171
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
172172
fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool);
173+
fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
174+
self.cmd().arg(path);
175+
}
173176
fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
174177
bug!("framework linked with unsupported linker")
175178
}
@@ -320,28 +323,55 @@ impl<'a> GccLinker<'a> {
320323
}
321324
} else {
322325
self.cmd.arg("-shared");
323-
if self.sess.target.is_like_windows {
324-
// The output filename already contains `dll_suffix` so
325-
// the resulting import library will have a name in the
326-
// form of libfoo.dll.a
327-
let implib_name =
328-
out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
329-
format!(
330-
"{}{}{}",
331-
self.sess.target.staticlib_prefix,
332-
file,
333-
self.sess.target.staticlib_suffix
334-
)
335-
});
336-
if let Some(implib_name) = implib_name {
337-
let implib = out_filename.parent().map(|dir| dir.join(&implib_name));
338-
if let Some(implib) = implib {
339-
self.linker_arg(&format!("--out-implib={}", (*implib).to_str().unwrap()));
326+
if let Some(name) = out_filename.file_name() {
327+
if self.sess.target.is_like_windows {
328+
// The output filename already contains `dll_suffix` so
329+
// the resulting import library will have a name in the
330+
// form of libfoo.dll.a
331+
let mut implib_name = OsString::from(&*self.sess.target.staticlib_prefix);
332+
implib_name.push(name);
333+
implib_name.push(&*self.sess.target.staticlib_suffix);
334+
if let Some(implib) = out_filename.parent().map(|dir| dir.join(&implib_name)) {
335+
let mut out_implib = OsString::from("--out-implib=");
336+
out_implib.push(implib);
337+
self.linker_arg(out_implib);
340338
}
339+
} else {
340+
// When dylibs are linked by a full path this value will get into `DT_NEEDED`
341+
// instead of the full path, so the library can be later found in some other
342+
// location than that specific path.
343+
let mut soname = OsString::from("-soname=");
344+
soname.push(name);
345+
self.linker_arg(soname);
341346
}
342347
}
343348
}
344349
}
350+
351+
fn open_as_needed(&mut self, as_needed: bool) {
352+
if !as_needed {
353+
if self.sess.target.is_like_osx {
354+
// FIXME(81490): ld64 doesn't support these flags but macOS 11
355+
// has -needed-l{} / -needed_library {}
356+
// but we have no way to detect that here.
357+
self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
358+
} else if self.is_gnu && !self.sess.target.is_like_windows {
359+
self.linker_arg("--no-as-needed");
360+
} else {
361+
self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier);
362+
}
363+
}
364+
}
365+
366+
fn close_as_needed(&mut self, as_needed: bool) {
367+
if !as_needed {
368+
if self.sess.target.is_like_osx {
369+
// See above FIXME comment
370+
} else if self.is_gnu && !self.sess.target.is_like_windows {
371+
self.linker_arg("--as-needed");
372+
}
373+
}
374+
}
345375
}
346376

347377
impl<'a> Linker for GccLinker<'a> {
@@ -443,27 +473,17 @@ impl<'a> Linker for GccLinker<'a> {
443473
// to the linker.
444474
return;
445475
}
446-
if !as_needed {
447-
if self.sess.target.is_like_osx {
448-
// FIXME(81490): ld64 doesn't support these flags but macOS 11
449-
// has -needed-l{} / -needed_library {}
450-
// but we have no way to detect that here.
451-
self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
452-
} else if self.is_gnu && !self.sess.target.is_like_windows {
453-
self.linker_arg("--no-as-needed");
454-
} else {
455-
self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier);
456-
}
457-
}
458476
self.hint_dynamic();
477+
self.open_as_needed(as_needed);
459478
self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },));
460-
if !as_needed {
461-
if self.sess.target.is_like_osx {
462-
// See above FIXME comment
463-
} else if self.is_gnu && !self.sess.target.is_like_windows {
464-
self.linker_arg("--as-needed");
465-
}
466-
}
479+
self.close_as_needed(as_needed);
480+
}
481+
482+
fn link_dylib_by_path(&mut self, path: &Path, as_needed: bool) {
483+
self.hint_dynamic();
484+
self.open_as_needed(as_needed);
485+
self.cmd.arg(path);
486+
self.close_as_needed(as_needed);
467487
}
468488

469489
fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) {
@@ -1537,6 +1557,11 @@ impl<'a> Linker for AixLinker<'a> {
15371557
self.cmd.arg(format!("-l{name}"));
15381558
}
15391559

1560+
fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1561+
self.hint_dynamic();
1562+
self.cmd().arg(path);
1563+
}
1564+
15401565
fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
15411566
self.hint_static();
15421567
if !whole_archive {

src/ci/github-actions/jobs.yml

+5
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ pr:
9191
<<: *job-linux-16c
9292
- image: x86_64-gnu-tools
9393
<<: *job-linux-16c
94+
- image: x86_64-msvc
95+
env:
96+
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
97+
SCRIPT: make ci-msvc
98+
<<: *job-windows-8c
9499

95100
# Jobs that run when you perform a try build (@bors try)
96101
# These jobs automatically inherit envs.try, to avoid repeating

0 commit comments

Comments
 (0)