Skip to content

Commit 15d33db

Browse files
committed
Preliminary support for verbatim linking of crates
Due to the fact that if we were not using verbatim linking, linking against a versioned crate will only work if a unversioned symlink to the versioned one is part of the searchpath. This is "preliminary" as right now it only uses the whole filename for GNU-style linkers. It should however, be expanded to any linker that supports verbatim linking. Also added suggestions from @wesleywiser.
1 parent 432565c commit 15d33db

File tree

3 files changed

+42
-43
lines changed

3 files changed

+42
-43
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+5-19
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
33
use rustc_errors::{ErrorReported, Handler};
44
use rustc_fs_util::fix_windows_verbatim_for_gcc;
55
use rustc_hir::def_id::CrateNum;
6+
use rustc_metadata::locator::{get_dylib_symbol_name, unlib};
67
use rustc_middle::middle::dependency_format::Linkage;
78
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
89
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
@@ -17,7 +18,7 @@ use rustc_span::symbol::Symbol;
1718
use rustc_target::abi::Endian;
1819
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
1920
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
20-
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
21+
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet};
2122

2223
use super::archive::{find_library, ArchiveBuilder};
2324
use super::command::Command;
@@ -2252,11 +2253,6 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
22522253
add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
22532254
}
22542255

2255-
// Converts a library file-stem into a cc -l argument
2256-
fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str {
2257-
if stem.starts_with("lib") && !target.is_like_windows { &stem[3..] } else { stem }
2258-
}
2259-
22602256
// Adds the static "rlib" versions of all crates to the command line.
22612257
// There's a bit of magic which happens here specifically related to LTO,
22622258
// namely that we remove upstream object files.
@@ -2380,19 +2376,9 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
23802376
cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
23812377
}
23822378
let filename = cratepath.file_name().unwrap().to_str().unwrap();
2383-
// test if dll_suffix is found within filename (should be, but if it
2384-
// isn't falls back to just getting the file stem). Then just gets the
2385-
// substring from the beginning to the suffix. This is better than just
2386-
// getting the filestem, as it respects versioned libraries.
2387-
let filestem = filename
2388-
.find(&sess.target.dll_suffix)
2389-
.map(|idx| filename.get(0..idx))
2390-
.flatten()
2391-
.unwrap_or(cratepath.file_stem().unwrap().to_str().unwrap());
2392-
cmd.link_rust_dylib(
2393-
Symbol::intern(&unlib(&sess.target, filestem)),
2394-
parent.unwrap_or_else(|| Path::new("")),
2395-
);
2379+
let symbol_name = get_dylib_symbol_name(filename, &sess.target)
2380+
.unwrap_or(unlib(&sess.target, cratepath.file_stem().unwrap().to_str().unwrap()));
2381+
cmd.link_rust_dylib(Symbol::intern(symbol_name), cratepath);
23962382
}
23972383
}
23982384

compiler/rustc_codegen_ssa/src/back/linker.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,9 @@ impl<'a> Linker for GccLinker<'a> {
464464
self.linker_arg("-znorelro");
465465
}
466466

467-
fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
467+
fn link_rust_dylib(&mut self, _lib: Symbol, path: &Path) {
468468
self.hint_dynamic();
469-
self.cmd.arg(format!("-l{}", lib));
469+
self.cmd.arg(format!("-l:{}", path.file_name().unwrap().to_str().unwrap()));
470470
}
471471

472472
fn link_framework(&mut self, framework: Symbol, as_needed: bool) {
@@ -837,7 +837,7 @@ impl<'a> Linker for MsvcLinker<'a> {
837837
// check to see if the file is there and just omit linking to it if it's
838838
// not present.
839839
let name = format!("{}.dll.lib", lib);
840-
if path.join(&name).exists() {
840+
if path.parent().unwrap_or_else(|| Path::new("")).join(&name).exists() {
841841
self.cmd.arg(name);
842842
}
843843
}

compiler/rustc_metadata/src/locator.rs

+34-21
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,35 @@ use std::path::{Path, PathBuf};
238238
use std::{cmp, fmt, fs};
239239
use tracing::{debug, info, warn};
240240

241+
// Converts a library file-stem into a cc -l argument
242+
pub fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str {
243+
if stem.starts_with("lib") && !target.is_like_windows { &stem[3..] } else { stem }
244+
}
245+
246+
/// Returns Some(symbol_name) if `file` could be a valid dylib
247+
/// Example (assuming target is GNU/Linux):
248+
/// - `libsomecrate.asdf` -> `None`
249+
/// - `libsomecrate.so` -> `Some(somecreate)`
250+
/// - `libsomecrate.so.0.1` -> `Some(somecreate)`
251+
/// - `libsomecrate.so.a.4` -> `None`
252+
pub fn get_dylib_symbol_name<'a>(file: &'a str, target: &Target) -> Option<&'a str> {
253+
// test if the targets dll_suffix is found within the filename. If it
254+
// is check if all of the chars following it are either a digit (0-9)
255+
// or a dot.
256+
file.find(&target.dll_suffix)
257+
.map(|idx| {
258+
match file
259+
.chars()
260+
.skip(idx + idx + target.dll_suffix.len())
261+
.all(|c| c.is_ascii_digit() || c == '.')
262+
{
263+
true => file.get(0..idx).map(|s| unlib(target, s)),
264+
false => None,
265+
}
266+
})
267+
.flatten()
268+
}
269+
241270
#[derive(Clone)]
242271
crate struct CrateLocator<'a> {
243272
// Immutable per-session configuration.
@@ -365,25 +394,6 @@ impl<'a> CrateLocator<'a> {
365394
self.find_library_crate("", &mut seen_paths)
366395
}
367396

368-
/// Returns true if `file` has a suffix that could be a valid dylib
369-
/// Example (assuming target has .so as dll_suffix):
370-
/// - `libsomecrate.asdf` -> `false`
371-
/// - `libsomecrate.so` -> `true`
372-
/// - `libsomecrate.so.0.1` -> `true`
373-
/// - `libsomecrate.so.a.4` -> `false`
374-
fn test_dylib_suffix(&self, file: &str) -> bool {
375-
// test if the targets dll_suffix is found within the filename. If it
376-
// is check if all of the chars following it are either in range 0x30
377-
// to 0x39 (0-9) or 0x2E (.).
378-
match file.find(&self.target.dll_suffix) {
379-
Some(idx) => file
380-
.chars()
381-
.skip(idx + self.target.dll_suffix.len())
382-
.all(|c| c as u32 >= 0x30 && c as u32 <= 0x39 || c as u32 == 0x2E),
383-
None => false,
384-
}
385-
}
386-
387397
fn find_library_crate(
388398
&mut self,
389399
extra_prefix: &str,
@@ -421,7 +431,9 @@ impl<'a> CrateLocator<'a> {
421431
(&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib)
422432
} else if file.starts_with(&rlib_prefix) && file.ends_with(".rmeta") {
423433
(&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta)
424-
} else if file.starts_with(&dylib_prefix) && self.test_dylib_suffix(file) {
434+
} else if file.starts_with(&dylib_prefix)
435+
&& get_dylib_symbol_name(file, &self.target).is_some()
436+
{
425437
(
426438
&file[(dylib_prefix.len())..(file.len() - self.target.dll_suffix.len())],
427439
CrateFlavor::Dylib,
@@ -700,7 +712,8 @@ impl<'a> CrateLocator<'a> {
700712
};
701713

702714
if file.starts_with("lib") && (file.ends_with(".rlib") || file.ends_with(".rmeta"))
703-
|| file.starts_with(&self.target.dll_prefix) && self.test_dylib_suffix(file)
715+
|| file.starts_with(&self.target.dll_prefix)
716+
&& get_dylib_symbol_name(file, &self.target).is_some()
704717
{
705718
// Make sure there's at most one rlib and at most one dylib.
706719
// Note to take care and match against the non-canonicalized name:

0 commit comments

Comments
 (0)