ab.add_file(&metadata).unwrap();
remove(sess, &metadata);
- if sess.opts.cg.codegen_units == 1 {
- // For LTO purposes, the bytecode of this library is also
- // inserted into the archive. We currently do this only when
- // codegen_units == 1, so we don't have to deal with multiple
- // bitcode files per crate.
- //
+ // For LTO purposes, the bytecode of this library is also inserted
+ // into the archive. If codegen_units > 1, we insert each of the
+ // bitcode files.
+ for i in range(0, sess.opts.cg.codegen_units) {
// Note that we make sure that the bytecode filename in the
// archive is never exactly 16 bytes long by adding a 16 byte
// extension to it. This is to work around a bug in LLDB that
// would cause it to crash if the name of a file in an archive
// was exactly 16 bytes.
- let bc_filename = obj_filename.with_extension("bc");
- let bc_deflated_filename = obj_filename.with_extension("bytecode.deflate");
+ let bc_filename = obj_filename.with_extension(format!("{}.bc", i).as_slice());
+ let bc_deflated_filename = obj_filename.with_extension(
+ format!("{}.bytecode.deflate", i).as_slice());
let bc_data = match fs::File::open(&bc_filename).read_to_end() {
Ok(buffer) => buffer,
ab.add_file(&bc_deflated_filename).unwrap();
remove(sess, &bc_deflated_filename);
- if !sess.opts.cg.save_temps &&
- !sess.opts.output_types.contains(&OutputTypeBitcode) {
+
+ // See the bottom of back::write::run_passes for an explanation
+ // of when we do and don't keep .0.bc files around.
+ let user_wants_numbered_bitcode =
+ sess.opts.output_types.contains(&OutputTypeBitcode) &&
+ sess.opts.cg.codegen_units > 1;
+ if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode {
remove(sess, &bc_filename);
}
}
use libc;
use flate;
+use std::iter;
use std::mem;
pub fn run(sess: &session::Session, llmod: ModuleRef,
let file = path.filename_str().unwrap();
let file = file.slice(3, file.len() - 5); // chop off lib/.rlib
debug!("reading {}", file);
- let bc_encoded = time(sess.time_passes(),
- format!("read {}.bytecode.deflate", name).as_slice(),
- (),
- |_| {
- archive.read(format!("{}.bytecode.deflate",
- file).as_slice())
- });
- let bc_encoded = match bc_encoded {
- Some(data) => data,
- None => {
- sess.fatal(format!("missing compressed bytecode in {} \
- (perhaps it was compiled with -C codegen-units > 1)",
- path.display()).as_slice());
- },
- };
- let bc_extractor = if is_versioned_bytecode_format(bc_encoded) {
- |_| {
- // Read the version
- let version = extract_bytecode_format_version(bc_encoded);
-
- if version == 1 {
- // The only version existing so far
- let data_size = extract_compressed_bytecode_size_v1(bc_encoded);
- let compressed_data = bc_encoded.slice(
- link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET,
- link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET + data_size as uint);
-
- match flate::inflate_bytes(compressed_data) {
- Some(inflated) => inflated,
+ for i in iter::count(0u, 1) {
+ let bc_encoded = time(sess.time_passes(),
+ format!("check for {}.{}.bytecode.deflate", name, i).as_slice(),
+ (),
+ |_| {
+ archive.read(format!("{}.{}.bytecode.deflate",
+ file, i).as_slice())
+ });
+ 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()).as_slice());
+ }
+ // No more bitcode files to read.
+ break;
+ },
+ };
+ let bc_extractor = if is_versioned_bytecode_format(bc_encoded) {
+ |_| {
+ // Read the version
+ let version = extract_bytecode_format_version(bc_encoded);
+
+ if version == 1 {
+ // The only version existing so far
+ let data_size = extract_compressed_bytecode_size_v1(bc_encoded);
+ let compressed_data = bc_encoded.slice(
+ link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET,
+ link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET + data_size as uint);
+
+ match flate::inflate_bytes(compressed_data) {
+ Some(inflated) => inflated,
+ None => {
+ sess.fatal(format!("failed to decompress bc of `{}`",
+ name).as_slice())
+ }
+ }
+ } else {
+ sess.fatal(format!("Unsupported bytecode format version {}",
+ version).as_slice())
+ }
+ }
+ } else {
+ // 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) {
+ Some(bc) => bc,
None => {
sess.fatal(format!("failed to decompress bc of `{}`",
name).as_slice())
}
}
- } else {
- sess.fatal(format!("Unsupported bytecode format version {}",
- version).as_slice())
}
- }
- } else {
- // 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) {
- Some(bc) => bc,
- None => {
- sess.fatal(format!("failed to decompress bc of `{}`",
- name).as_slice())
- }
+ };
+
+ let bc_decoded = time(sess.time_passes(),
+ format!("decode {}.{}.bc", file, i).as_slice(),
+ (),
+ bc_extractor);
+
+ let ptr = bc_decoded.as_slice().as_ptr();
+ debug!("linking {}, part {}", name, i);
+ time(sess.time_passes(),
+ format!("ll link {}.{}", name, i).as_slice(),
+ (),
+ |()| unsafe {
+ if !llvm::LLVMRustLinkInExternalBitcode(llmod,
+ ptr as *const libc::c_char,
+ bc_decoded.len() as libc::size_t) {
+ write::llvm_err(sess.diagnostic().handler(),
+ format!("failed to load bc of `{}`",
+ name.as_slice()));
}
- }
- };
-
- let bc_decoded = time(sess.time_passes(),
- format!("decode {}.bc", file).as_slice(),
- (),
- bc_extractor);
-
- let ptr = bc_decoded.as_slice().as_ptr();
- debug!("linking {}", name);
- time(sess.time_passes(),
- format!("ll link {}", name).as_slice(),
- (),
- |()| unsafe {
- if !llvm::LLVMRustLinkInExternalBitcode(llmod,
- ptr as *const libc::c_char,
- bc_decoded.len() as libc::size_t) {
- write::llvm_err(sess.diagnostic().handler(),
- format!("failed to load bc of `{}`",
- name.as_slice()));
- }
- });
+ });
+ }
}
// Internalize everything but the reachable symbols of the current module
metadata_config.emit_bc = true;
}
- // Emit a bitcode file for the crate if we're emitting an rlib.
+ // Emit bitcode files for the crate if we're emitting an rlib.
// Whenever an rlib is created, the bitcode is inserted into the
// archive in order to allow LTO against it.
let needs_crate_bitcode =
sess.crate_types.borrow().contains(&config::CrateTypeRlib) &&
- sess.opts.output_types.contains(&OutputTypeExe) &&
- sess.opts.cg.codegen_units == 1;
+ sess.opts.output_types.contains(&OutputTypeExe);
if needs_crate_bitcode {
modules_config.emit_bc = true;
}
// Process the work items, optionally using worker threads.
if sess.opts.cg.codegen_units == 1 {
run_work_singlethreaded(sess, trans.reachable.as_slice(), work_items);
-
- if needs_crate_bitcode {
- // The only bitcode file produced (aside from metadata) was
- // "crate.0.bc". Rename to "crate.bc" since that's what
- // `link_rlib` expects to find.
- fs::copy(&crate_output.with_extension("0.bc"),
- &crate_output.temp_path(OutputTypeBitcode)).unwrap();
- }
} else {
run_work_multithreaded(sess, work_items, sess.opts.cg.codegen_units);
-
- assert!(!needs_crate_bitcode,
- "can't produce a crate bitcode file from multiple compilation units");
}
// All codegen is finished.
// Produce final compile outputs.
- let copy_if_one_unit = |ext: &str, output_type: OutputType| {
+ let copy_if_one_unit = |ext: &str, output_type: OutputType, keep_numbered: bool| {
// Three cases:
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`.
fs::copy(&crate_output.with_extension(ext),
&crate_output.path(output_type)).unwrap();
- if !sess.opts.cg.save_temps {
+ 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));
}
// 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.
- // FIXME: Since we don't support LTO anyway, maybe we can avoid
- // producing the temporary .0.bc's in the first place?
- let mut save_bitcode = false;
+ let mut user_wants_bitcode = false;
for output_type in output_types.iter() {
match *output_type {
OutputTypeBitcode => {
- save_bitcode = true;
- copy_if_one_unit("0.bc", OutputTypeBitcode);
+ user_wants_bitcode = true;
+ // Copy to .bc, but always keep the .0.bc. There is a later
+ // check to figure out if we should delete .0.bc files, or keep
+ // them for making an rlib.
+ copy_if_one_unit("0.bc", OutputTypeBitcode, true);
},
- OutputTypeLlvmAssembly => { copy_if_one_unit("0.ll", OutputTypeLlvmAssembly); },
- OutputTypeAssembly => { copy_if_one_unit("0.s", OutputTypeAssembly); },
+ OutputTypeLlvmAssembly => { copy_if_one_unit("0.ll", OutputTypeLlvmAssembly, false); },
+ OutputTypeAssembly => { copy_if_one_unit("0.s", OutputTypeAssembly, false); },
OutputTypeObject => { link_obj(&crate_output.path(OutputTypeObject)); },
OutputTypeExe => {
// If OutputTypeObject is already in the list, then
},
}
}
- let save_bitcode = save_bitcode;
+ let user_wants_bitcode = user_wants_bitcode;
// Clean up unwanted temporary files.
if !sess.opts.cg.save_temps {
// Remove the temporary .0.o objects. If the user didn't
- // explicitly request bitcode (with --emit=bc), we must remove
- // .0.bc as well. (We don't touch the crate.bc that may have been
- // produced earlier.)
+ // explicitly request bitcode (with --emit=bc), and the bitcode is not
+ // needed for building an rlib, then we must remove .0.bc as well.
+
+ // Specific rules for keeping .0.bc:
+ // - If we're building an rlib (`needs_crate_bitcode`), then keep
+ // it.
+ // - If the user requested bitcode (`user_wants_bitcode`), and
+ // codegen_units > 1, then keep it.
+ // - If the user requested bitcode but codegen_units == 1, then we
+ // can toss .0.bc because we copied it to .bc earlier.
+ // - If we're not building an rlib and the user didn't request
+ // bitcode, then delete .0.bc.
+ // If you change how this works, also update back::link::link_rlib,
+ // where .0.bc files are (maybe) deleted after making an rlib.
+ let keep_numbered_bitcode = needs_crate_bitcode ||
+ (user_wants_bitcode && sess.opts.cg.codegen_units > 1);
+
for i in range(0, trans.modules.len()) {
if modules_config.emit_obj {
let ext = format!("{}.o", i);
remove(sess, &crate_output.with_extension(ext.as_slice()));
}
- if modules_config.emit_bc && !save_bitcode {
+ if modules_config.emit_bc && !keep_numbered_bitcode {
let ext = format!("{}.bc", i);
remove(sess, &crate_output.with_extension(ext.as_slice()));
}
}
- if metadata_config.emit_bc && !save_bitcode {
+ if metadata_config.emit_bc && !user_wants_bitcode {
remove(sess, &crate_output.with_extension("metadata.bc"));
}
}
+++ /dev/null
-// Copyright 2012 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.
-
-// Make sure we give a sane error message when the user requests LTO with a
-// library built with -C codegen-units > 1.
-
-// aux-build:sepcomp_lib.rs
-// compile-flags: -Z lto
-// error-pattern:missing compressed bytecode
-// no-prefer-dynamic
-
-extern crate sepcomp_lib;
-use sepcomp_lib::a::one;
-use sepcomp_lib::b::two;
-use sepcomp_lib::c::three;
-
-fn main() {
- assert_eq!(one(), 1);
- assert_eq!(two(), 2);
- assert_eq!(three(), 3);
-}
--- /dev/null
+// Copyright 2012 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.
+
+// Check that we can use `-Z lto` when linking against libraries that were
+// separately compiled.
+
+// aux-build:sepcomp_lib.rs
+// compile-flags: -Z lto
+// no-prefer-dynamic
+
+extern crate sepcomp_lib;
+use sepcomp_lib::a::one;
+use sepcomp_lib::b::two;
+use sepcomp_lib::c::three;
+
+fn main() {
+ assert_eq!(one(), 1);
+ assert_eq!(two(), 2);
+ assert_eq!(three(), 3);
+}