]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
c1a9b12d | 11 | use super::archive::{ArchiveBuilder, ArchiveConfig}; |
abe05a73 | 12 | use super::bytecode::RLIB_BYTECODE_EXTENSION; |
3157f602 | 13 | use super::linker::Linker; |
ea8adc8c | 14 | use super::command::Command; |
1a4d82fc | 15 | use super::rpath::RPathConfig; |
62682a34 | 16 | use super::rpath; |
7cac9316 | 17 | use metadata::METADATA_FILENAME; |
ea8adc8c XL |
18 | use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest}; |
19 | use rustc::session::config::RUST_CGU_EXT; | |
7cac9316 XL |
20 | use rustc::session::filesearch; |
21 | use rustc::session::search_paths::PathKind; | |
22 | use rustc::session::Session; | |
ea8adc8c | 23 | use rustc::middle::cstore::{NativeLibrary, LibSource, NativeLibraryKind}; |
7cac9316 | 24 | use rustc::middle::dependency_format::Linkage; |
ea8adc8c | 25 | use {CrateTranslation, CrateInfo}; |
7cac9316 XL |
26 | use rustc::util::common::time; |
27 | use rustc::util::fs::fix_windows_verbatim_for_gcc; | |
9e0c209e | 28 | use rustc::hir::def_id::CrateNum; |
c34b1796 | 29 | use rustc_back::tempdir::TempDir; |
abe05a73 | 30 | use rustc_back::{PanicStrategy, RelroLevel, LinkerFlavor}; |
8bb4bdeb XL |
31 | use context::get_reloc_model; |
32 | use llvm; | |
1a4d82fc | 33 | |
b039eaaf SL |
34 | use std::ascii; |
35 | use std::char; | |
62682a34 | 36 | use std::env; |
c34b1796 | 37 | use std::ffi::OsString; |
ea8adc8c XL |
38 | use std::fmt; |
39 | use std::fs::{self, File}; | |
abe05a73 | 40 | use std::io::{self, Write, BufWriter}; |
c34b1796 | 41 | use std::path::{Path, PathBuf}; |
ea8adc8c | 42 | use std::process::{Output, Stdio}; |
1a4d82fc | 43 | use std::str; |
476ff2be | 44 | use syntax::attr; |
e9174d1e | 45 | |
8bb4bdeb XL |
46 | /// The LLVM module name containing crate-metadata. This includes a `.` on |
47 | /// purpose, so it cannot clash with the name of a user-defined module. | |
48 | pub const METADATA_MODULE_NAME: &'static str = "crate.metadata"; | |
8bb4bdeb | 49 | |
041b39d2 XL |
50 | // same as for metadata above, but for allocator shim |
51 | pub const ALLOCATOR_MODULE_NAME: &'static str = "crate.allocator"; | |
ea8adc8c XL |
52 | |
53 | pub use rustc_trans_utils::link::{find_crate_name, filename_for_input, default_output_for_target, | |
54 | invalid_output_for_target, build_link_meta, out_filename, | |
55 | check_file_is_writeable}; | |
1a4d82fc | 56 | |
7cac9316 XL |
57 | // The third parameter is for env vars, used on windows to set up the |
58 | // path for MSVC to find its DLLs, and gcc to find its bundled | |
59 | // toolchain | |
60 | pub fn get_linker(sess: &Session) -> (String, Command, Vec<(OsString, OsString)>) { | |
61 | let envs = vec![("PATH".into(), command_path(sess))]; | |
62 | ||
3b2f2976 XL |
63 | // If our linker looks like a batch script on Windows then to execute this |
64 | // we'll need to spawn `cmd` explicitly. This is primarily done to handle | |
65 | // emscripten where the linker is `emcc.bat` and needs to be spawned as | |
66 | // `cmd /c emcc.bat ...`. | |
67 | // | |
68 | // This worked historically but is needed manually since #42436 (regression | |
69 | // was tagged as #42791) and some more info can be found on #44443 for | |
70 | // emscripten itself. | |
71 | let cmd = |linker: &str| { | |
72 | if cfg!(windows) && linker.ends_with(".bat") { | |
73 | let mut cmd = Command::new("cmd"); | |
74 | cmd.arg("/c").arg(linker); | |
75 | cmd | |
76 | } else { | |
77 | Command::new(linker) | |
78 | } | |
79 | }; | |
80 | ||
c1a9b12d | 81 | if let Some(ref linker) = sess.opts.cg.linker { |
3b2f2976 | 82 | (linker.clone(), cmd(linker), envs) |
c1a9b12d | 83 | } else if sess.target.target.options.is_like_msvc { |
7cac9316 XL |
84 | let (cmd, envs) = msvc_link_exe_cmd(sess); |
85 | ("link.exe".to_string(), cmd, envs) | |
86 | } else { | |
87 | let linker = &sess.target.target.options.linker; | |
3b2f2976 | 88 | (linker.clone(), cmd(linker), envs) |
7cac9316 XL |
89 | } |
90 | } | |
91 | ||
92 | #[cfg(windows)] | |
93 | pub fn msvc_link_exe_cmd(sess: &Session) -> (Command, Vec<(OsString, OsString)>) { | |
ea8adc8c | 94 | use cc::windows_registry; |
7cac9316 XL |
95 | |
96 | let target = &sess.opts.target_triple; | |
97 | let tool = windows_registry::find_tool(target, "link.exe"); | |
98 | ||
99 | if let Some(tool) = tool { | |
ea8adc8c XL |
100 | let mut cmd = Command::new(tool.path()); |
101 | cmd.args(tool.args()); | |
102 | for &(ref k, ref v) in tool.env() { | |
103 | cmd.env(k, v); | |
104 | } | |
7cac9316 | 105 | let envs = tool.env().to_vec(); |
ea8adc8c | 106 | (cmd, envs) |
c1a9b12d | 107 | } else { |
7cac9316 XL |
108 | debug!("Failed to locate linker."); |
109 | (Command::new("link.exe"), vec![]) | |
1a4d82fc JJ |
110 | } |
111 | } | |
112 | ||
7cac9316 XL |
113 | #[cfg(not(windows))] |
114 | pub fn msvc_link_exe_cmd(_sess: &Session) -> (Command, Vec<(OsString, OsString)>) { | |
115 | (Command::new("link.exe"), vec![]) | |
116 | } | |
117 | ||
7cac9316 | 118 | fn command_path(sess: &Session) -> OsString { |
62682a34 SL |
119 | // The compiler's sysroot often has some bundled tools, so add it to the |
120 | // PATH for the child. | |
121 | let mut new_path = sess.host_filesearch(PathKind::All) | |
122 | .get_tools_search_paths(); | |
123 | if let Some(path) = env::var_os("PATH") { | |
124 | new_path.extend(env::split_paths(&path)); | |
125 | } | |
126 | env::join_paths(new_path).unwrap() | |
127 | } | |
128 | ||
1a4d82fc | 129 | pub fn remove(sess: &Session, path: &Path) { |
c34b1796 | 130 | match fs::remove_file(path) { |
1a4d82fc JJ |
131 | Ok(..) => {} |
132 | Err(e) => { | |
133 | sess.err(&format!("failed to remove {}: {}", | |
134 | path.display(), | |
c34b1796 | 135 | e)); |
1a4d82fc JJ |
136 | } |
137 | } | |
138 | } | |
139 | ||
140 | /// Perform the linkage portion of the compilation phase. This will generate all | |
141 | /// of the requested outputs for this compilation session. | |
142 | pub fn link_binary(sess: &Session, | |
143 | trans: &CrateTranslation, | |
144 | outputs: &OutputFilenames, | |
c34b1796 | 145 | crate_name: &str) -> Vec<PathBuf> { |
1a4d82fc | 146 | let mut out_filenames = Vec::new(); |
62682a34 | 147 | for &crate_type in sess.crate_types.borrow().iter() { |
3157f602 | 148 | // Ignore executable crates if we have -Z no-trans, as they will error. |
32a655c1 SL |
149 | if (sess.opts.debugging_opts.no_trans || |
150 | !sess.opts.output_types.should_trans()) && | |
5bcae85e | 151 | crate_type == config::CrateTypeExecutable { |
3157f602 XL |
152 | continue; |
153 | } | |
154 | ||
1a4d82fc | 155 | if invalid_output_for_target(sess, crate_type) { |
54a0048b SL |
156 | bug!("invalid output type `{:?}` for target os `{}`", |
157 | crate_type, sess.opts.target_triple); | |
1a4d82fc | 158 | } |
ea8adc8c XL |
159 | let mut out_files = link_binary_output(sess, |
160 | trans, | |
161 | crate_type, | |
162 | outputs, | |
163 | crate_name); | |
32a655c1 | 164 | out_filenames.append(&mut out_files); |
1a4d82fc JJ |
165 | } |
166 | ||
167 | // Remove the temporary object file and metadata if we aren't saving temps | |
168 | if !sess.opts.cg.save_temps { | |
32a655c1 | 169 | if sess.opts.output_types.should_trans() { |
abe05a73 XL |
170 | for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { |
171 | remove(sess, obj); | |
32a655c1 | 172 | } |
1a4d82fc | 173 | } |
abe05a73 XL |
174 | for obj in trans.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) { |
175 | remove(sess, obj); | |
176 | } | |
177 | if let Some(ref obj) = trans.metadata_module.object { | |
178 | remove(sess, obj); | |
179 | } | |
180 | if let Some(ref allocator) = trans.allocator_module { | |
181 | if let Some(ref obj) = allocator.object { | |
182 | remove(sess, obj); | |
183 | } | |
184 | if let Some(ref bc) = allocator.bytecode_compressed { | |
185 | remove(sess, bc); | |
186 | } | |
041b39d2 | 187 | } |
1a4d82fc JJ |
188 | } |
189 | ||
190 | out_filenames | |
191 | } | |
192 | ||
32a655c1 SL |
193 | fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilenames) -> PathBuf { |
194 | let out_filename = outputs.single_output_file.clone() | |
195 | .unwrap_or(outputs | |
196 | .out_directory | |
197 | .join(&format!("lib{}{}.rmeta", crate_name, sess.opts.cg.extra_filename))); | |
198 | check_file_is_writeable(&out_filename, sess); | |
199 | out_filename | |
200 | } | |
201 | ||
e9174d1e | 202 | pub fn each_linked_rlib(sess: &Session, |
ea8adc8c | 203 | info: &CrateInfo, |
041b39d2 | 204 | f: &mut FnMut(CrateNum, &Path)) -> Result<(), String> { |
ea8adc8c | 205 | let crates = info.used_crates_static.iter(); |
e9174d1e | 206 | let fmts = sess.dependency_formats.borrow(); |
a7813a04 XL |
207 | let fmts = fmts.get(&config::CrateTypeExecutable) |
208 | .or_else(|| fmts.get(&config::CrateTypeStaticlib)) | |
9e0c209e | 209 | .or_else(|| fmts.get(&config::CrateTypeCdylib)) |
c30ab7b3 | 210 | .or_else(|| fmts.get(&config::CrateTypeProcMacro)); |
041b39d2 XL |
211 | let fmts = match fmts { |
212 | Some(f) => f, | |
213 | None => return Err(format!("could not find formats for rlibs")) | |
214 | }; | |
ea8adc8c | 215 | for &(cnum, ref path) in crates { |
041b39d2 XL |
216 | match fmts.get(cnum.as_usize() - 1) { |
217 | Some(&Linkage::NotLinked) | | |
218 | Some(&Linkage::IncludedFromDylib) => continue, | |
219 | Some(_) => {} | |
220 | None => return Err(format!("could not find formats for rlibs")) | |
e9174d1e | 221 | } |
ea8adc8c XL |
222 | let name = &info.crate_name[&cnum]; |
223 | let path = match *path { | |
224 | LibSource::Some(ref p) => p, | |
476ff2be | 225 | LibSource::MetadataOnly => { |
041b39d2 XL |
226 | return Err(format!("could not find rlib for: `{}`, found rmeta (metadata) file", |
227 | name)) | |
476ff2be SL |
228 | } |
229 | LibSource::None => { | |
041b39d2 | 230 | return Err(format!("could not find rlib for: `{}`", name)) |
e9174d1e SL |
231 | } |
232 | }; | |
233 | f(cnum, &path); | |
234 | } | |
041b39d2 XL |
235 | Ok(()) |
236 | } | |
237 | ||
238 | /// Returns a boolean indicating whether the specified crate should be ignored | |
239 | /// during LTO. | |
240 | /// | |
241 | /// Crates ignored during LTO are not lumped together in the "massive object | |
242 | /// file" that we create and are linked in their normal rlib states. See | |
243 | /// comments below for what crates do not participate in LTO. | |
244 | /// | |
245 | /// It's unusual for a crate to not participate in LTO. Typically only | |
246 | /// compiler-specific and unstable crates have a reason to not participate in | |
247 | /// LTO. | |
abe05a73 XL |
248 | pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool { |
249 | // If our target enables builtin function lowering in LLVM then the | |
250 | // crates providing these functions don't participate in LTO (e.g. | |
251 | // no_builtins or compiler builtins crates). | |
252 | !sess.target.target.options.no_builtins && | |
253 | (info.is_no_builtins.contains(&cnum) || info.compiler_builtins == Some(cnum)) | |
32a655c1 SL |
254 | } |
255 | ||
1a4d82fc JJ |
256 | fn link_binary_output(sess: &Session, |
257 | trans: &CrateTranslation, | |
258 | crate_type: config::CrateType, | |
259 | outputs: &OutputFilenames, | |
32a655c1 | 260 | crate_name: &str) -> Vec<PathBuf> { |
abe05a73 XL |
261 | for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { |
262 | check_file_is_writeable(obj, sess); | |
1a4d82fc JJ |
263 | } |
264 | ||
32a655c1 SL |
265 | let mut out_filenames = vec![]; |
266 | ||
267 | if outputs.outputs.contains_key(&OutputType::Metadata) { | |
268 | let out_filename = filename_for_metadata(sess, crate_name, outputs); | |
abe05a73 XL |
269 | // To avoid races with another rustc process scanning the output directory, |
270 | // we need to write the file somewhere else and atomically move it to its | |
271 | // final destination, with a `fs::rename` call. In order for the rename to | |
272 | // always succeed, the temporary file needs to be on the same filesystem, | |
273 | // which is why we create it inside the output directory specifically. | |
274 | let metadata_tmpdir = match TempDir::new_in(out_filename.parent().unwrap(), "rmeta") { | |
275 | Ok(tmpdir) => tmpdir, | |
276 | Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)), | |
277 | }; | |
278 | let metadata = emit_metadata(sess, trans, &metadata_tmpdir); | |
279 | if let Err(e) = fs::rename(metadata, &out_filename) { | |
280 | sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); | |
281 | } | |
32a655c1 SL |
282 | out_filenames.push(out_filename); |
283 | } | |
284 | ||
abe05a73 XL |
285 | let tmpdir = match TempDir::new("rustc") { |
286 | Ok(tmpdir) => tmpdir, | |
287 | Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)), | |
288 | }; | |
289 | ||
32a655c1 SL |
290 | if outputs.outputs.should_trans() { |
291 | let out_filename = out_filename(sess, crate_type, outputs, crate_name); | |
292 | match crate_type { | |
293 | config::CrateTypeRlib => { | |
041b39d2 XL |
294 | link_rlib(sess, |
295 | trans, | |
296 | RlibFlavor::Normal, | |
041b39d2 | 297 | &out_filename, |
abe05a73 | 298 | &tmpdir).build(); |
32a655c1 SL |
299 | } |
300 | config::CrateTypeStaticlib => { | |
abe05a73 | 301 | link_staticlib(sess, trans, &out_filename, &tmpdir); |
32a655c1 SL |
302 | } |
303 | _ => { | |
abe05a73 | 304 | link_natively(sess, crate_type, &out_filename, trans, tmpdir.path()); |
32a655c1 | 305 | } |
1a4d82fc | 306 | } |
32a655c1 | 307 | out_filenames.push(out_filename); |
1a4d82fc JJ |
308 | } |
309 | ||
041b39d2 XL |
310 | if sess.opts.cg.save_temps { |
311 | let _ = tmpdir.into_path(); | |
312 | } | |
313 | ||
32a655c1 | 314 | out_filenames |
1a4d82fc JJ |
315 | } |
316 | ||
c34b1796 | 317 | fn archive_search_paths(sess: &Session) -> Vec<PathBuf> { |
1a4d82fc | 318 | let mut search = Vec::new(); |
85aaf69f | 319 | sess.target_filesearch(PathKind::Native).for_each_lib_search_path(|path, _| { |
c34b1796 | 320 | search.push(path.to_path_buf()); |
1a4d82fc JJ |
321 | }); |
322 | return search; | |
323 | } | |
324 | ||
c1a9b12d SL |
325 | fn archive_config<'a>(sess: &'a Session, |
326 | output: &Path, | |
327 | input: Option<&Path>) -> ArchiveConfig<'a> { | |
328 | ArchiveConfig { | |
3b2f2976 | 329 | sess, |
c1a9b12d SL |
330 | dst: output.to_path_buf(), |
331 | src: input.map(|p| p.to_path_buf()), | |
332 | lib_search_paths: archive_search_paths(sess), | |
c1a9b12d SL |
333 | } |
334 | } | |
335 | ||
abe05a73 XL |
336 | /// We use a temp directory here to avoid races between concurrent rustc processes, |
337 | /// such as builds in the same directory using the same filename for metadata while | |
338 | /// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a | |
339 | /// directory being searched for `extern crate` (observing an incomplete file). | |
340 | /// The returned path is the temporary file containing the complete metadata. | |
341 | fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, tmpdir: &TempDir) | |
342 | -> PathBuf { | |
343 | let out_filename = tmpdir.path().join(METADATA_FILENAME); | |
344 | let result = fs::File::create(&out_filename).and_then(|mut f| { | |
cc61c64b XL |
345 | f.write_all(&trans.metadata.raw_data) |
346 | }); | |
347 | ||
476ff2be SL |
348 | if let Err(e) = result { |
349 | sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); | |
350 | } | |
abe05a73 XL |
351 | |
352 | out_filename | |
476ff2be SL |
353 | } |
354 | ||
041b39d2 XL |
355 | enum RlibFlavor { |
356 | Normal, | |
357 | StaticlibBase, | |
358 | } | |
359 | ||
1a4d82fc JJ |
360 | // Create an 'rlib' |
361 | // | |
362 | // An rlib in its current incarnation is essentially a renamed .a file. The | |
363 | // rlib primarily contains the object file of the crate, but it also contains | |
364 | // all of the object files from native libraries. This is done by unzipping | |
365 | // native libraries and inserting all of the contents into this archive. | |
366 | fn link_rlib<'a>(sess: &'a Session, | |
041b39d2 XL |
367 | trans: &CrateTranslation, |
368 | flavor: RlibFlavor, | |
c1a9b12d | 369 | out_filename: &Path, |
abe05a73 | 370 | tmpdir: &TempDir) -> ArchiveBuilder<'a> { |
ea8adc8c | 371 | info!("preparing rlib to {:?}", out_filename); |
c1a9b12d | 372 | let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None)); |
476ff2be | 373 | |
abe05a73 XL |
374 | for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { |
375 | ab.add_file(obj); | |
c1a9b12d | 376 | } |
1a4d82fc | 377 | |
476ff2be SL |
378 | // Note that in this loop we are ignoring the value of `lib.cfg`. That is, |
379 | // we may not be configured to actually include a static library if we're | |
380 | // adding it here. That's because later when we consume this rlib we'll | |
381 | // decide whether we actually needed the static library or not. | |
382 | // | |
383 | // To do this "correctly" we'd need to keep track of which libraries added | |
384 | // which object files to the archive. We don't do that here, however. The | |
385 | // #[link(cfg(..))] feature is unstable, though, and only intended to get | |
386 | // liblibc working. In that sense the check below just indicates that if | |
387 | // there are any libraries we want to omit object files for at link time we | |
388 | // just exclude all custom object files. | |
389 | // | |
390 | // Eventually if we want to stabilize or flesh out the #[link(cfg(..))] | |
391 | // feature then we'll need to figure out how to record what objects were | |
392 | // loaded from the libraries found here and then encode that into the | |
393 | // metadata of the rlib we're generating somehow. | |
ea8adc8c | 394 | for lib in trans.crate_info.used_libraries.iter() { |
476ff2be SL |
395 | match lib.kind { |
396 | NativeLibraryKind::NativeStatic => {} | |
8bb4bdeb | 397 | NativeLibraryKind::NativeStaticNobundle | |
92a42be0 | 398 | NativeLibraryKind::NativeFramework | |
476ff2be | 399 | NativeLibraryKind::NativeUnknown => continue, |
1a4d82fc | 400 | } |
476ff2be | 401 | ab.add_native_library(&lib.name.as_str()); |
1a4d82fc JJ |
402 | } |
403 | ||
404 | // After adding all files to the archive, we need to update the | |
405 | // symbol table of the archive. | |
406 | ab.update_symbols(); | |
407 | ||
1a4d82fc JJ |
408 | // Note that it is important that we add all of our non-object "magical |
409 | // files" *after* all of the object files in the archive. The reason for | |
410 | // this is as follows: | |
411 | // | |
412 | // * When performing LTO, this archive will be modified to remove | |
c1a9b12d | 413 | // objects from above. The reason for this is described below. |
1a4d82fc JJ |
414 | // |
415 | // * When the system linker looks at an archive, it will attempt to | |
416 | // determine the architecture of the archive in order to see whether its | |
417 | // linkable. | |
418 | // | |
419 | // The algorithm for this detection is: iterate over the files in the | |
420 | // archive. Skip magical SYMDEF names. Interpret the first file as an | |
421 | // object file. Read architecture from the object file. | |
422 | // | |
423 | // * As one can probably see, if "metadata" and "foo.bc" were placed | |
424 | // before all of the objects, then the architecture of this archive would | |
425 | // not be correctly inferred once 'foo.o' is removed. | |
426 | // | |
427 | // Basically, all this means is that this code should not move above the | |
428 | // code above. | |
041b39d2 XL |
429 | match flavor { |
430 | RlibFlavor::Normal => { | |
1a4d82fc | 431 | // Instead of putting the metadata in an object file section, rlibs |
abe05a73 XL |
432 | // contain the metadata in a separate file. |
433 | ab.add_file(&emit_metadata(sess, trans, tmpdir)); | |
1a4d82fc JJ |
434 | |
435 | // For LTO purposes, the bytecode of this library is also inserted | |
abe05a73 XL |
436 | // into the archive. |
437 | for bytecode in trans.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) { | |
438 | ab.add_file(bytecode); | |
1a4d82fc JJ |
439 | } |
440 | ||
441 | // After adding all files to the archive, we need to update the | |
cc61c64b | 442 | // symbol table of the archive. This currently dies on macOS (see |
1a4d82fc | 443 | // #11162), and isn't necessary there anyway |
3157f602 | 444 | if !sess.target.target.options.is_like_osx { |
1a4d82fc JJ |
445 | ab.update_symbols(); |
446 | } | |
447 | } | |
448 | ||
041b39d2 | 449 | RlibFlavor::StaticlibBase => { |
abe05a73 XL |
450 | let obj = trans.allocator_module |
451 | .as_ref() | |
452 | .and_then(|m| m.object.as_ref()); | |
453 | if let Some(obj) = obj { | |
454 | ab.add_file(obj); | |
041b39d2 XL |
455 | } |
456 | } | |
1a4d82fc JJ |
457 | } |
458 | ||
459 | ab | |
460 | } | |
461 | ||
1a4d82fc JJ |
462 | // Create a static archive |
463 | // | |
464 | // This is essentially the same thing as an rlib, but it also involves adding | |
465 | // all of the upstream crates' objects into the archive. This will slurp in | |
466 | // all of the native libraries of upstream dependencies as well. | |
467 | // | |
468 | // Additionally, there's no way for us to link dynamic libraries, so we warn | |
469 | // about all dynamic library dependencies that they're not linked in. | |
470 | // | |
471 | // There's no need to include metadata in a static archive, so ensure to not | |
472 | // link in the metadata object file (and also don't prepare the archive with a | |
473 | // metadata file). | |
041b39d2 XL |
474 | fn link_staticlib(sess: &Session, |
475 | trans: &CrateTranslation, | |
041b39d2 | 476 | out_filename: &Path, |
abe05a73 | 477 | tempdir: &TempDir) { |
041b39d2 XL |
478 | let mut ab = link_rlib(sess, |
479 | trans, | |
480 | RlibFlavor::StaticlibBase, | |
041b39d2 XL |
481 | out_filename, |
482 | tempdir); | |
1a4d82fc JJ |
483 | let mut all_native_libs = vec![]; |
484 | ||
ea8adc8c XL |
485 | let res = each_linked_rlib(sess, &trans.crate_info, &mut |cnum, path| { |
486 | let name = &trans.crate_info.crate_name[&cnum]; | |
487 | let native_libs = &trans.crate_info.native_libraries[&cnum]; | |
476ff2be SL |
488 | |
489 | // Here when we include the rlib into our staticlib we need to make a | |
490 | // decision whether to include the extra object files along the way. | |
491 | // These extra object files come from statically included native | |
492 | // libraries, but they may be cfg'd away with #[link(cfg(..))]. | |
493 | // | |
494 | // This unstable feature, though, only needs liblibc to work. The only | |
495 | // use case there is where musl is statically included in liblibc.rlib, | |
496 | // so if we don't want the included version we just need to skip it. As | |
497 | // a result the logic here is that if *any* linked library is cfg'd away | |
498 | // we just skip all object files. | |
499 | // | |
500 | // Clearly this is not sufficient for a general purpose feature, and | |
501 | // we'd want to read from the library's metadata to determine which | |
502 | // object files come from where and selectively skip them. | |
503 | let skip_object_files = native_libs.iter().any(|lib| { | |
504 | lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) | |
505 | }); | |
041b39d2 XL |
506 | ab.add_rlib(path, |
507 | &name.as_str(), | |
abe05a73 | 508 | sess.lto() && !ignored_for_lto(sess, &trans.crate_info, cnum), |
041b39d2 | 509 | skip_object_files).unwrap(); |
476ff2be | 510 | |
ea8adc8c | 511 | all_native_libs.extend(trans.crate_info.native_libraries[&cnum].iter().cloned()); |
e9174d1e | 512 | }); |
041b39d2 XL |
513 | if let Err(e) = res { |
514 | sess.fatal(&e); | |
515 | } | |
1a4d82fc JJ |
516 | |
517 | ab.update_symbols(); | |
c1a9b12d | 518 | ab.build(); |
1a4d82fc JJ |
519 | |
520 | if !all_native_libs.is_empty() { | |
ea8adc8c XL |
521 | if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) { |
522 | print_native_static_libs(sess, &all_native_libs); | |
ea8adc8c | 523 | } |
1a4d82fc | 524 | } |
ea8adc8c XL |
525 | } |
526 | ||
ea8adc8c XL |
527 | fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) { |
528 | let lib_args: Vec<_> = all_native_libs.iter() | |
529 | .filter(|l| relevant_lib(sess, l)) | |
530 | .filter_map(|lib| match lib.kind { | |
531 | NativeLibraryKind::NativeStaticNobundle | | |
532 | NativeLibraryKind::NativeUnknown => { | |
533 | if sess.target.target.options.is_like_msvc { | |
534 | Some(format!("{}.lib", lib.name)) | |
535 | } else { | |
536 | Some(format!("-l{}", lib.name)) | |
537 | } | |
538 | }, | |
539 | NativeLibraryKind::NativeFramework => { | |
540 | // ld-only syntax, since there are no frameworks in MSVC | |
541 | Some(format!("-framework {}", lib.name)) | |
542 | }, | |
543 | // These are included, no need to print them | |
544 | NativeLibraryKind::NativeStatic => None, | |
545 | }) | |
546 | .collect(); | |
547 | if !lib_args.is_empty() { | |
548 | sess.note_without_error("Link against the following native artifacts when linking \ | |
549 | against this static library. The order and any duplication \ | |
550 | can be significant on some platforms."); | |
551 | // Prefix for greppability | |
552 | sess.note_without_error(&format!("native-static-libs: {}", &lib_args.join(" "))); | |
553 | } | |
554 | } | |
555 | ||
1a4d82fc JJ |
556 | // Create a dynamic library or executable |
557 | // | |
558 | // This will invoke the system linker/cc to create the resulting file. This | |
559 | // links to all upstream files as well. | |
a7813a04 XL |
560 | fn link_natively(sess: &Session, |
561 | crate_type: config::CrateType, | |
a7813a04 | 562 | out_filename: &Path, |
e9174d1e | 563 | trans: &CrateTranslation, |
c1a9b12d | 564 | tmpdir: &Path) { |
ea8adc8c | 565 | info!("preparing {:?} to {:?}", crate_type, out_filename); |
cc61c64b | 566 | let flavor = sess.linker_flavor(); |
1a4d82fc | 567 | |
abe05a73 XL |
568 | // The "binaryen linker" is massively special, so skip everything below. |
569 | if flavor == LinkerFlavor::Binaryen { | |
570 | return link_binaryen(sess, crate_type, out_filename, trans, tmpdir); | |
571 | } | |
572 | ||
1a4d82fc | 573 | // The invocations of cc share some flags across platforms |
7cac9316 XL |
574 | let (pname, mut cmd, envs) = get_linker(sess); |
575 | // This will set PATH on windows | |
576 | cmd.envs(envs); | |
1a4d82fc | 577 | |
d9579d0f | 578 | let root = sess.target_filesearch(PathKind::Native).get_lib_path(); |
cc61c64b XL |
579 | if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) { |
580 | cmd.args(args); | |
581 | } | |
7cac9316 XL |
582 | if let Some(ref args) = sess.opts.debugging_opts.pre_link_args { |
583 | cmd.args(args); | |
584 | } | |
585 | cmd.args(&sess.opts.debugging_opts.pre_link_arg); | |
92a42be0 | 586 | |
a7813a04 | 587 | let pre_link_objects = if crate_type == config::CrateTypeExecutable { |
92a42be0 | 588 | &sess.target.target.options.pre_link_objects_exe |
a7813a04 XL |
589 | } else { |
590 | &sess.target.target.options.pre_link_objects_dll | |
92a42be0 SL |
591 | }; |
592 | for obj in pre_link_objects { | |
d9579d0f AL |
593 | cmd.arg(root.join(obj)); |
594 | } | |
595 | ||
8bb4bdeb XL |
596 | if sess.target.target.options.is_like_emscripten { |
597 | cmd.arg("-s"); | |
598 | cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { | |
599 | "DISABLE_EXCEPTION_CATCHING=1" | |
600 | } else { | |
601 | "DISABLE_EXCEPTION_CATCHING=0" | |
602 | }); | |
603 | } | |
604 | ||
62682a34 | 605 | { |
cc61c64b | 606 | let mut linker = trans.linker_info.to_linker(cmd, &sess); |
a7813a04 | 607 | link_args(&mut *linker, sess, crate_type, tmpdir, |
abe05a73 | 608 | out_filename, trans); |
cc61c64b XL |
609 | cmd = linker.finalize(); |
610 | } | |
611 | if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { | |
612 | cmd.args(args); | |
1a4d82fc | 613 | } |
d9579d0f AL |
614 | for obj in &sess.target.target.options.post_link_objects { |
615 | cmd.arg(root.join(obj)); | |
616 | } | |
cc61c64b XL |
617 | if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) { |
618 | cmd.args(args); | |
619 | } | |
041b39d2 XL |
620 | for &(ref k, ref v) in &sess.target.target.options.link_env { |
621 | cmd.env(k, v); | |
622 | } | |
1a4d82fc JJ |
623 | |
624 | if sess.opts.debugging_opts.print_link_args { | |
85aaf69f | 625 | println!("{:?}", &cmd); |
1a4d82fc JJ |
626 | } |
627 | ||
628 | // May have not found libraries in the right formats. | |
629 | sess.abort_if_errors(); | |
630 | ||
631 | // Invoke the system linker | |
8bb4bdeb XL |
632 | // |
633 | // Note that there's a terribly awful hack that really shouldn't be present | |
634 | // in any compiler. Here an environment variable is supported to | |
635 | // automatically retry the linker invocation if the linker looks like it | |
636 | // segfaulted. | |
637 | // | |
638 | // Gee that seems odd, normally segfaults are things we want to know about! | |
639 | // Unfortunately though in rust-lang/rust#38878 we're experiencing the | |
640 | // linker segfaulting on Travis quite a bit which is causing quite a bit of | |
641 | // pain to land PRs when they spuriously fail due to a segfault. | |
642 | // | |
643 | // The issue #38878 has some more debugging information on it as well, but | |
cc61c64b | 644 | // this unfortunately looks like it's just a race condition in macOS's linker |
8bb4bdeb XL |
645 | // with some thread pool working in the background. It seems that no one |
646 | // currently knows a fix for this so in the meantime we're left with this... | |
62682a34 | 647 | info!("{:?}", &cmd); |
8bb4bdeb XL |
648 | let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok(); |
649 | let mut prog; | |
650 | let mut i = 0; | |
651 | loop { | |
652 | i += 1; | |
ea8adc8c XL |
653 | prog = time(sess.time_passes(), "running linker", || { |
654 | exec_linker(sess, &mut cmd, tmpdir) | |
655 | }); | |
8bb4bdeb XL |
656 | if !retry_on_segfault || i > 3 { |
657 | break | |
658 | } | |
659 | let output = match prog { | |
660 | Ok(ref output) => output, | |
661 | Err(_) => break, | |
662 | }; | |
663 | if output.status.success() { | |
664 | break | |
665 | } | |
666 | let mut out = output.stderr.clone(); | |
667 | out.extend(&output.stdout); | |
668 | let out = String::from_utf8_lossy(&out); | |
abe05a73 XL |
669 | let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11"; |
670 | let msg_bus = "clang: error: unable to execute command: Bus error: 10"; | |
671 | if !(out.contains(msg_segv) || out.contains(msg_bus)) { | |
8bb4bdeb XL |
672 | break |
673 | } | |
674 | ||
abe05a73 XL |
675 | warn!( |
676 | "looks like the linker segfaulted when we tried to call it, \ | |
677 | automatically retrying again. cmd = {:?}, out = {}.", | |
678 | cmd, | |
679 | out, | |
680 | ); | |
8bb4bdeb XL |
681 | } |
682 | ||
1a4d82fc JJ |
683 | match prog { |
684 | Ok(prog) => { | |
b039eaaf SL |
685 | fn escape_string(s: &[u8]) -> String { |
686 | str::from_utf8(s).map(|s| s.to_owned()) | |
687 | .unwrap_or_else(|_| { | |
688 | let mut x = "Non-UTF-8 output: ".to_string(); | |
689 | x.extend(s.iter() | |
690 | .flat_map(|&b| ascii::escape_default(b)) | |
691 | .map(|b| char::from_u32(b as u32).unwrap())); | |
692 | x | |
693 | }) | |
694 | } | |
1a4d82fc | 695 | if !prog.status.success() { |
c34b1796 | 696 | let mut output = prog.stderr.clone(); |
92a42be0 | 697 | output.extend_from_slice(&prog.stdout); |
9cc50fc6 SL |
698 | sess.struct_err(&format!("linking with `{}` failed: {}", |
699 | pname, | |
700 | prog.status)) | |
701 | .note(&format!("{:?}", &cmd)) | |
cc61c64b | 702 | .note(&escape_string(&output)) |
9cc50fc6 | 703 | .emit(); |
1a4d82fc JJ |
704 | sess.abort_if_errors(); |
705 | } | |
cc61c64b XL |
706 | info!("linker stderr:\n{}", escape_string(&prog.stderr)); |
707 | info!("linker stdout:\n{}", escape_string(&prog.stdout)); | |
1a4d82fc JJ |
708 | }, |
709 | Err(e) => { | |
3157f602 XL |
710 | sess.struct_err(&format!("could not exec the linker `{}`: {}", pname, e)) |
711 | .note(&format!("{:?}", &cmd)) | |
712 | .emit(); | |
713 | if sess.target.target.options.is_like_msvc && e.kind() == io::ErrorKind::NotFound { | |
714 | sess.note_without_error("the msvc targets depend on the msvc linker \ | |
715 | but `link.exe` was not found"); | |
716 | sess.note_without_error("please ensure that VS 2013 or VS 2015 was installed \ | |
717 | with the Visual C++ option"); | |
718 | } | |
719 | sess.abort_if_errors(); | |
1a4d82fc JJ |
720 | } |
721 | } | |
722 | ||
723 | ||
cc61c64b | 724 | // On macOS, debuggers need this utility to get run to do some munging of |
1a4d82fc JJ |
725 | // the symbols |
726 | if sess.target.target.options.is_like_osx && sess.opts.debuginfo != NoDebugInfo { | |
727 | match Command::new("dsymutil").arg(out_filename).output() { | |
728 | Ok(..) => {} | |
62682a34 | 729 | Err(e) => sess.fatal(&format!("failed to run dsymutil: {}", e)), |
1a4d82fc JJ |
730 | } |
731 | } | |
732 | } | |
733 | ||
ea8adc8c XL |
734 | fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path) |
735 | -> io::Result<Output> | |
736 | { | |
737 | // When attempting to spawn the linker we run a risk of blowing out the | |
738 | // size limits for spawning a new process with respect to the arguments | |
739 | // we pass on the command line. | |
740 | // | |
741 | // Here we attempt to handle errors from the OS saying "your list of | |
742 | // arguments is too big" by reinvoking the linker again with an `@`-file | |
743 | // that contains all the arguments. The theory is that this is then | |
744 | // accepted on all linkers and the linker will read all its options out of | |
745 | // there instead of looking at the command line. | |
746 | match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() { | |
747 | Ok(child) => return child.wait_with_output(), | |
748 | Err(ref e) if command_line_too_big(e) => {} | |
749 | Err(e) => return Err(e) | |
750 | } | |
751 | ||
752 | let file = tmpdir.join("linker-arguments"); | |
753 | let mut cmd2 = Command::new(cmd.get_program()); | |
754 | cmd2.arg(format!("@{}", file.display())); | |
755 | for &(ref k, ref v) in cmd.get_env() { | |
756 | cmd2.env(k, v); | |
757 | } | |
758 | let mut f = BufWriter::new(File::create(&file)?); | |
759 | for arg in cmd.get_args() { | |
760 | writeln!(f, "{}", Escape { | |
761 | arg: arg.to_str().unwrap(), | |
762 | is_like_msvc: sess.target.target.options.is_like_msvc, | |
763 | })?; | |
764 | } | |
765 | f.into_inner()?; | |
766 | return cmd2.output(); | |
767 | ||
768 | #[cfg(unix)] | |
769 | fn command_line_too_big(err: &io::Error) -> bool { | |
770 | err.raw_os_error() == Some(::libc::E2BIG) | |
771 | } | |
772 | ||
773 | #[cfg(windows)] | |
774 | fn command_line_too_big(err: &io::Error) -> bool { | |
775 | const ERROR_FILENAME_EXCED_RANGE: i32 = 206; | |
776 | err.raw_os_error() == Some(ERROR_FILENAME_EXCED_RANGE) | |
777 | } | |
778 | ||
779 | struct Escape<'a> { | |
780 | arg: &'a str, | |
781 | is_like_msvc: bool, | |
782 | } | |
783 | ||
784 | impl<'a> fmt::Display for Escape<'a> { | |
785 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
786 | if self.is_like_msvc { | |
787 | // This is "documented" at | |
788 | // https://msdn.microsoft.com/en-us/library/4xdcbak7.aspx | |
789 | // | |
790 | // Unfortunately there's not a great specification of the | |
791 | // syntax I could find online (at least) but some local | |
792 | // testing showed that this seemed sufficient-ish to catch | |
793 | // at least a few edge cases. | |
794 | write!(f, "\"")?; | |
795 | for c in self.arg.chars() { | |
796 | match c { | |
797 | '"' => write!(f, "\\{}", c)?, | |
798 | c => write!(f, "{}", c)?, | |
799 | } | |
800 | } | |
801 | write!(f, "\"")?; | |
802 | } else { | |
803 | // This is documented at https://linux.die.net/man/1/ld, namely: | |
804 | // | |
805 | // > Options in file are separated by whitespace. A whitespace | |
806 | // > character may be included in an option by surrounding the | |
807 | // > entire option in either single or double quotes. Any | |
808 | // > character (including a backslash) may be included by | |
809 | // > prefixing the character to be included with a backslash. | |
810 | // | |
811 | // We put an argument on each line, so all we need to do is | |
812 | // ensure the line is interpreted as one whole argument. | |
813 | for c in self.arg.chars() { | |
814 | match c { | |
815 | '\\' | | |
816 | ' ' => write!(f, "\\{}", c)?, | |
817 | c => write!(f, "{}", c)?, | |
818 | } | |
819 | } | |
820 | } | |
821 | Ok(()) | |
822 | } | |
823 | } | |
824 | } | |
825 | ||
62682a34 | 826 | fn link_args(cmd: &mut Linker, |
1a4d82fc | 827 | sess: &Session, |
a7813a04 | 828 | crate_type: config::CrateType, |
1a4d82fc | 829 | tmpdir: &Path, |
c1a9b12d | 830 | out_filename: &Path, |
c30ab7b3 | 831 | trans: &CrateTranslation) { |
1a4d82fc JJ |
832 | |
833 | // The default library location, we need this to find the runtime. | |
834 | // The location of crates will be determined as needed. | |
835 | let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); | |
836 | ||
837 | // target descriptor | |
838 | let t = &sess.target.target; | |
839 | ||
62682a34 | 840 | cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); |
abe05a73 XL |
841 | for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { |
842 | cmd.add_object(obj); | |
c1a9b12d | 843 | } |
62682a34 | 844 | cmd.output_filename(out_filename); |
1a4d82fc | 845 | |
c30ab7b3 SL |
846 | if crate_type == config::CrateTypeExecutable && |
847 | sess.target.target.options.is_like_windows { | |
848 | if let Some(ref s) = trans.windows_subsystem { | |
849 | cmd.subsystem(s); | |
850 | } | |
851 | } | |
852 | ||
e9174d1e SL |
853 | // If we're building a dynamic library then some platforms need to make sure |
854 | // that all symbols are exported correctly from the dynamic library. | |
8bb4bdeb XL |
855 | if crate_type != config::CrateTypeExecutable || |
856 | sess.target.target.options.is_like_emscripten { | |
3157f602 | 857 | cmd.export_symbols(tmpdir, crate_type); |
1a4d82fc JJ |
858 | } |
859 | ||
860 | // When linking a dynamic library, we put the metadata into a section of the | |
861 | // executable. This metadata is in a separate object file from the main | |
862 | // object file, so we link that in here. | |
9e0c209e | 863 | if crate_type == config::CrateTypeDylib || |
c30ab7b3 | 864 | crate_type == config::CrateTypeProcMacro { |
abe05a73 XL |
865 | if let Some(obj) = trans.metadata_module.object.as_ref() { |
866 | cmd.add_object(obj); | |
867 | } | |
1a4d82fc JJ |
868 | } |
869 | ||
abe05a73 XL |
870 | let obj = trans.allocator_module |
871 | .as_ref() | |
872 | .and_then(|m| m.object.as_ref()); | |
873 | if let Some(obj) = obj { | |
874 | cmd.add_object(obj); | |
041b39d2 XL |
875 | } |
876 | ||
62682a34 SL |
877 | // Try to strip as much out of the generated object by removing unused |
878 | // sections if possible. See more comments in linker.rs | |
7453a54e | 879 | if !sess.opts.cg.link_dead_code { |
a7813a04 XL |
880 | let keep_metadata = crate_type == config::CrateTypeDylib; |
881 | cmd.gc_sections(keep_metadata); | |
7453a54e | 882 | } |
1a4d82fc | 883 | |
ea8adc8c | 884 | let used_link_args = &trans.crate_info.link_args; |
1a4d82fc | 885 | |
a7813a04 XL |
886 | if crate_type == config::CrateTypeExecutable && |
887 | t.options.position_independent_executables { | |
1a4d82fc | 888 | let empty_vec = Vec::new(); |
1a4d82fc | 889 | let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec); |
9e0c209e SL |
890 | let more_args = &sess.opts.cg.link_arg; |
891 | let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter()); | |
8bb4bdeb XL |
892 | |
893 | if get_reloc_model(sess) == llvm::RelocMode::PIC | |
3b2f2976 | 894 | && !sess.crt_static() && !args.any(|x| *x == "-static") { |
62682a34 | 895 | cmd.position_independent_executable(); |
1a4d82fc JJ |
896 | } |
897 | } | |
898 | ||
3b2f2976 XL |
899 | let relro_level = match sess.opts.debugging_opts.relro_level { |
900 | Some(level) => level, | |
901 | None => t.options.relro_level, | |
902 | }; | |
903 | match relro_level { | |
904 | RelroLevel::Full => { | |
905 | cmd.full_relro(); | |
906 | }, | |
907 | RelroLevel::Partial => { | |
908 | cmd.partial_relro(); | |
909 | }, | |
910 | RelroLevel::Off => {}, | |
911 | } | |
912 | ||
62682a34 SL |
913 | // Pass optimization flags down to the linker. |
914 | cmd.optimize(); | |
1a4d82fc | 915 | |
c1a9b12d SL |
916 | // Pass debuginfo flags down to the linker. |
917 | cmd.debuginfo(); | |
918 | ||
1a4d82fc JJ |
919 | // We want to prevent the compiler from accidentally leaking in any system |
920 | // libraries, so we explicitly ask gcc to not link to any libraries by | |
921 | // default. Note that this does not happen for windows because windows pulls | |
922 | // in some large number of libraries and I couldn't quite figure out which | |
923 | // subset we wanted. | |
b039eaaf SL |
924 | if t.options.no_default_libraries { |
925 | cmd.no_default_libraries(); | |
926 | } | |
1a4d82fc JJ |
927 | |
928 | // Take careful note of the ordering of the arguments we pass to the linker | |
929 | // here. Linkers will assume that things on the left depend on things to the | |
930 | // right. Things on the right cannot depend on things on the left. This is | |
931 | // all formally implemented in terms of resolving symbols (libs on the right | |
932 | // resolve unknown symbols of libs on the left, but not vice versa). | |
933 | // | |
934 | // For this reason, we have organized the arguments we pass to the linker as | |
935 | // such: | |
936 | // | |
937 | // 1. The local object that LLVM just generated | |
b039eaaf SL |
938 | // 2. Local native libraries |
939 | // 3. Upstream rust libraries | |
1a4d82fc JJ |
940 | // 4. Upstream native libraries |
941 | // | |
b039eaaf SL |
942 | // The rationale behind this ordering is that those items lower down in the |
943 | // list can't depend on items higher up in the list. For example nothing can | |
944 | // depend on what we just generated (e.g. that'd be a circular dependency). | |
945 | // Upstream rust libraries are not allowed to depend on our local native | |
946 | // libraries as that would violate the structure of the DAG, in that | |
947 | // scenario they are required to link to them as well in a shared fashion. | |
1a4d82fc | 948 | // |
b039eaaf SL |
949 | // Note that upstream rust libraries may contain native dependencies as |
950 | // well, but they also can't depend on what we just started to add to the | |
951 | // link line. And finally upstream native libraries can't depend on anything | |
952 | // in this DAG so far because they're only dylibs and dylibs can only depend | |
953 | // on other dylibs (e.g. other native deps). | |
ea8adc8c XL |
954 | add_local_native_libraries(cmd, sess, trans); |
955 | add_upstream_rust_crates(cmd, sess, trans, crate_type, tmpdir); | |
956 | add_upstream_native_libraries(cmd, sess, trans, crate_type); | |
1a4d82fc | 957 | |
3b2f2976 | 958 | // Tell the linker what we're doing. |
a7813a04 | 959 | if crate_type != config::CrateTypeExecutable { |
62682a34 | 960 | cmd.build_dylib(out_filename); |
1a4d82fc | 961 | } |
3b2f2976 XL |
962 | if crate_type == config::CrateTypeExecutable && sess.crt_static() { |
963 | cmd.build_static_executable(); | |
964 | } | |
1a4d82fc JJ |
965 | |
966 | // FIXME (#2397): At some point we want to rpath our guesses as to | |
967 | // where extern libraries might live, based on the | |
968 | // addl_lib_search_paths | |
969 | if sess.opts.cg.rpath { | |
970 | let sysroot = sess.sysroot(); | |
c34b1796 AL |
971 | let target_triple = &sess.opts.target_triple; |
972 | let mut get_install_prefix_lib_path = || { | |
1a4d82fc JJ |
973 | let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX"); |
974 | let tlib = filesearch::relative_target_lib_path(sysroot, target_triple); | |
c34b1796 | 975 | let mut path = PathBuf::from(install_prefix); |
1a4d82fc JJ |
976 | path.push(&tlib); |
977 | ||
978 | path | |
979 | }; | |
c34b1796 | 980 | let mut rpath_config = RPathConfig { |
ea8adc8c | 981 | used_crates: &trans.crate_info.used_crates_dynamic, |
c34b1796 | 982 | out_filename: out_filename.to_path_buf(), |
1a4d82fc JJ |
983 | has_rpath: sess.target.target.options.has_rpath, |
984 | is_like_osx: sess.target.target.options.is_like_osx, | |
9cc50fc6 | 985 | linker_is_gnu: sess.target.target.options.linker_is_gnu, |
c34b1796 | 986 | get_install_prefix_lib_path: &mut get_install_prefix_lib_path, |
1a4d82fc | 987 | }; |
c34b1796 | 988 | cmd.args(&rpath::get_rpath_flags(&mut rpath_config)); |
1a4d82fc JJ |
989 | } |
990 | ||
991 | // Finally add all the linker arguments provided on the command line along | |
992 | // with any #[link_args] attributes found inside the crate | |
62682a34 SL |
993 | if let Some(ref args) = sess.opts.cg.link_args { |
994 | cmd.args(args); | |
995 | } | |
9e0c209e | 996 | cmd.args(&sess.opts.cg.link_arg); |
62682a34 | 997 | cmd.args(&used_link_args); |
1a4d82fc JJ |
998 | } |
999 | ||
1000 | // # Native library linking | |
1001 | // | |
1002 | // User-supplied library search paths (-L on the command line). These are | |
1003 | // the same paths used to find Rust crates, so some of them may have been | |
1004 | // added already by the previous crate linking code. This only allows them | |
1005 | // to be found at compile time so it is still entirely up to outside | |
1006 | // forces to make sure that library can be found at runtime. | |
1007 | // | |
1008 | // Also note that the native libraries linked here are only the ones located | |
1009 | // in the current crate. Upstream crates with native library dependencies | |
1010 | // may have their native library pulled in above. | |
ea8adc8c XL |
1011 | fn add_local_native_libraries(cmd: &mut Linker, |
1012 | sess: &Session, | |
1013 | trans: &CrateTranslation) { | |
85aaf69f SL |
1014 | sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path, k| { |
1015 | match k { | |
62682a34 SL |
1016 | PathKind::Framework => { cmd.framework_path(path); } |
1017 | _ => { cmd.include_path(&fix_windows_verbatim_for_gcc(path)); } | |
85aaf69f | 1018 | } |
1a4d82fc JJ |
1019 | }); |
1020 | ||
ea8adc8c | 1021 | let relevant_libs = trans.crate_info.used_libraries.iter().filter(|l| { |
476ff2be | 1022 | relevant_lib(sess, l) |
1a4d82fc | 1023 | }); |
62682a34 | 1024 | |
1a4d82fc | 1025 | let search_path = archive_search_paths(sess); |
cc61c64b | 1026 | for lib in relevant_libs { |
476ff2be SL |
1027 | match lib.kind { |
1028 | NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), | |
1029 | NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()), | |
8bb4bdeb | 1030 | NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&lib.name.as_str()), |
cc61c64b XL |
1031 | NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&lib.name.as_str(), |
1032 | &search_path) | |
1a4d82fc JJ |
1033 | } |
1034 | } | |
1035 | } | |
1036 | ||
1037 | // # Rust Crate linking | |
1038 | // | |
1039 | // Rust crates are not considered at all when creating an rlib output. All | |
1040 | // dependencies will be linked when producing the final output (instead of | |
1041 | // the intermediate rlib version) | |
a7813a04 XL |
1042 | fn add_upstream_rust_crates(cmd: &mut Linker, |
1043 | sess: &Session, | |
ea8adc8c | 1044 | trans: &CrateTranslation, |
a7813a04 XL |
1045 | crate_type: config::CrateType, |
1046 | tmpdir: &Path) { | |
1a4d82fc JJ |
1047 | // All of the heavy lifting has previously been accomplished by the |
1048 | // dependency_format module of the compiler. This is just crawling the | |
1049 | // output of that module, adding crates as necessary. | |
1050 | // | |
1051 | // Linking to a rlib involves just passing it to the linker (the linker | |
1052 | // will slurp up the object files inside), and linking to a dynamic library | |
1053 | // involves just passing the right -l flag. | |
1054 | ||
e9174d1e | 1055 | let formats = sess.dependency_formats.borrow(); |
a7813a04 | 1056 | let data = formats.get(&crate_type).unwrap(); |
1a4d82fc JJ |
1057 | |
1058 | // Invoke get_used_crates to ensure that we get a topological sorting of | |
1059 | // crates. | |
ea8adc8c | 1060 | let deps = &trans.crate_info.used_crates_dynamic; |
1a4d82fc | 1061 | |
9e0c209e SL |
1062 | let mut compiler_builtins = None; |
1063 | ||
ea8adc8c | 1064 | for &(cnum, _) in deps.iter() { |
1a4d82fc JJ |
1065 | // We may not pass all crates through to the linker. Some crates may |
1066 | // appear statically in an existing dylib, meaning we'll pick up all the | |
1067 | // symbols from the dylib. | |
ea8adc8c | 1068 | let src = &trans.crate_info.used_crate_source[&cnum]; |
9e0c209e | 1069 | match data[cnum.as_usize() - 1] { |
ea8adc8c XL |
1070 | _ if trans.crate_info.profiler_runtime == Some(cnum) => { |
1071 | add_static_crate(cmd, sess, trans, tmpdir, crate_type, cnum); | |
041b39d2 | 1072 | } |
ea8adc8c XL |
1073 | _ if trans.crate_info.sanitizer_runtime == Some(cnum) => { |
1074 | link_sanitizer_runtime(cmd, sess, trans, tmpdir, cnum); | |
8bb4bdeb | 1075 | } |
9e0c209e SL |
1076 | // compiler-builtins are always placed last to ensure that they're |
1077 | // linked correctly. | |
ea8adc8c | 1078 | _ if trans.crate_info.compiler_builtins == Some(cnum) => { |
9e0c209e SL |
1079 | assert!(compiler_builtins.is_none()); |
1080 | compiler_builtins = Some(cnum); | |
1081 | } | |
e9174d1e SL |
1082 | Linkage::NotLinked | |
1083 | Linkage::IncludedFromDylib => {} | |
1084 | Linkage::Static => { | |
ea8adc8c | 1085 | add_static_crate(cmd, sess, trans, tmpdir, crate_type, cnum); |
1a4d82fc | 1086 | } |
e9174d1e | 1087 | Linkage::Dynamic => { |
ea8adc8c | 1088 | add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0) |
e9174d1e | 1089 | } |
1a4d82fc | 1090 | } |
1a4d82fc JJ |
1091 | } |
1092 | ||
8bb4bdeb XL |
1093 | // compiler-builtins are always placed last to ensure that they're |
1094 | // linked correctly. | |
9e0c209e SL |
1095 | // We must always link the `compiler_builtins` crate statically. Even if it |
1096 | // was already "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` | |
1097 | // is used) | |
1098 | if let Some(cnum) = compiler_builtins { | |
ea8adc8c | 1099 | add_static_crate(cmd, sess, trans, tmpdir, crate_type, cnum); |
9e0c209e SL |
1100 | } |
1101 | ||
1a4d82fc | 1102 | // Converts a library file-stem into a cc -l argument |
c34b1796 AL |
1103 | fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str { |
1104 | if stem.starts_with("lib") && !config.target.options.is_like_windows { | |
1a4d82fc JJ |
1105 | &stem[3..] |
1106 | } else { | |
1107 | stem | |
1108 | } | |
1109 | } | |
1110 | ||
8bb4bdeb XL |
1111 | // We must link the sanitizer runtime using -Wl,--whole-archive but since |
1112 | // it's packed in a .rlib, it contains stuff that are not objects that will | |
1113 | // make the linker error. So we must remove those bits from the .rlib before | |
1114 | // linking it. | |
1115 | fn link_sanitizer_runtime(cmd: &mut Linker, | |
1116 | sess: &Session, | |
ea8adc8c | 1117 | trans: &CrateTranslation, |
8bb4bdeb XL |
1118 | tmpdir: &Path, |
1119 | cnum: CrateNum) { | |
ea8adc8c XL |
1120 | let src = &trans.crate_info.used_crate_source[&cnum]; |
1121 | let cratepath = &src.rlib.as_ref().unwrap().0; | |
7cac9316 XL |
1122 | |
1123 | if sess.target.target.options.is_like_osx { | |
1124 | // On Apple platforms, the sanitizer is always built as a dylib, and | |
1125 | // LLVM will link to `@rpath/*.dylib`, so we need to specify an | |
1126 | // rpath to the library as well (the rpath should be absolute, see | |
1127 | // PR #41352 for details). | |
1128 | // | |
1129 | // FIXME: Remove this logic into librustc_*san once Cargo supports it | |
1130 | let rpath = cratepath.parent().unwrap(); | |
1131 | let rpath = rpath.to_str().expect("non-utf8 component in path"); | |
1132 | cmd.args(&["-Wl,-rpath".into(), "-Xlinker".into(), rpath.into()]); | |
1133 | } | |
1134 | ||
8bb4bdeb XL |
1135 | let dst = tmpdir.join(cratepath.file_name().unwrap()); |
1136 | let cfg = archive_config(sess, &dst, Some(cratepath)); | |
1137 | let mut archive = ArchiveBuilder::new(cfg); | |
1138 | archive.update_symbols(); | |
1139 | ||
1140 | for f in archive.src_files() { | |
ea8adc8c | 1141 | if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME { |
abe05a73 XL |
1142 | archive.remove_file(&f); |
1143 | continue | |
1144 | } | |
8bb4bdeb XL |
1145 | } |
1146 | ||
1147 | archive.build(); | |
1148 | ||
1149 | cmd.link_whole_rlib(&dst); | |
1150 | } | |
1151 | ||
1a4d82fc | 1152 | // Adds the static "rlib" versions of all crates to the command line. |
c1a9b12d SL |
1153 | // There's a bit of magic which happens here specifically related to LTO and |
1154 | // dynamic libraries. Specifically: | |
1155 | // | |
1156 | // * For LTO, we remove upstream object files. | |
1157 | // * For dylibs we remove metadata and bytecode from upstream rlibs | |
1158 | // | |
9e0c209e SL |
1159 | // When performing LTO, almost(*) all of the bytecode from the upstream |
1160 | // libraries has already been included in our object file output. As a | |
1161 | // result we need to remove the object files in the upstream libraries so | |
1162 | // the linker doesn't try to include them twice (or whine about duplicate | |
1163 | // symbols). We must continue to include the rest of the rlib, however, as | |
1164 | // it may contain static native libraries which must be linked in. | |
1165 | // | |
1166 | // (*) Crates marked with `#![no_builtins]` don't participate in LTO and | |
1167 | // their bytecode wasn't included. The object files in those libraries must | |
1168 | // still be passed to the linker. | |
c1a9b12d SL |
1169 | // |
1170 | // When making a dynamic library, linkers by default don't include any | |
1171 | // object files in an archive if they're not necessary to resolve the link. | |
1172 | // We basically want to convert the archive (rlib) to a dylib, though, so we | |
1173 | // *do* want everything included in the output, regardless of whether the | |
1174 | // linker thinks it's needed or not. As a result we must use the | |
1175 | // --whole-archive option (or the platform equivalent). When using this | |
1176 | // option the linker will fail if there are non-objects in the archive (such | |
1177 | // as our own metadata and/or bytecode). All in all, for rlibs to be | |
1178 | // entirely included in dylibs, we need to remove all non-object files. | |
1179 | // | |
1180 | // Note, however, that if we're not doing LTO or we're not producing a dylib | |
1181 | // (aka we're making an executable), we can just pass the rlib blindly to | |
1182 | // the linker (fast) because it's fine if it's not actually included as | |
1183 | // we're at the end of the dependency chain. | |
a7813a04 XL |
1184 | fn add_static_crate(cmd: &mut Linker, |
1185 | sess: &Session, | |
ea8adc8c | 1186 | trans: &CrateTranslation, |
a7813a04 XL |
1187 | tmpdir: &Path, |
1188 | crate_type: config::CrateType, | |
9e0c209e | 1189 | cnum: CrateNum) { |
ea8adc8c XL |
1190 | let src = &trans.crate_info.used_crate_source[&cnum]; |
1191 | let cratepath = &src.rlib.as_ref().unwrap().0; | |
476ff2be SL |
1192 | |
1193 | // See the comment above in `link_staticlib` and `link_rlib` for why if | |
1194 | // there's a static library that's not relevant we skip all object | |
1195 | // files. | |
ea8adc8c | 1196 | let native_libs = &trans.crate_info.native_libraries[&cnum]; |
476ff2be SL |
1197 | let skip_native = native_libs.iter().any(|lib| { |
1198 | lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) | |
1199 | }); | |
1200 | ||
abe05a73 | 1201 | if (!sess.lto() || ignored_for_lto(sess, &trans.crate_info, cnum)) && |
041b39d2 XL |
1202 | crate_type != config::CrateTypeDylib && |
1203 | !skip_native { | |
c1a9b12d SL |
1204 | cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); |
1205 | return | |
1206 | } | |
1207 | ||
1208 | let dst = tmpdir.join(cratepath.file_name().unwrap()); | |
1209 | let name = cratepath.file_name().unwrap().to_str().unwrap(); | |
1210 | let name = &name[3..name.len() - 5]; // chop off lib/.rlib | |
1211 | ||
e9174d1e | 1212 | time(sess.time_passes(), &format!("altering {}.rlib", name), || { |
c1a9b12d SL |
1213 | let cfg = archive_config(sess, &dst, Some(cratepath)); |
1214 | let mut archive = ArchiveBuilder::new(cfg); | |
c1a9b12d SL |
1215 | archive.update_symbols(); |
1216 | ||
1217 | let mut any_objects = false; | |
1218 | for f in archive.src_files() { | |
ea8adc8c | 1219 | if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME { |
c1a9b12d SL |
1220 | archive.remove_file(&f); |
1221 | continue | |
1a4d82fc | 1222 | } |
476ff2be | 1223 | |
c1a9b12d SL |
1224 | let canonical = f.replace("-", "_"); |
1225 | let canonical_name = name.replace("-", "_"); | |
9e0c209e | 1226 | |
abe05a73 | 1227 | // Look for `.rcgu.o` at the end of the filename to conclude |
ea8adc8c XL |
1228 | // that this is a Rust-related object file. |
1229 | fn looks_like_rust(s: &str) -> bool { | |
1230 | let path = Path::new(s); | |
1231 | let ext = path.extension().and_then(|s| s.to_str()); | |
1232 | if ext != Some(OutputType::Object.extension()) { | |
1233 | return false | |
1234 | } | |
1235 | let ext2 = path.file_stem() | |
1236 | .and_then(|s| Path::new(s).extension()) | |
1237 | .and_then(|s| s.to_str()); | |
1238 | ext2 == Some(RUST_CGU_EXT) | |
1239 | } | |
1240 | ||
476ff2be | 1241 | let is_rust_object = |
ea8adc8c XL |
1242 | canonical.starts_with(&canonical_name) && |
1243 | looks_like_rust(&f); | |
476ff2be SL |
1244 | |
1245 | // If we've been requested to skip all native object files | |
1246 | // (those not generated by the rust compiler) then we can skip | |
1247 | // this file. See above for why we may want to do this. | |
1248 | let skip_because_cfg_say_so = skip_native && !is_rust_object; | |
1249 | ||
9e0c209e SL |
1250 | // If we're performing LTO and this is a rust-generated object |
1251 | // file, then we don't need the object file as it's part of the | |
1252 | // LTO module. Note that `#![no_builtins]` is excluded from LTO, | |
1253 | // though, so we let that object file slide. | |
abe05a73 XL |
1254 | let skip_because_lto = sess.lto() && |
1255 | is_rust_object && | |
1256 | (sess.target.target.options.no_builtins || | |
1257 | !trans.crate_info.is_no_builtins.contains(&cnum)); | |
476ff2be SL |
1258 | |
1259 | if skip_because_cfg_say_so || skip_because_lto { | |
1260 | archive.remove_file(&f); | |
1261 | } else { | |
1262 | any_objects = true; | |
1a4d82fc | 1263 | } |
c1a9b12d SL |
1264 | } |
1265 | ||
9e0c209e SL |
1266 | if !any_objects { |
1267 | return | |
1268 | } | |
1269 | archive.build(); | |
1270 | ||
1271 | // If we're creating a dylib, then we need to include the | |
1272 | // whole of each object in our archive into that artifact. This is | |
1273 | // because a `dylib` can be reused as an intermediate artifact. | |
1274 | // | |
1275 | // Note, though, that we don't want to include the whole of a | |
1276 | // compiler-builtins crate (e.g. compiler-rt) because it'll get | |
1277 | // repeatedly linked anyway. | |
1278 | if crate_type == config::CrateTypeDylib && | |
ea8adc8c | 1279 | trans.crate_info.compiler_builtins != Some(cnum) { |
9e0c209e SL |
1280 | cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); |
1281 | } else { | |
1282 | cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst)); | |
c1a9b12d SL |
1283 | } |
1284 | }); | |
1a4d82fc JJ |
1285 | } |
1286 | ||
1287 | // Same thing as above, but for dynamic crates instead of static crates. | |
62682a34 | 1288 | fn add_dynamic_crate(cmd: &mut Linker, sess: &Session, cratepath: &Path) { |
1a4d82fc JJ |
1289 | // If we're performing LTO, then it should have been previously required |
1290 | // that all upstream rust dependencies were available in an rlib format. | |
1291 | assert!(!sess.lto()); | |
1292 | ||
1293 | // Just need to tell the linker about where the library lives and | |
1294 | // what its name is | |
c1a9b12d SL |
1295 | let parent = cratepath.parent(); |
1296 | if let Some(dir) = parent { | |
62682a34 | 1297 | cmd.include_path(&fix_windows_verbatim_for_gcc(dir)); |
c34b1796 AL |
1298 | } |
1299 | let filestem = cratepath.file_stem().unwrap().to_str().unwrap(); | |
c1a9b12d SL |
1300 | cmd.link_rust_dylib(&unlib(&sess.target, filestem), |
1301 | parent.unwrap_or(Path::new(""))); | |
1a4d82fc JJ |
1302 | } |
1303 | } | |
1304 | ||
1305 | // Link in all of our upstream crates' native dependencies. Remember that | |
1306 | // all of these upstream native dependencies are all non-static | |
1307 | // dependencies. We've got two cases then: | |
1308 | // | |
1309 | // 1. The upstream crate is an rlib. In this case we *must* link in the | |
1310 | // native dependency because the rlib is just an archive. | |
1311 | // | |
1312 | // 2. The upstream crate is a dylib. In order to use the dylib, we have to | |
1313 | // have the dependency present on the system somewhere. Thus, we don't | |
1314 | // gain a whole lot from not linking in the dynamic dependency to this | |
1315 | // crate as well. | |
1316 | // | |
1317 | // The use case for this is a little subtle. In theory the native | |
1318 | // dependencies of a crate are purely an implementation detail of the crate | |
1319 | // itself, but the problem arises with generic and inlined functions. If a | |
1320 | // generic function calls a native function, then the generic function must | |
1321 | // be instantiated in the target crate, meaning that the native symbol must | |
1322 | // also be resolved in the target crate. | |
ea8adc8c XL |
1323 | fn add_upstream_native_libraries(cmd: &mut Linker, |
1324 | sess: &Session, | |
1325 | trans: &CrateTranslation, | |
1326 | crate_type: config::CrateType) { | |
1a4d82fc JJ |
1327 | // Be sure to use a topological sorting of crates because there may be |
1328 | // interdependencies between native libraries. When passing -nodefaultlibs, | |
1329 | // for example, almost all native libraries depend on libc, so we have to | |
1330 | // make sure that's all the way at the right (liblibc is near the base of | |
1331 | // the dependency chain). | |
1332 | // | |
1333 | // This passes RequireStatic, but the actual requirement doesn't matter, | |
1334 | // we're just getting an ordering of crate numbers, we're not worried about | |
1335 | // the paths. | |
8bb4bdeb XL |
1336 | let formats = sess.dependency_formats.borrow(); |
1337 | let data = formats.get(&crate_type).unwrap(); | |
1338 | ||
ea8adc8c XL |
1339 | let crates = &trans.crate_info.used_crates_static; |
1340 | for &(cnum, _) in crates { | |
1341 | for lib in trans.crate_info.native_libraries[&cnum].iter() { | |
476ff2be SL |
1342 | if !relevant_lib(sess, &lib) { |
1343 | continue | |
1344 | } | |
1345 | match lib.kind { | |
1346 | NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), | |
1347 | NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()), | |
8bb4bdeb XL |
1348 | NativeLibraryKind::NativeStaticNobundle => { |
1349 | // Link "static-nobundle" native libs only if the crate they originate from | |
1350 | // is being linked statically to the current crate. If it's linked dynamically | |
1351 | // or is an rlib already included via some other dylib crate, the symbols from | |
1352 | // native libs will have already been included in that dylib. | |
1353 | if data[cnum.as_usize() - 1] == Linkage::Static { | |
1354 | cmd.link_staticlib(&lib.name.as_str()) | |
1355 | } | |
1356 | }, | |
476ff2be SL |
1357 | // ignore statically included native libraries here as we've |
1358 | // already included them when we included the rust library | |
1359 | // previously | |
1360 | NativeLibraryKind::NativeStatic => {} | |
1a4d82fc JJ |
1361 | } |
1362 | } | |
1363 | } | |
1364 | } | |
476ff2be SL |
1365 | |
1366 | fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { | |
1367 | match lib.cfg { | |
1368 | Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None), | |
1369 | None => true, | |
1370 | } | |
1371 | } | |
abe05a73 XL |
1372 | |
1373 | /// For now "linking with binaryen" is just "move the one module we generated in | |
1374 | /// the backend to the final output" | |
1375 | /// | |
1376 | /// That is, all the heavy lifting happens during the `back::write` phase. Here | |
1377 | /// we just clean up after that. | |
1378 | /// | |
1379 | /// Note that this is super temporary and "will not survive the night", this is | |
1380 | /// guaranteed to get removed as soon as a linker for wasm exists. This should | |
1381 | /// not be used for anything other than wasm. | |
1382 | fn link_binaryen(sess: &Session, | |
1383 | _crate_type: config::CrateType, | |
1384 | out_filename: &Path, | |
1385 | trans: &CrateTranslation, | |
1386 | _tmpdir: &Path) { | |
1387 | assert!(trans.allocator_module.is_none()); | |
1388 | assert_eq!(trans.modules.len(), 1); | |
1389 | ||
1390 | let object = trans.modules[0].object.as_ref().expect("object must exist"); | |
1391 | let res = fs::hard_link(object, out_filename) | |
1392 | .or_else(|_| fs::copy(object, out_filename).map(|_| ())); | |
1393 | if let Err(e) = res { | |
1394 | sess.fatal(&format!("failed to create `{}`: {}", | |
1395 | out_filename.display(), | |
1396 | e)); | |
1397 | } | |
1398 | } |