]> git.lizzy.rs Git - rust.git/blob - src/link.rs
Bump serde from 1.0.86 to 1.0.87
[rust.git] / src / link.rs
1 use std::ascii;
2 use std::char;
3 use std::env;
4 use std::fs::File;
5 use std::io;
6 use std::path::{Path, PathBuf};
7 use std::str;
8
9 use tempfile::Builder as TempFileBuilder;
10
11 use rustc::session::config::{self, CrateType, DebugInfo, RUST_CGU_EXT};
12 use rustc::session::search_paths::PathKind;
13 use rustc::session::Session;
14 use rustc_codegen_ssa::back::command::Command;
15 use rustc_codegen_ssa::back::link::*;
16 use rustc_codegen_ssa::back::linker::*;
17 use rustc_fs_util::fix_windows_verbatim_for_gcc;
18 use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
19
20 use crate::prelude::*;
21
22 use crate::link_copied::*;
23
24 pub(crate) fn link_rlib(sess: &Session, res: &CodegenResults, output_name: PathBuf) {
25     let file = File::create(&output_name).unwrap();
26     let mut builder = ar::Builder::new(file);
27
28     // Add main object file
29     for module in &res.modules {
30         if let Some(ref object_path) = module.object {
31             let object = File::open(object_path).expect("Someone deleted our object file");
32             let object_len = object.metadata().unwrap().len();
33             builder
34                 .append(
35                     &ar::Header::new(
36                         (module.name.to_string() + RUST_CGU_EXT).into_bytes(),
37                         object_len,
38                     ),
39                     object,
40                 )
41                 .unwrap();
42         }
43     }
44
45     // Non object files need to be added after object files, because ranlib will
46     // try to read the native architecture from the first file, even if it isn't
47     // an object file
48     builder
49         .append(
50             &ar::Header::new(
51                 crate::metadata::METADATA_FILENAME.as_bytes().to_vec(),
52                 res.metadata.raw_data.len() as u64,
53             ),
54             ::std::io::Cursor::new(res.metadata.raw_data.clone()),
55         )
56         .unwrap();
57
58     // Finalize archive
59     std::mem::drop(builder);
60
61     // Run ranlib to be able to link the archive
62     let status = std::process::Command::new("ranlib")
63         .arg(output_name)
64         .status()
65         .expect("Couldn't run ranlib");
66     if !status.success() {
67         sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
68     }
69 }
70
71 pub(crate) fn link_natively(
72     sess: &Session,
73     crate_type: CrateType,
74     codegen_results: &CodegenResults,
75     out_filename: &Path,
76 ) {
77     let tmpdir = match TempFileBuilder::new().prefix("rustc").tempdir() {
78         Ok(tmpdir) => tmpdir,
79         Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)),
80     };
81
82     let (linker, flavor) = linker_and_flavor(sess);
83
84     // The invocations of cc share some flags across platforms
85     let (pname, mut cmd) = get_linker(sess, &linker, flavor);
86
87     let root = sess.target_filesearch(PathKind::Native).get_lib_path();
88     if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
89         cmd.args(args);
90     }
91     if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) {
92         if sess.crt_static() {
93             cmd.args(args);
94         }
95     }
96     if let Some(ref args) = sess.opts.debugging_opts.pre_link_args {
97         cmd.args(args);
98     }
99     cmd.args(&sess.opts.debugging_opts.pre_link_arg);
100
101     let pre_link_objects = if crate_type == config::CrateType::Executable {
102         &sess.target.target.options.pre_link_objects_exe
103     } else {
104         &sess.target.target.options.pre_link_objects_dll
105     };
106     for obj in pre_link_objects {
107         cmd.arg(root.join(obj));
108     }
109
110     if crate_type == config::CrateType::Executable && sess.crt_static() {
111         for obj in &sess.target.target.options.pre_link_objects_exe_crt {
112             cmd.arg(root.join(obj));
113         }
114     }
115
116     if sess.target.target.options.is_like_emscripten {
117         cmd.arg("-s");
118         cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
119             "DISABLE_EXCEPTION_CATCHING=1"
120         } else {
121             "DISABLE_EXCEPTION_CATCHING=0"
122         });
123     }
124
125     {
126         let target_cpu = ::target_lexicon::HOST.to_string();
127         let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor, &target_cpu);
128         link_args(&mut *linker, flavor, sess, crate_type, tmpdir.path(),
129                   out_filename, codegen_results);
130         cmd = linker.finalize();
131     }
132     if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
133         cmd.args(args);
134     }
135     for obj in &sess.target.target.options.post_link_objects {
136         cmd.arg(root.join(obj));
137     }
138     if sess.crt_static() {
139         for obj in &sess.target.target.options.post_link_objects_crt {
140             cmd.arg(root.join(obj));
141         }
142     }
143     if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
144         cmd.args(args);
145     }
146     for &(ref k, ref v) in &sess.target.target.options.link_env {
147         cmd.env(k, v);
148     }
149
150     if sess.opts.debugging_opts.print_link_args {
151         println!("{:?}", &cmd);
152     }
153
154     // May have not found libraries in the right formats.
155     sess.abort_if_errors();
156
157     // Invoke the system linker
158     //
159     // Note that there's a terribly awful hack that really shouldn't be present
160     // in any compiler. Here an environment variable is supported to
161     // automatically retry the linker invocation if the linker looks like it
162     // segfaulted.
163     //
164     // Gee that seems odd, normally segfaults are things we want to know about!
165     // Unfortunately though in rust-lang/rust#38878 we're experiencing the
166     // linker segfaulting on Travis quite a bit which is causing quite a bit of
167     // pain to land PRs when they spuriously fail due to a segfault.
168     //
169     // The issue #38878 has some more debugging information on it as well, but
170     // this unfortunately looks like it's just a race condition in macOS's linker
171     // with some thread pool working in the background. It seems that no one
172     // currently knows a fix for this so in the meantime we're left with this...
173     let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok();
174     let mut prog;
175     let mut i = 0;
176     loop {
177         i += 1;
178         prog = exec_linker(sess, &mut cmd, out_filename, tmpdir.path());
179         let output = match prog {
180             Ok(ref output) => output,
181             Err(_) => break,
182         };
183         if output.status.success() {
184             break
185         }
186         let mut out = output.stderr.clone();
187         out.extend(&output.stdout);
188         let out = String::from_utf8_lossy(&out);
189
190         // Check to see if the link failed with "unrecognized command line option:
191         // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so,
192         // reperform the link step without the -no-pie option. This is safe because
193         // if the linker doesn't support -no-pie then it should not default to
194         // linking executables as pie. Different versions of gcc seem to use
195         // different quotes in the error message so don't check for them.
196         if sess.target.target.options.linker_is_gnu &&
197            flavor != LinkerFlavor::Ld &&
198            (out.contains("unrecognized command line option") ||
199             out.contains("unknown argument")) &&
200            out.contains("-no-pie") &&
201            cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") {
202             for arg in cmd.take_args() {
203                 if arg.to_string_lossy() != "-no-pie" {
204                     cmd.arg(arg);
205                 }
206             }
207             continue;
208         }
209         if !retry_on_segfault || i > 3 {
210             break
211         }
212         let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11";
213         let msg_bus  = "clang: error: unable to execute command: Bus error: 10";
214         if !(out.contains(msg_segv) || out.contains(msg_bus)) {
215             break
216         }
217     }
218
219     match prog {
220         Ok(prog) => {
221             fn escape_string(s: &[u8]) -> String {
222                 str::from_utf8(s).map(|s| s.to_owned())
223                     .unwrap_or_else(|_| {
224                         let mut x = "Non-UTF-8 output: ".to_string();
225                         x.extend(s.iter()
226                                   .flat_map(|&b| ascii::escape_default(b))
227                                   .map(char::from));
228                         x
229                     })
230             }
231             if !prog.status.success() {
232                 let mut output = prog.stderr.clone();
233                 output.extend_from_slice(&prog.stdout);
234                 sess.struct_err(&format!("linking with `{}` failed: {}",
235                                          pname.display(),
236                                          prog.status))
237                     .note(&format!("{:?}", &cmd))
238                     .note(&escape_string(&output))
239                     .emit();
240                 sess.abort_if_errors();
241             }
242         },
243         Err(e) => {
244             let linker_not_found = e.kind() == io::ErrorKind::NotFound;
245
246             let mut linker_error = {
247                 if linker_not_found {
248                     sess.struct_err(&format!("linker `{}` not found", pname.display()))
249                 } else {
250                     sess.struct_err(&format!("could not exec the linker `{}`", pname.display()))
251                 }
252             };
253
254             linker_error.note(&e.to_string());
255
256             if !linker_not_found {
257                 linker_error.note(&format!("{:?}", &cmd));
258             }
259
260             linker_error.emit();
261
262             if sess.target.target.options.is_like_msvc && linker_not_found {
263                 sess.note_without_error("the msvc targets depend on the msvc linker \
264                     but `link.exe` was not found");
265                 sess.note_without_error("please ensure that VS 2013, VS 2015 or VS 2017 \
266                     was installed with the Visual C++ option");
267             }
268             sess.abort_if_errors();
269         }
270     }
271
272
273     // On macOS, debuggers need this utility to get run to do some munging of
274     // the symbols. Note, though, that if the object files are being preserved
275     // for their debug information there's no need for us to run dsymutil.
276     if sess.target.target.options.is_like_osx &&
277         sess.opts.debuginfo != DebugInfo::None
278     {
279         if let Err(e) = Command::new("dsymutil").arg(out_filename).output() {
280             sess.fatal(&format!("failed to run dsymutil: {}", e))
281         }
282     }
283 }
284
285 fn link_args(cmd: &mut dyn Linker,
286              flavor: LinkerFlavor,
287              sess: &Session,
288              crate_type: config::CrateType,
289              tmpdir: &Path,
290              out_filename: &Path,
291              codegen_results: &CodegenResults) {
292
293     // Linker plugins should be specified early in the list of arguments
294     cmd.cross_lang_lto();
295
296     // The default library location, we need this to find the runtime.
297     // The location of crates will be determined as needed.
298     let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
299
300     // target descriptor
301     let t = &sess.target.target;
302
303     cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
304     for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
305         cmd.add_object(obj);
306     }
307     cmd.output_filename(out_filename);
308
309     // If we're building a dynamic library then some platforms need to make sure
310     // that all symbols are exported correctly from the dynamic library.
311     if crate_type != config::CrateType::Executable ||
312        sess.target.target.options.is_like_emscripten {
313         cmd.export_symbols(tmpdir, crate_type);
314     }
315
316     let obj = codegen_results.allocator_module
317         .as_ref()
318         .and_then(|m| m.object.as_ref());
319     if let Some(obj) = obj {
320         cmd.add_object(obj);
321     }
322
323     // Try to strip as much out of the generated object by removing unused
324     // sections if possible. See more comments in linker.rs
325     if !sess.opts.cg.link_dead_code {
326         let keep_metadata = crate_type == config::CrateType::Dylib;
327         cmd.gc_sections(keep_metadata);
328     }
329
330     let used_link_args = &codegen_results.crate_info.link_args;
331
332     if crate_type == config::CrateType::Executable {
333         let mut position_independent_executable = false;
334
335         if t.options.position_independent_executables {
336             let empty_vec = Vec::new();
337             let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
338             let more_args = &sess.opts.cg.link_arg;
339             let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());
340
341             if !sess.crt_static() && !args.any(|x| *x == "-static") {
342                 position_independent_executable = true;
343             }
344         }
345
346         if position_independent_executable {
347             cmd.position_independent_executable();
348         } else {
349             // recent versions of gcc can be configured to generate position
350             // independent executables by default. We have to pass -no-pie to
351             // explicitly turn that off. Not applicable to ld.
352             if sess.target.target.options.linker_is_gnu
353                 && flavor != LinkerFlavor::Ld {
354                 cmd.no_position_independent_executable();
355             }
356         }
357     }
358
359     let relro_level = match sess.opts.debugging_opts.relro_level {
360         Some(level) => level,
361         None => t.options.relro_level,
362     };
363     match relro_level {
364         RelroLevel::Full => {
365             cmd.full_relro();
366         },
367         RelroLevel::Partial => {
368             cmd.partial_relro();
369         },
370         RelroLevel::Off => {
371             cmd.no_relro();
372         },
373         RelroLevel::None => {
374         },
375     }
376
377     // Pass optimization flags down to the linker.
378     cmd.optimize();
379
380     // Pass debuginfo flags down to the linker.
381     cmd.debuginfo();
382
383     // We want to, by default, prevent the compiler from accidentally leaking in
384     // any system libraries, so we may explicitly ask linkers to not link to any
385     // libraries by default. Note that this does not happen for windows because
386     // windows pulls in some large number of libraries and I couldn't quite
387     // figure out which subset we wanted.
388     //
389     // This is all naturally configurable via the standard methods as well.
390     if !sess.opts.cg.default_linker_libraries.unwrap_or(false) &&
391         t.options.no_default_libraries
392     {
393         cmd.no_default_libraries();
394     }
395
396     // Take careful note of the ordering of the arguments we pass to the linker
397     // here. Linkers will assume that things on the left depend on things to the
398     // right. Things on the right cannot depend on things on the left. This is
399     // all formally implemented in terms of resolving symbols (libs on the right
400     // resolve unknown symbols of libs on the left, but not vice versa).
401     //
402     // For this reason, we have organized the arguments we pass to the linker as
403     // such:
404     //
405     //  1. The local object that LLVM just generated
406     //  2. Local native libraries
407     //  3. Upstream rust libraries
408     //  4. Upstream native libraries
409     //
410     // The rationale behind this ordering is that those items lower down in the
411     // list can't depend on items higher up in the list. For example nothing can
412     // depend on what we just generated (e.g. that'd be a circular dependency).
413     // Upstream rust libraries are not allowed to depend on our local native
414     // libraries as that would violate the structure of the DAG, in that
415     // scenario they are required to link to them as well in a shared fashion.
416     //
417     // Note that upstream rust libraries may contain native dependencies as
418     // well, but they also can't depend on what we just started to add to the
419     // link line. And finally upstream native libraries can't depend on anything
420     // in this DAG so far because they're only dylibs and dylibs can only depend
421     // on other dylibs (e.g. other native deps).
422     add_local_native_libraries(cmd, sess, codegen_results);
423     add_upstream_rust_crates(cmd, sess, codegen_results, crate_type, tmpdir);
424     add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
425
426     // Tell the linker what we're doing.
427     if crate_type != config::CrateType::Executable {
428         cmd.build_dylib(out_filename);
429     }
430     if crate_type == config::CrateType::Executable && sess.crt_static() {
431         cmd.build_static_executable();
432     }
433
434     if sess.opts.debugging_opts.pgo_gen.is_some() {
435         cmd.pgo_gen();
436     }
437
438     // Finally add all the linker arguments provided on the command line along
439     // with any #[link_args] attributes found inside the crate
440     if let Some(ref args) = sess.opts.cg.link_args {
441         cmd.args(args);
442     }
443     cmd.args(&sess.opts.cg.link_arg);
444     cmd.args(&used_link_args);
445 }