Commit 9bc8e6d1 authored by Alex Crichton's avatar Alex Crichton

trans: Link rlibs to dylibs with --whole-archive

This commit starts passing the `--whole-archive` flag (`-force_load` on OSX) to
the linker when linking rlibs into dylibs. The primary purpose of this commit is
to ensure that the linker doesn't strip out objects from an archive when
creating a dynamic library. Information on how this can go wrong can be found in
issues #14344 and #25185.

The unfortunate part about passing this flag to the linker is that we have to
preprocess the rlib to remove the metadata and compressed bytecode found within.
This means that creating a dylib will now take longer to link as we've got to
copy around the input rlibs to a temporary location, modify them, and then
invoke the linker. This isn't done for executables, however, so the "hello
world" compile time is not affected.

This fix was instigated because of the previous commit where rlibs may not
contain multiple object files instead of one due to codegen units being greater
than one. That change prevented the main distribution from being compiled with
more than one codegen-unit and this commit fixes that.

Closes #14344
Closes #25185
parent d23239b4
......@@ -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() {}
......@@ -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))]
......
......@@ -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
......@@ -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);
......
......@@ -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);
}
}
......
......@@ -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());
}
......
This diff is collapsed.
......@@ -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);
......@@ -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
......@@ -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
}
......
......@@ -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);
......@@ -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) {
......@@ -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,
......
// 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() {}
// 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() {}
// 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;
}
// 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,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)
// 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.
// aux-build:issue-14344-1.rs
// aux-build:issue-14344-2.rs
extern crate issue_14344_1;
extern crate issue_14344_2;
fn main() {
issue_14344_1::foo();
issue_14344_2::bar();
}
// 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.
// aux-build:issue-25185-1.rs
// aux-build:issue-25185-2.rs
extern crate issue_25185_2;
fn main() {
let x = unsafe {
issue_25185_2::rust_dbg_extern_identity_u32(1)
};
assert_eq!(x, 1);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment