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