Skip to content

Commit

Permalink
Auto merge of #26869 - alexcrichton:fix-msvc-sepcomp, r=nrc
Browse files Browse the repository at this point in the history
This commit alters the implementation of multiple codegen units slightly to be
compatible with the MSVC linker. Currently the implementation will take the N
object files created by each codegen unit and will run `ld -r` to create a new
object file which is then passed along. The MSVC linker, however, is not able to
do this operation.

The compiler will now no longer attempt to assemble object files together but
will instead just pass through all the object files as usual. This implies that
rlibs may not contain more than one object file (if the library is compiled with
more than one codegen unit) and the output of `-C save-temps` will have changed
slightly as object files with the extension `0.o` will not be renamed to `o`
unless requested otherwise.
  • Loading branch information
bors committed Jul 8, 2015
2 parents 020d201 + 9bc8e6d commit 9f26f14
Show file tree
Hide file tree
Showing 18 changed files with 289 additions and 252 deletions.
1 change: 1 addition & 0 deletions src/liballoc/lib.rs
Expand Up @@ -148,4 +148,5 @@ pub fn oom() -> ! {
// optimize it out).
#[doc(hidden)]
#[unstable(feature = "issue_14344_fixme")]
#[cfg(stage0)]
pub fn fixme_14344_be_sure_to_link_to_collections() {}
1 change: 1 addition & 0 deletions src/libcollections/lib.rs
Expand Up @@ -138,6 +138,7 @@ pub mod btree_set {
// FIXME(#14344) this shouldn't be necessary
#[doc(hidden)]
#[unstable(feature = "issue_14344_fixme")]
#[cfg(stage0)]
pub fn fixme_14344_be_sure_to_link_to_collections() {}

#[cfg(not(test))]
Expand Down
1 change: 1 addition & 0 deletions src/liblibc/lib.rs
Expand Up @@ -6431,6 +6431,7 @@ pub mod funcs {
}

#[doc(hidden)]
#[cfg(stage0)]
pub fn issue_14344_workaround() {} // FIXME #14344 force linkage to happen correctly

#[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows
6 changes: 1 addition & 5 deletions src/librustc/metadata/encoder.rs
Expand Up @@ -2136,11 +2136,7 @@ fn encode_metadata_inner(wr: &mut Cursor<Vec<u8>>,
let mut rbml_w = Encoder::new(wr);

encode_crate_name(&mut rbml_w, &ecx.link_meta.crate_name);
encode_crate_triple(&mut rbml_w,
&tcx.sess
.opts
.target_triple
);
encode_crate_triple(&mut rbml_w, &tcx.sess.opts.target_triple);
encode_hash(&mut rbml_w, &ecx.link_meta.crate_hash);
encode_dylib_dependency_formats(&mut rbml_w, &ecx);

Expand Down
4 changes: 2 additions & 2 deletions src/librustc_driver/driver.rs
Expand Up @@ -804,8 +804,8 @@ fn write_out_deps(sess: &Session,
match *output_type {
config::OutputTypeExe => {
for output in sess.crate_types.borrow().iter() {
let p = link::filename_for_input(sess, *output,
id, &file);
let p = link::filename_for_input(sess, *output, id,
outputs);
out_filenames.push(p);
}
}
Expand Down
6 changes: 2 additions & 4 deletions src/librustc_driver/lib.rs
Expand Up @@ -452,10 +452,8 @@ impl RustcDefaultCalls {
let metadata = driver::collect_crate_metadata(sess, attrs);
*sess.crate_metadata.borrow_mut() = metadata;
for &style in &crate_types {
let fname = link::filename_for_input(sess,
style,
&id,
&t_outputs.with_extension(""));
let fname = link::filename_for_input(sess, style, &id,
&t_outputs);
println!("{}", fname.file_name().unwrap()
.to_string_lossy());
}
Expand Down
266 changes: 139 additions & 127 deletions src/librustc_trans/back/link.rs

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions src/librustc_trans/back/linker.rs
Expand Up @@ -30,6 +30,7 @@ pub trait Linker {
fn link_framework(&mut self, framework: &str);
fn link_staticlib(&mut self, lib: &str);
fn link_rlib(&mut self, lib: &Path);
fn link_whole_rlib(&mut self, lib: &Path);
fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]);
fn include_path(&mut self, path: &Path);
fn framework_path(&mut self, path: &Path);
Expand Down Expand Up @@ -96,6 +97,17 @@ impl<'a> Linker for GnuLinker<'a> {
}
}

fn link_whole_rlib(&mut self, lib: &Path) {
if self.sess.target.target.options.is_like_osx {
let mut v = OsString::from("-Wl,-force_load,");
v.push(lib);
self.cmd.arg(&v);
} else {
self.cmd.arg("-Wl,--whole-archive").arg(lib)
.arg("-Wl,--no-whole-archive");
}
}

fn gc_sections(&mut self, is_dylib: bool) {
// The dead_strip option to the linker specifies that functions and data
// unreachable by the entry point will be removed. This is quite useful
Expand Down Expand Up @@ -250,6 +262,10 @@ impl<'a> Linker for MsvcLinker<'a> {
// not supported?
self.link_staticlib(lib);
}
fn link_whole_rlib(&mut self, path: &Path) {
// not supported?
self.link_rlib(path);
}
fn optimize(&mut self) {
// Needs more investigation of `/OPT` arguments
}
Expand Down
39 changes: 9 additions & 30 deletions src/librustc_trans/back/lto.rs
Expand Up @@ -56,33 +56,14 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
};

let archive = ArchiveRO::open(&path).expect("wanted an rlib");
let file = path.file_name().unwrap().to_str().unwrap();
let file = &file[3..file.len() - 5]; // chop off lib/.rlib
debug!("reading {}", file);
for i in 0.. {
let filename = format!("{}.{}.bytecode.deflate", file, i);
let msg = format!("check for {}", filename);
let bc_encoded = time(sess.time_passes(), &msg, (), |_| {
archive.iter().find(|section| {
section.name() == Some(&filename[..])
})
});
let bc_encoded = match bc_encoded {
Some(data) => data,
None => {
if i == 0 {
// No bitcode was found at all.
sess.fatal(&format!("missing compressed bytecode in {}",
path.display()));
}
// No more bitcode files to read.
break
}
};
let bc_encoded = bc_encoded.data();
let bytecodes = archive.iter().filter_map(|child| {
child.name().map(|name| (name, child))
}).filter(|&(name, _)| name.ends_with("bytecode.deflate"));
for (name, data) in bytecodes {
let bc_encoded = data.data();

let bc_decoded = if is_versioned_bytecode_format(bc_encoded) {
time(sess.time_passes(), &format!("decode {}.{}.bc", file, i), (), |_| {
time(sess.time_passes(), &format!("decode {}", name), (), |_| {
// Read the version
let version = extract_bytecode_format_version(bc_encoded);

Expand All @@ -106,7 +87,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
}
})
} else {
time(sess.time_passes(), &format!("decode {}.{}.bc", file, i), (), |_| {
time(sess.time_passes(), &format!("decode {}", name), (), |_| {
// the object must be in the old, pre-versioning format, so simply
// inflate everything and let LLVM decide if it can make sense of it
match flate::inflate_bytes(bc_encoded) {
Expand All @@ -120,10 +101,8 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
};

let ptr = bc_decoded.as_ptr();
debug!("linking {}, part {}", name, i);
time(sess.time_passes(),
&format!("ll link {}.{}", name, i),
(),
debug!("linking {}", name);
time(sess.time_passes(), &format!("ll link {}", name), (),
|()| unsafe {
if !llvm::LLVMRustLinkInExternalBitcode(llmod,
ptr as *const libc::c_char,
Expand Down
95 changes: 14 additions & 81 deletions src/librustc_trans/back/write.rs
Expand Up @@ -27,7 +27,6 @@ use std::ffi::{CStr, CString};
use std::fs;
use std::mem;
use std::path::Path;
use std::process::Stdio;
use std::ptr;
use std::str;
use std::sync::{Arc, Mutex};
Expand Down Expand Up @@ -619,6 +618,8 @@ pub fn run_passes(sess: &Session,
let needs_crate_bitcode =
sess.crate_types.borrow().contains(&config::CrateTypeRlib) &&
sess.opts.output_types.contains(&config::OutputTypeExe);
let needs_crate_object =
sess.opts.output_types.contains(&config::OutputTypeExe);
if needs_crate_bitcode {
modules_config.emit_bc = true;
}
Expand Down Expand Up @@ -696,7 +697,8 @@ pub fn run_passes(sess: &Session,
if sess.opts.cg.codegen_units == 1 {
// 1) Only one codegen unit. In this case it's no difficulty
// to copy `foo.0.x` to `foo.x`.
copy_gracefully(&crate_output.with_extension(ext), &crate_output.path(output_type));
copy_gracefully(&crate_output.with_extension(ext),
&crate_output.path(output_type));
if !sess.opts.cg.save_temps && !keep_numbered {
// The user just wants `foo.x`, not `foo.0.x`.
remove(sess, &crate_output.with_extension(ext));
Expand All @@ -715,76 +717,11 @@ pub fn run_passes(sess: &Session,
}
};

let link_obj = |output_path: &Path| {
// Running `ld -r` on a single input is kind of pointless.
if sess.opts.cg.codegen_units == 1 {
copy_gracefully(&crate_output.with_extension("0.o"), output_path);
// Leave the .0.o file around, to mimic the behavior of the normal
// code path.
return;
}

// Some builds of MinGW GCC will pass --force-exe-suffix to ld, which
// will automatically add a .exe extension if the extension is not
// already .exe or .dll. To ensure consistent behavior on Windows, we
// add the .exe suffix explicitly and then rename the output file to
// the desired path. This will give the correct behavior whether or
// not GCC adds --force-exe-suffix.
let windows_output_path =
if sess.target.target.options.is_like_windows {
Some(output_path.with_extension("o.exe"))
} else {
None
};

let (pname, mut cmd) = get_linker(sess);

cmd.args(&sess.target.target.options.pre_link_args);
cmd.arg("-nostdlib");

for index in 0..trans.modules.len() {
cmd.arg(&crate_output.with_extension(&format!("{}.o", index)));
}

cmd.arg("-r").arg("-o")
.arg(windows_output_path.as_ref().map(|s| &**s).unwrap_or(output_path));

cmd.args(&sess.target.target.options.post_link_args);

if sess.opts.debugging_opts.print_link_args {
println!("{:?}", &cmd);
}

cmd.stdin(Stdio::null());
match cmd.status() {
Ok(status) => {
if !status.success() {
sess.err(&format!("linking of {} with `{:?}` failed",
output_path.display(), cmd));
sess.abort_if_errors();
}
},
Err(e) => {
sess.err(&format!("could not exec the linker `{}`: {}",
pname, e));
sess.abort_if_errors();
},
}

match windows_output_path {
Some(ref windows_path) => {
fs::rename(windows_path, output_path).unwrap();
},
None => {
// The file is already named according to `output_path`.
}
}
};

// Flag to indicate whether the user explicitly requested bitcode.
// Otherwise, we produced it only as a temporary output, and will need
// to get rid of it.
let mut user_wants_bitcode = false;
let mut user_wants_objects = false;
for output_type in output_types {
match *output_type {
config::OutputTypeBitcode => {
Expand All @@ -801,17 +738,10 @@ pub fn run_passes(sess: &Session,
copy_if_one_unit("0.s", config::OutputTypeAssembly, false);
}
config::OutputTypeObject => {
link_obj(&crate_output.path(config::OutputTypeObject));
}
config::OutputTypeExe => {
// If config::OutputTypeObject is already in the list, then
// `crate.o` will be handled by the config::OutputTypeObject case.
// Otherwise, we need to create the temporary object so we
// can run the linker.
if !sess.opts.output_types.contains(&config::OutputTypeObject) {
link_obj(&crate_output.temp_path(config::OutputTypeObject));
}
user_wants_objects = true;
copy_if_one_unit("0.o", config::OutputTypeObject, true);
}
config::OutputTypeExe |
config::OutputTypeDepInfo => {}
}
}
Expand Down Expand Up @@ -848,15 +778,18 @@ pub fn run_passes(sess: &Session,
let keep_numbered_bitcode = needs_crate_bitcode ||
(user_wants_bitcode && sess.opts.cg.codegen_units > 1);

let keep_numbered_objects = needs_crate_object ||
(user_wants_objects && sess.opts.cg.codegen_units > 1);

for i in 0..trans.modules.len() {
if modules_config.emit_obj {
if modules_config.emit_obj && !keep_numbered_objects {
let ext = format!("{}.o", i);
remove(sess, &crate_output.with_extension(&ext[..]));
remove(sess, &crate_output.with_extension(&ext));
}

if modules_config.emit_bc && !keep_numbered_bitcode {
let ext = format!("{}.bc", i);
remove(sess, &crate_output.with_extension(&ext[..]));
remove(sess, &crate_output.with_extension(&ext));
}
}

Expand Down
15 changes: 15 additions & 0 deletions src/test/auxiliary/issue-14344-1.rs
@@ -0,0 +1,15 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// no-prefer-dynamic

#![crate_type = "rlib"]

pub fn foo() {}
13 changes: 13 additions & 0 deletions src/test/auxiliary/issue-14344-2.rs
@@ -0,0 +1,13 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate issue_14344_1;

pub fn bar() {}
18 changes: 18 additions & 0 deletions src/test/auxiliary/issue-25185-1.rs
@@ -0,0 +1,18 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// no-prefer-dynamic

#![crate_type = "rlib"]

#[link(name = "rust_test_helpers", kind = "static")]
extern {
pub fn rust_dbg_extern_identity_u32(u: u32) -> u32;
}
13 changes: 13 additions & 0 deletions src/test/auxiliary/issue-25185-2.rs
@@ -0,0 +1,13 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate issue_25185_1;

pub use issue_25185_1::rust_dbg_extern_identity_u32;
4 changes: 2 additions & 2 deletions src/test/run-make/extern-fn-reachable/Makefile
Expand Up @@ -4,6 +4,6 @@
TARGET_RPATH_DIR:=$(TARGET_RPATH_DIR):$(TMPDIR)

all:
$(RUSTC) dylib.rs -o $(TMPDIR)/libdylib.so
$(RUSTC) main.rs
$(RUSTC) dylib.rs -o $(TMPDIR)/libdylib.so -C prefer-dynamic
$(RUSTC) main.rs -C prefer-dynamic
$(call RUN,main)
Expand Up @@ -2,5 +2,5 @@

all:
$(RUSTC) -C extra-filename=bar foo.rs -C save-temps
rm $(TMPDIR)/foobar.o
rm $(TMPDIR)/foobar.0.o
rm $(TMPDIR)/$(call BIN,foobar)

0 comments on commit 9f26f14

Please sign in to comment.