Skip to content

Commit 5d3fbdd

Browse files
committed
Use more rustc_codegen_ssa::back::link for linking
1 parent 8b3b6f0 commit 5d3fbdd

File tree

3 files changed

+4
-284
lines changed

3 files changed

+4
-284
lines changed

src/link.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use tempfile::Builder as TempFileBuilder;
1111
use rustc::session::config::{self, CrateType, DebugInfo, RUST_CGU_EXT};
1212
use rustc::session::search_paths::PathKind;
1313
use rustc::session::Session;
14+
use rustc_codegen_ssa::METADATA_FILENAME;
1415
use rustc_codegen_ssa::back::command::Command;
1516
use rustc_codegen_ssa::back::link::*;
1617
use rustc_codegen_ssa::back::linker::*;
@@ -48,7 +49,7 @@ pub(crate) fn link_rlib(sess: &Session, res: &CodegenResults, output_name: PathB
4849
builder
4950
.append(
5051
&ar::Header::new(
51-
crate::metadata::METADATA_FILENAME.as_bytes().to_vec(),
52+
METADATA_FILENAME.as_bytes().to_vec(),
5253
res.metadata.raw_data.len() as u64,
5354
),
5455
::std::io::Cursor::new(res.metadata.raw_data.clone()),

src/link_copied.rs

Lines changed: 1 addition & 281 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
//! All functions here are copied from https://github.com/rust-lang/rust/blob/942864a000efd74b73e36bda5606b2cdb55ecf39/src/librustc_codegen_llvm/back/link.rs
22
3-
use std::fmt;
4-
use std::fs;
5-
use std::io;
6-
use std::iter;
73
use std::path::{Path, PathBuf};
8-
use std::process::{Output, Stdio};
9-
10-
use log::info;
114

125
use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind};
136
use rustc::middle::dependency_format::Linkage;
147
use rustc::session::config::{self, OutputType, RUST_CGU_EXT};
158
use rustc::session::search_paths::PathKind;
169
use rustc::session::Session;
1710
use rustc::util::common::time;
18-
use rustc_codegen_ssa::back::command::Command;
11+
use rustc_codegen_ssa::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION};
1912
use rustc_codegen_ssa::back::linker::*;
2013
use rustc_codegen_ssa::back::link::*;
2114
use rustc_data_structures::fx::FxHashSet;
@@ -25,11 +18,6 @@ use syntax::attr;
2518
use crate::prelude::*;
2619

2720
use crate::archive::{ArchiveBuilder, ArchiveConfig};
28-
use crate::metadata::METADATA_FILENAME;
29-
30-
31-
// cg_clif doesn't have bytecode, so this is just a dummy
32-
const RLIB_BYTECODE_EXTENSION: &str = ".cg_clif_bytecode_dummy";
3321

3422
fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
3523
sess.target_filesearch(PathKind::Native).search_path_dirs()
@@ -46,147 +34,6 @@ fn archive_config<'a>(sess: &'a Session,
4634
}
4735
}
4836

49-
pub fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &Path)
50-
-> io::Result<Output>
51-
{
52-
// When attempting to spawn the linker we run a risk of blowing out the
53-
// size limits for spawning a new process with respect to the arguments
54-
// we pass on the command line.
55-
//
56-
// Here we attempt to handle errors from the OS saying "your list of
57-
// arguments is too big" by reinvoking the linker again with an `@`-file
58-
// that contains all the arguments. The theory is that this is then
59-
// accepted on all linkers and the linker will read all its options out of
60-
// there instead of looking at the command line.
61-
if !cmd.very_likely_to_exceed_some_spawn_limit() {
62-
match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
63-
Ok(child) => {
64-
let output = child.wait_with_output();
65-
flush_linked_file(&output, out_filename)?;
66-
return output;
67-
}
68-
Err(ref e) if command_line_too_big(e) => {
69-
info!("command line to linker was too big: {}", e);
70-
}
71-
Err(e) => return Err(e)
72-
}
73-
}
74-
75-
info!("falling back to passing arguments to linker via an @-file");
76-
let mut cmd2 = cmd.clone();
77-
let mut args = String::new();
78-
for arg in cmd2.take_args() {
79-
args.push_str(&Escape {
80-
arg: arg.to_str().unwrap(),
81-
is_like_msvc: sess.target.target.options.is_like_msvc,
82-
}.to_string());
83-
args.push_str("\n");
84-
}
85-
let file = tmpdir.join("linker-arguments");
86-
let bytes = if sess.target.target.options.is_like_msvc {
87-
let mut out = Vec::with_capacity((1 + args.len()) * 2);
88-
// start the stream with a UTF-16 BOM
89-
for c in iter::once(0xFEFF).chain(args.encode_utf16()) {
90-
// encode in little endian
91-
out.push(c as u8);
92-
out.push((c >> 8) as u8);
93-
}
94-
out
95-
} else {
96-
args.into_bytes()
97-
};
98-
fs::write(&file, &bytes)?;
99-
cmd2.arg(format!("@{}", file.display()));
100-
info!("invoking linker {:?}", cmd2);
101-
let output = cmd2.output();
102-
flush_linked_file(&output, out_filename)?;
103-
return output;
104-
105-
#[cfg(unix)]
106-
fn flush_linked_file(_: &io::Result<Output>, _: &Path) -> io::Result<()> {
107-
Ok(())
108-
}
109-
110-
#[cfg(windows)]
111-
fn flush_linked_file(command_output: &io::Result<Output>, out_filename: &Path)
112-
-> io::Result<()>
113-
{
114-
// On Windows, under high I/O load, output buffers are sometimes not flushed,
115-
// even long after process exit, causing nasty, non-reproducible output bugs.
116-
//
117-
// File::sync_all() calls FlushFileBuffers() down the line, which solves the problem.
118-
//
119-
// А full writeup of the original Chrome bug can be found at
120-
// randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/amp
121-
122-
if let &Ok(ref out) = command_output {
123-
if out.status.success() {
124-
if let Ok(of) = fs::OpenOptions::new().write(true).open(out_filename) {
125-
of.sync_all()?;
126-
}
127-
}
128-
}
129-
130-
Ok(())
131-
}
132-
133-
#[cfg(unix)]
134-
fn command_line_too_big(err: &io::Error) -> bool {
135-
err.raw_os_error() == Some(::libc::E2BIG)
136-
}
137-
138-
#[cfg(windows)]
139-
fn command_line_too_big(err: &io::Error) -> bool {
140-
const ERROR_FILENAME_EXCED_RANGE: i32 = 206;
141-
err.raw_os_error() == Some(ERROR_FILENAME_EXCED_RANGE)
142-
}
143-
144-
struct Escape<'a> {
145-
arg: &'a str,
146-
is_like_msvc: bool,
147-
}
148-
149-
impl<'a> fmt::Display for Escape<'a> {
150-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151-
if self.is_like_msvc {
152-
// This is "documented" at
153-
// https://msdn.microsoft.com/en-us/library/4xdcbak7.aspx
154-
//
155-
// Unfortunately there's not a great specification of the
156-
// syntax I could find online (at least) but some local
157-
// testing showed that this seemed sufficient-ish to catch
158-
// at least a few edge cases.
159-
write!(f, "\"")?;
160-
for c in self.arg.chars() {
161-
match c {
162-
'"' => write!(f, "\\{}", c)?,
163-
c => write!(f, "{}", c)?,
164-
}
165-
}
166-
write!(f, "\"")?;
167-
} else {
168-
// This is documented at https://linux.die.net/man/1/ld, namely:
169-
//
170-
// > Options in file are separated by whitespace. A whitespace
171-
// > character may be included in an option by surrounding the
172-
// > entire option in either single or double quotes. Any
173-
// > character (including a backslash) may be included by
174-
// > prefixing the character to be included with a backslash.
175-
//
176-
// We put an argument on each line, so all we need to do is
177-
// ensure the line is interpreted as one whole argument.
178-
for c in self.arg.chars() {
179-
match c {
180-
'\\' | ' ' => write!(f, "\\{}", c)?,
181-
c => write!(f, "{}", c)?,
182-
}
183-
}
184-
}
185-
Ok(())
186-
}
187-
}
188-
}
189-
19037
// # Rust Crate linking
19138
//
19239
// Rust crates are not considered at all when creating an rlib output. All
@@ -505,130 +352,3 @@ pub fn add_upstream_rust_crates(cmd: &mut dyn Linker,
505352
parent.unwrap_or(Path::new("")));
506353
}
507354
}
508-
509-
// # Native library linking
510-
//
511-
// User-supplied library search paths (-L on the command line). These are
512-
// the same paths used to find Rust crates, so some of them may have been
513-
// added already by the previous crate linking code. This only allows them
514-
// to be found at compile time so it is still entirely up to outside
515-
// forces to make sure that library can be found at runtime.
516-
//
517-
// Also note that the native libraries linked here are only the ones located
518-
// in the current crate. Upstream crates with native library dependencies
519-
// may have their native library pulled in above.
520-
pub fn add_local_native_libraries(cmd: &mut dyn Linker,
521-
sess: &Session,
522-
codegen_results: &CodegenResults) {
523-
let filesearch = sess.target_filesearch(PathKind::All);
524-
for search_path in filesearch.search_paths() {
525-
match search_path.kind {
526-
PathKind::Framework => { cmd.framework_path(&search_path.dir); }
527-
_ => { cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir)); }
528-
}
529-
}
530-
531-
let relevant_libs = codegen_results.crate_info.used_libraries.iter().filter(|l| {
532-
relevant_lib(sess, l)
533-
});
534-
535-
let search_path = archive_search_paths(sess);
536-
for lib in relevant_libs {
537-
let name = match lib.name {
538-
Some(ref l) => l,
539-
None => continue,
540-
};
541-
match lib.kind {
542-
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()),
543-
NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()),
544-
NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&name.as_str()),
545-
NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&name.as_str(),
546-
&search_path)
547-
}
548-
}
549-
}
550-
551-
// Link in all of our upstream crates' native dependencies. Remember that
552-
// all of these upstream native dependencies are all non-static
553-
// dependencies. We've got two cases then:
554-
//
555-
// 1. The upstream crate is an rlib. In this case we *must* link in the
556-
// native dependency because the rlib is just an archive.
557-
//
558-
// 2. The upstream crate is a dylib. In order to use the dylib, we have to
559-
// have the dependency present on the system somewhere. Thus, we don't
560-
// gain a whole lot from not linking in the dynamic dependency to this
561-
// crate as well.
562-
//
563-
// The use case for this is a little subtle. In theory the native
564-
// dependencies of a crate are purely an implementation detail of the crate
565-
// itself, but the problem arises with generic and inlined functions. If a
566-
// generic function calls a native function, then the generic function must
567-
// be instantiated in the target crate, meaning that the native symbol must
568-
// also be resolved in the target crate.
569-
pub fn add_upstream_native_libraries(cmd: &mut dyn Linker,
570-
sess: &Session,
571-
codegen_results: &CodegenResults,
572-
crate_type: config::CrateType) {
573-
// Be sure to use a topological sorting of crates because there may be
574-
// interdependencies between native libraries. When passing -nodefaultlibs,
575-
// for example, almost all native libraries depend on libc, so we have to
576-
// make sure that's all the way at the right (liblibc is near the base of
577-
// the dependency chain).
578-
//
579-
// This passes RequireStatic, but the actual requirement doesn't matter,
580-
// we're just getting an ordering of crate numbers, we're not worried about
581-
// the paths.
582-
let formats = sess.dependency_formats.borrow();
583-
let data = formats.get(&crate_type).unwrap();
584-
585-
let crates = &codegen_results.crate_info.used_crates_static;
586-
for &(cnum, _) in crates {
587-
for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
588-
let name = match lib.name {
589-
Some(ref l) => l,
590-
None => continue,
591-
};
592-
if !relevant_lib(sess, &lib) {
593-
continue
594-
}
595-
match lib.kind {
596-
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()),
597-
NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()),
598-
NativeLibraryKind::NativeStaticNobundle => {
599-
// Link "static-nobundle" native libs only if the crate they originate from
600-
// is being linked statically to the current crate. If it's linked dynamically
601-
// or is an rlib already included via some other dylib crate, the symbols from
602-
// native libs will have already been included in that dylib.
603-
if data[cnum.as_usize() - 1] == Linkage::Static {
604-
cmd.link_staticlib(&name.as_str())
605-
}
606-
},
607-
// ignore statically included native libraries here as we've
608-
// already included them when we included the rust library
609-
// previously
610-
NativeLibraryKind::NativeStatic => {}
611-
}
612-
}
613-
}
614-
}
615-
616-
fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
617-
match lib.cfg {
618-
Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None),
619-
None => true,
620-
}
621-
}
622-
623-
fn are_upstream_rust_objects_already_included(sess: &Session) -> bool {
624-
match sess.lto() {
625-
Lto::Fat => true,
626-
Lto::Thin => {
627-
// If we defer LTO to the linker, we haven't run LTO ourselves, so
628-
// any upstream object files have not been copied yet.
629-
!sess.opts.cg.linker_plugin_lto.enabled()
630-
}
631-
Lto::No |
632-
Lto::ThinLocal => false,
633-
}
634-
}

src/metadata.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use rustc::middle::cstore::MetadataLoader;
2+
use rustc_codegen_ssa::METADATA_FILENAME;
23
use rustc_data_structures::owning_ref::{self, OwningRef};
34
use rustc_data_structures::rustc_erase_owner;
45
use std::fs::File;
56
use std::path::Path;
67

7-
pub const METADATA_FILENAME: &str = "rust.metadata.bin";
8-
98
pub struct CraneliftMetadataLoader;
109

1110
impl MetadataLoader for CraneliftMetadataLoader {

0 commit comments

Comments
 (0)