1 use std::path::PathBuf;
4 use rustc_session::Session;
5 use rustc_target::spec::LinkerFlavor;
7 /// Tries to infer the path of a binary for the target toolchain from the linker name.
8 pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf {
9 let (mut linker, _linker_flavor) = linker_and_flavor(sess);
10 let linker_file_name = linker.file_name().and_then(|name| name.to_str()).unwrap_or_else(|| {
11 sess.fatal("couldn't extract file name from specified linker")
14 if linker_file_name == "ld.lld" {
16 linker.set_file_name(tool)
19 let tool_file_name = linker_file_name
22 .replace("clang", tool)
25 linker.set_file_name(tool_file_name)
31 // Adapted from https://github.com/rust-lang/rust/blob/5db778affee7c6600c8e7a177c48282dab3f6292/src/librustc_codegen_ssa/back/link.rs#L848-L931
32 fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
35 linker: Option<PathBuf>,
36 flavor: Option<LinkerFlavor>,
37 ) -> Option<(PathBuf, LinkerFlavor)> {
38 match (linker, flavor) {
39 (Some(linker), Some(flavor)) => Some((linker, flavor)),
40 // only the linker flavor is known; use the default linker for the selected flavor
41 (None, Some(flavor)) => Some((
42 PathBuf::from(match flavor {
50 LinkerFlavor::Gcc => {
51 if cfg!(any(target_os = "solaris", target_os = "illumos")) {
52 // On historical Solaris systems, "cc" may have
53 // been Sun Studio, which is not flag-compatible
54 // with "gcc". This history casts a long shadow,
55 // and many modern illumos distributions today
56 // ship GCC as "gcc" without also making it
63 LinkerFlavor::Ld => "ld",
64 LinkerFlavor::Msvc => "link.exe",
65 LinkerFlavor::Lld(_) => "lld",
66 LinkerFlavor::PtxLinker => "rust-ptx-linker",
70 (Some(linker), None) => {
71 let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
72 sess.fatal("couldn't extract file stem from specified linker")
75 let flavor = if stem == "emcc" {
77 } else if stem == "gcc"
78 || stem.ends_with("-gcc")
80 || stem.ends_with("-clang")
83 } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
85 } else if stem == "link" || stem == "lld-link" {
87 } else if stem == "lld" || stem == "rust-lld" {
88 LinkerFlavor::Lld(sess.target.target.options.lld_flavor)
90 // fall back to the value in the target spec
91 sess.target.target.linker_flavor
94 Some((linker, flavor))
100 // linker and linker flavor specified via command line have precedence over what the target
101 // specification specifies
102 if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) {
106 if let Some(ret) = infer_from(
108 sess.target.target.options.linker.clone().map(PathBuf::from),
109 Some(sess.target.target.linker_flavor),
114 bug!("Not enough information provided to determine how to invoke the linker");