]> git.lizzy.rs Git - rust.git/blob - src/toolchain.rs
fmt: Run cargo fmt since it is available
[rust.git] / src / toolchain.rs
1 use std::path::PathBuf;
2
3 use rustc_middle::bug;
4 use rustc_session::Session;
5 use rustc_target::spec::LinkerFlavor;
6
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
11         .file_name()
12         .and_then(|name| name.to_str())
13         .unwrap_or_else(|| sess.fatal("couldn't extract file name from specified linker"));
14
15     if linker_file_name == "ld.lld" {
16         if tool != "ld" {
17             linker.set_file_name(tool)
18         }
19     } else {
20         let tool_file_name = linker_file_name
21             .replace("ld", tool)
22             .replace("gcc", tool)
23             .replace("clang", tool)
24             .replace("cc", tool);
25
26         linker.set_file_name(tool_file_name)
27     }
28
29     linker
30 }
31
32 // Adapted from https://github.com/rust-lang/rust/blob/5db778affee7c6600c8e7a177c48282dab3f6292/src/librustc_codegen_ssa/back/link.rs#L848-L931
33 fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
34     fn infer_from(
35         sess: &Session,
36         linker: Option<PathBuf>,
37         flavor: Option<LinkerFlavor>,
38     ) -> Option<(PathBuf, LinkerFlavor)> {
39         match (linker, flavor) {
40             (Some(linker), Some(flavor)) => Some((linker, flavor)),
41             // only the linker flavor is known; use the default linker for the selected flavor
42             (None, Some(flavor)) => Some((
43                 PathBuf::from(match flavor {
44                     LinkerFlavor::Em => {
45                         if cfg!(windows) {
46                             "emcc.bat"
47                         } else {
48                             "emcc"
49                         }
50                     }
51                     LinkerFlavor::Gcc => {
52                         if cfg!(any(target_os = "solaris", target_os = "illumos")) {
53                             // On historical Solaris systems, "cc" may have
54                             // been Sun Studio, which is not flag-compatible
55                             // with "gcc".  This history casts a long shadow,
56                             // and many modern illumos distributions today
57                             // ship GCC as "gcc" without also making it
58                             // available as "cc".
59                             "gcc"
60                         } else {
61                             "cc"
62                         }
63                     }
64                     LinkerFlavor::Ld => "ld",
65                     LinkerFlavor::Msvc => "link.exe",
66                     LinkerFlavor::Lld(_) => "lld",
67                     LinkerFlavor::PtxLinker => "rust-ptx-linker",
68                 }),
69                 flavor,
70             )),
71             (Some(linker), None) => {
72                 let stem = linker
73                     .file_stem()
74                     .and_then(|stem| stem.to_str())
75                     .unwrap_or_else(|| {
76                         sess.fatal("couldn't extract file stem from specified linker")
77                     });
78
79                 let flavor = if stem == "emcc" {
80                     LinkerFlavor::Em
81                 } else if stem == "gcc"
82                     || stem.ends_with("-gcc")
83                     || stem == "clang"
84                     || stem.ends_with("-clang")
85                 {
86                     LinkerFlavor::Gcc
87                 } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
88                     LinkerFlavor::Ld
89                 } else if stem == "link" || stem == "lld-link" {
90                     LinkerFlavor::Msvc
91                 } else if stem == "lld" || stem == "rust-lld" {
92                     LinkerFlavor::Lld(sess.target.target.options.lld_flavor)
93                 } else {
94                     // fall back to the value in the target spec
95                     sess.target.target.linker_flavor
96                 };
97
98                 Some((linker, flavor))
99             }
100             (None, None) => None,
101         }
102     }
103
104     // linker and linker flavor specified via command line have precedence over what the target
105     // specification specifies
106     if let Some(ret) = infer_from(
107         sess,
108         sess.opts.cg.linker.clone(),
109         sess.opts.cg.linker_flavor,
110     ) {
111         return ret;
112     }
113
114     if let Some(ret) = infer_from(
115         sess,
116         sess.target.target.options.linker.clone().map(PathBuf::from),
117         Some(sess.target.target.linker_flavor),
118     ) {
119         return ret;
120     }
121
122     bug!("Not enough information provided to determine how to invoke the linker");
123 }