Skip to content

Commit 9f26f14

Browse files
committed
Auto merge of #26869 - alexcrichton:fix-msvc-sepcomp, r=nrc
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.
2 parents 020d201 + 9bc8e6d commit 9f26f14

File tree

18 files changed

+289
-252
lines changed

18 files changed

+289
-252
lines changed

src/liballoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,5 @@ pub fn oom() -> ! {
148148
// optimize it out).
149149
#[doc(hidden)]
150150
#[unstable(feature = "issue_14344_fixme")]
151+
#[cfg(stage0)]
151152
pub fn fixme_14344_be_sure_to_link_to_collections() {}

src/libcollections/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ pub mod btree_set {
138138
// FIXME(#14344) this shouldn't be necessary
139139
#[doc(hidden)]
140140
#[unstable(feature = "issue_14344_fixme")]
141+
#[cfg(stage0)]
141142
pub fn fixme_14344_be_sure_to_link_to_collections() {}
142143

143144
#[cfg(not(test))]

src/liblibc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -6431,6 +6431,7 @@ pub mod funcs {
64316431
}
64326432

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

64366437
#[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows

src/librustc/metadata/encoder.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -2136,11 +2136,7 @@ fn encode_metadata_inner(wr: &mut Cursor<Vec<u8>>,
21362136
let mut rbml_w = Encoder::new(wr);
21372137

21382138
encode_crate_name(&mut rbml_w, &ecx.link_meta.crate_name);
2139-
encode_crate_triple(&mut rbml_w,
2140-
&tcx.sess
2141-
.opts
2142-
.target_triple
2143-
);
2139+
encode_crate_triple(&mut rbml_w, &tcx.sess.opts.target_triple);
21442140
encode_hash(&mut rbml_w, &ecx.link_meta.crate_hash);
21452141
encode_dylib_dependency_formats(&mut rbml_w, &ecx);
21462142

src/librustc_driver/driver.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -804,8 +804,8 @@ fn write_out_deps(sess: &Session,
804804
match *output_type {
805805
config::OutputTypeExe => {
806806
for output in sess.crate_types.borrow().iter() {
807-
let p = link::filename_for_input(sess, *output,
808-
id, &file);
807+
let p = link::filename_for_input(sess, *output, id,
808+
outputs);
809809
out_filenames.push(p);
810810
}
811811
}

src/librustc_driver/lib.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -452,10 +452,8 @@ impl RustcDefaultCalls {
452452
let metadata = driver::collect_crate_metadata(sess, attrs);
453453
*sess.crate_metadata.borrow_mut() = metadata;
454454
for &style in &crate_types {
455-
let fname = link::filename_for_input(sess,
456-
style,
457-
&id,
458-
&t_outputs.with_extension(""));
455+
let fname = link::filename_for_input(sess, style, &id,
456+
&t_outputs);
459457
println!("{}", fname.file_name().unwrap()
460458
.to_string_lossy());
461459
}

src/librustc_trans/back/link.rs

+139-127
Large diffs are not rendered by default.

src/librustc_trans/back/linker.rs

+16
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub trait Linker {
3030
fn link_framework(&mut self, framework: &str);
3131
fn link_staticlib(&mut self, lib: &str);
3232
fn link_rlib(&mut self, lib: &Path);
33+
fn link_whole_rlib(&mut self, lib: &Path);
3334
fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]);
3435
fn include_path(&mut self, path: &Path);
3536
fn framework_path(&mut self, path: &Path);
@@ -96,6 +97,17 @@ impl<'a> Linker for GnuLinker<'a> {
9697
}
9798
}
9899

100+
fn link_whole_rlib(&mut self, lib: &Path) {
101+
if self.sess.target.target.options.is_like_osx {
102+
let mut v = OsString::from("-Wl,-force_load,");
103+
v.push(lib);
104+
self.cmd.arg(&v);
105+
} else {
106+
self.cmd.arg("-Wl,--whole-archive").arg(lib)
107+
.arg("-Wl,--no-whole-archive");
108+
}
109+
}
110+
99111
fn gc_sections(&mut self, is_dylib: bool) {
100112
// The dead_strip option to the linker specifies that functions and data
101113
// unreachable by the entry point will be removed. This is quite useful
@@ -250,6 +262,10 @@ impl<'a> Linker for MsvcLinker<'a> {
250262
// not supported?
251263
self.link_staticlib(lib);
252264
}
265+
fn link_whole_rlib(&mut self, path: &Path) {
266+
// not supported?
267+
self.link_rlib(path);
268+
}
253269
fn optimize(&mut self) {
254270
// Needs more investigation of `/OPT` arguments
255271
}

src/librustc_trans/back/lto.rs

+9-30
Original file line numberDiff line numberDiff line change
@@ -56,33 +56,14 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
5656
};
5757

5858
let archive = ArchiveRO::open(&path).expect("wanted an rlib");
59-
let file = path.file_name().unwrap().to_str().unwrap();
60-
let file = &file[3..file.len() - 5]; // chop off lib/.rlib
61-
debug!("reading {}", file);
62-
for i in 0.. {
63-
let filename = format!("{}.{}.bytecode.deflate", file, i);
64-
let msg = format!("check for {}", filename);
65-
let bc_encoded = time(sess.time_passes(), &msg, (), |_| {
66-
archive.iter().find(|section| {
67-
section.name() == Some(&filename[..])
68-
})
69-
});
70-
let bc_encoded = match bc_encoded {
71-
Some(data) => data,
72-
None => {
73-
if i == 0 {
74-
// No bitcode was found at all.
75-
sess.fatal(&format!("missing compressed bytecode in {}",
76-
path.display()));
77-
}
78-
// No more bitcode files to read.
79-
break
80-
}
81-
};
82-
let bc_encoded = bc_encoded.data();
59+
let bytecodes = archive.iter().filter_map(|child| {
60+
child.name().map(|name| (name, child))
61+
}).filter(|&(name, _)| name.ends_with("bytecode.deflate"));
62+
for (name, data) in bytecodes {
63+
let bc_encoded = data.data();
8364

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

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

122103
let ptr = bc_decoded.as_ptr();
123-
debug!("linking {}, part {}", name, i);
124-
time(sess.time_passes(),
125-
&format!("ll link {}.{}", name, i),
126-
(),
104+
debug!("linking {}", name);
105+
time(sess.time_passes(), &format!("ll link {}", name), (),
127106
|()| unsafe {
128107
if !llvm::LLVMRustLinkInExternalBitcode(llmod,
129108
ptr as *const libc::c_char,

src/librustc_trans/back/write.rs

+14-81
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use std::ffi::{CStr, CString};
2727
use std::fs;
2828
use std::mem;
2929
use std::path::Path;
30-
use std::process::Stdio;
3130
use std::ptr;
3231
use std::str;
3332
use std::sync::{Arc, Mutex};
@@ -619,6 +618,8 @@ pub fn run_passes(sess: &Session,
619618
let needs_crate_bitcode =
620619
sess.crate_types.borrow().contains(&config::CrateTypeRlib) &&
621620
sess.opts.output_types.contains(&config::OutputTypeExe);
621+
let needs_crate_object =
622+
sess.opts.output_types.contains(&config::OutputTypeExe);
622623
if needs_crate_bitcode {
623624
modules_config.emit_bc = true;
624625
}
@@ -696,7 +697,8 @@ pub fn run_passes(sess: &Session,
696697
if sess.opts.cg.codegen_units == 1 {
697698
// 1) Only one codegen unit. In this case it's no difficulty
698699
// to copy `foo.0.x` to `foo.x`.
699-
copy_gracefully(&crate_output.with_extension(ext), &crate_output.path(output_type));
700+
copy_gracefully(&crate_output.with_extension(ext),
701+
&crate_output.path(output_type));
700702
if !sess.opts.cg.save_temps && !keep_numbered {
701703
// The user just wants `foo.x`, not `foo.0.x`.
702704
remove(sess, &crate_output.with_extension(ext));
@@ -715,76 +717,11 @@ pub fn run_passes(sess: &Session,
715717
}
716718
};
717719

718-
let link_obj = |output_path: &Path| {
719-
// Running `ld -r` on a single input is kind of pointless.
720-
if sess.opts.cg.codegen_units == 1 {
721-
copy_gracefully(&crate_output.with_extension("0.o"), output_path);
722-
// Leave the .0.o file around, to mimic the behavior of the normal
723-
// code path.
724-
return;
725-
}
726-
727-
// Some builds of MinGW GCC will pass --force-exe-suffix to ld, which
728-
// will automatically add a .exe extension if the extension is not
729-
// already .exe or .dll. To ensure consistent behavior on Windows, we
730-
// add the .exe suffix explicitly and then rename the output file to
731-
// the desired path. This will give the correct behavior whether or
732-
// not GCC adds --force-exe-suffix.
733-
let windows_output_path =
734-
if sess.target.target.options.is_like_windows {
735-
Some(output_path.with_extension("o.exe"))
736-
} else {
737-
None
738-
};
739-
740-
let (pname, mut cmd) = get_linker(sess);
741-
742-
cmd.args(&sess.target.target.options.pre_link_args);
743-
cmd.arg("-nostdlib");
744-
745-
for index in 0..trans.modules.len() {
746-
cmd.arg(&crate_output.with_extension(&format!("{}.o", index)));
747-
}
748-
749-
cmd.arg("-r").arg("-o")
750-
.arg(windows_output_path.as_ref().map(|s| &**s).unwrap_or(output_path));
751-
752-
cmd.args(&sess.target.target.options.post_link_args);
753-
754-
if sess.opts.debugging_opts.print_link_args {
755-
println!("{:?}", &cmd);
756-
}
757-
758-
cmd.stdin(Stdio::null());
759-
match cmd.status() {
760-
Ok(status) => {
761-
if !status.success() {
762-
sess.err(&format!("linking of {} with `{:?}` failed",
763-
output_path.display(), cmd));
764-
sess.abort_if_errors();
765-
}
766-
},
767-
Err(e) => {
768-
sess.err(&format!("could not exec the linker `{}`: {}",
769-
pname, e));
770-
sess.abort_if_errors();
771-
},
772-
}
773-
774-
match windows_output_path {
775-
Some(ref windows_path) => {
776-
fs::rename(windows_path, output_path).unwrap();
777-
},
778-
None => {
779-
// The file is already named according to `output_path`.
780-
}
781-
}
782-
};
783-
784720
// Flag to indicate whether the user explicitly requested bitcode.
785721
// Otherwise, we produced it only as a temporary output, and will need
786722
// to get rid of it.
787723
let mut user_wants_bitcode = false;
724+
let mut user_wants_objects = false;
788725
for output_type in output_types {
789726
match *output_type {
790727
config::OutputTypeBitcode => {
@@ -801,17 +738,10 @@ pub fn run_passes(sess: &Session,
801738
copy_if_one_unit("0.s", config::OutputTypeAssembly, false);
802739
}
803740
config::OutputTypeObject => {
804-
link_obj(&crate_output.path(config::OutputTypeObject));
805-
}
806-
config::OutputTypeExe => {
807-
// If config::OutputTypeObject is already in the list, then
808-
// `crate.o` will be handled by the config::OutputTypeObject case.
809-
// Otherwise, we need to create the temporary object so we
810-
// can run the linker.
811-
if !sess.opts.output_types.contains(&config::OutputTypeObject) {
812-
link_obj(&crate_output.temp_path(config::OutputTypeObject));
813-
}
741+
user_wants_objects = true;
742+
copy_if_one_unit("0.o", config::OutputTypeObject, true);
814743
}
744+
config::OutputTypeExe |
815745
config::OutputTypeDepInfo => {}
816746
}
817747
}
@@ -848,15 +778,18 @@ pub fn run_passes(sess: &Session,
848778
let keep_numbered_bitcode = needs_crate_bitcode ||
849779
(user_wants_bitcode && sess.opts.cg.codegen_units > 1);
850780

781+
let keep_numbered_objects = needs_crate_object ||
782+
(user_wants_objects && sess.opts.cg.codegen_units > 1);
783+
851784
for i in 0..trans.modules.len() {
852-
if modules_config.emit_obj {
785+
if modules_config.emit_obj && !keep_numbered_objects {
853786
let ext = format!("{}.o", i);
854-
remove(sess, &crate_output.with_extension(&ext[..]));
787+
remove(sess, &crate_output.with_extension(&ext));
855788
}
856789

857790
if modules_config.emit_bc && !keep_numbered_bitcode {
858791
let ext = format!("{}.bc", i);
859-
remove(sess, &crate_output.with_extension(&ext[..]));
792+
remove(sess, &crate_output.with_extension(&ext));
860793
}
861794
}
862795

src/test/auxiliary/issue-14344-1.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2015 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+
11+
// no-prefer-dynamic
12+
13+
#![crate_type = "rlib"]
14+
15+
pub fn foo() {}

src/test/auxiliary/issue-14344-2.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2015 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+
11+
extern crate issue_14344_1;
12+
13+
pub fn bar() {}

src/test/auxiliary/issue-25185-1.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2015 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+
11+
// no-prefer-dynamic
12+
13+
#![crate_type = "rlib"]
14+
15+
#[link(name = "rust_test_helpers", kind = "static")]
16+
extern {
17+
pub fn rust_dbg_extern_identity_u32(u: u32) -> u32;
18+
}

src/test/auxiliary/issue-25185-2.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2015 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+
11+
extern crate issue_25185_1;
12+
13+
pub use issue_25185_1::rust_dbg_extern_identity_u32;

src/test/run-make/extern-fn-reachable/Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
TARGET_RPATH_DIR:=$(TARGET_RPATH_DIR):$(TMPDIR)
55

66
all:
7-
$(RUSTC) dylib.rs -o $(TMPDIR)/libdylib.so
8-
$(RUSTC) main.rs
7+
$(RUSTC) dylib.rs -o $(TMPDIR)/libdylib.so -C prefer-dynamic
8+
$(RUSTC) main.rs -C prefer-dynamic
99
$(call RUN,main)

src/test/run-make/extra-filename-with-temp-outputs/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22

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

0 commit comments

Comments
 (0)