rustc: Embed LLVM bitcode by default on iOS

This commit updates rustc to embed bitcode in each object file generated by
default when compiling for iOS. This was determined in #35968 as a step
towards better compatibility with the iOS toolchain, so let's give it a spin and
see how it turns out!

Note that this also updates the `cc` dependency which should propagate this
change of embedding bitcode for C dependencies as well.
This commit is contained in:
Alex Crichton 2018-03-09 07:25:54 -08:00
parent 1999a3fb41
commit 0e0f74bcf9
4 changed files with 87 additions and 2 deletions

View file

@ -1288,6 +1288,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"run `dsymutil` and delete intermediate object files"),
ui_testing: bool = (false, parse_bool, [UNTRACKED],
"format compiler diagnostics in a way that's better suitable for UI testing"),
embed_bitcode: bool = (false, parse_bool, [TRACKED],
"embed LLVM bitcode in object files"),
}
pub fn default_lib_output() -> CrateType {

View file

@ -473,6 +473,9 @@ pub struct TargetOptions {
/// The default visibility for symbols in this target should be "hidden"
/// rather than "default"
pub default_hidden_visibility: bool,
/// Whether or not bitcode is embedded in object files
pub embed_bitcode: bool,
}
impl Default for TargetOptions {
@ -544,6 +547,7 @@ impl Default for TargetOptions {
i128_lowering: false,
codegen_backend: "llvm".to_string(),
default_hidden_visibility: false,
embed_bitcode: false,
}
}
}
@ -792,6 +796,7 @@ impl Target {
key!(no_builtins, bool);
key!(codegen_backend);
key!(default_hidden_visibility, bool);
key!(embed_bitcode, bool);
if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
for name in array.iter().filter_map(|abi| abi.as_string()) {
@ -990,6 +995,7 @@ impl ToJson for Target {
target_option_val!(no_builtins);
target_option_val!(codegen_backend);
target_option_val!(default_hidden_visibility);
target_option_val!(embed_bitcode);
if default.abi_blacklist != self.options.abi_blacklist {
d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()

View file

@ -42,6 +42,7 @@ use syntax_pos::MultiSpan;
use syntax_pos::symbol::Symbol;
use type_::Type;
use context::{is_pie_binary, get_reloc_model};
use common::{C_bytes_in_context, val_ty};
use jobserver::{Client, Acquired};
use rustc_demangle;
@ -262,6 +263,8 @@ pub struct ModuleConfig {
// emscripten's ecc compiler, when used as the linker.
obj_is_bitcode: bool,
no_integrated_as: bool,
embed_bitcode: bool,
embed_bitcode_marker: bool,
}
impl ModuleConfig {
@ -279,6 +282,8 @@ impl ModuleConfig {
emit_asm: false,
emit_obj: false,
obj_is_bitcode: false,
embed_bitcode: false,
embed_bitcode_marker: false,
no_integrated_as: false,
no_verify: false,
@ -299,6 +304,17 @@ impl ModuleConfig {
self.time_passes = sess.time_passes();
self.inline_threshold = sess.opts.cg.inline_threshold;
self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode;
let embed_bitcode = sess.target.target.options.embed_bitcode ||
sess.opts.debugging_opts.embed_bitcode;
if embed_bitcode {
match sess.opts.optimize {
config::OptLevel::No |
config::OptLevel::Less => {
self.embed_bitcode_marker = embed_bitcode;
}
_ => self.embed_bitcode = embed_bitcode,
}
}
// Copy what clang does by turning on loop vectorization at O2 and
// slp vectorization at O3. Otherwise configure other optimization aspects
@ -662,7 +678,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
if write_bc || config.emit_bc_compressed {
if write_bc || config.emit_bc_compressed || config.embed_bitcode {
let thin;
let old;
let data = if llvm::LLVMRustThinLTOAvailable() {
@ -681,6 +697,11 @@ unsafe fn codegen(cgcx: &CodegenContext,
timeline.record("write-bc");
}
if config.embed_bitcode {
embed_bitcode(cgcx, llcx, llmod, Some(data));
timeline.record("embed-bc");
}
if config.emit_bc_compressed {
let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
let data = bytecode::encode(&mtrans.llmod_id, data);
@ -689,6 +710,8 @@ unsafe fn codegen(cgcx: &CodegenContext,
}
timeline.record("compress-bc");
}
} else if config.embed_bitcode_marker {
embed_bitcode(cgcx, llcx, llmod, None);
}
time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()),
@ -796,6 +819,59 @@ unsafe fn codegen(cgcx: &CodegenContext,
&cgcx.output_filenames))
}
/// Embed the bitcode of an LLVM module in the LLVM module itself.
///
/// This is done primarily for iOS where it appears to be standard to compile C
/// code at least with `-fembed-bitcode` which creates two sections in the
/// executable:
///
/// * __LLVM,__bitcode
/// * __LLVM,__cmdline
///
/// It appears *both* of these sections are necessary to get the linker to
/// recognize what's going on. For us though we just always throw in an empty
/// cmdline section.
///
/// Furthermore debug/O1 builds don't actually embed bitcode but rather just
/// embed an empty section.
///
/// Basically all of this is us attempting to follow in the footsteps of clang
/// on iOS. See #35968 for lots more info.
unsafe fn embed_bitcode(cgcx: &CodegenContext,
llcx: ContextRef,
llmod: ModuleRef,
bitcode: Option<&[u8]>) {
let llconst = C_bytes_in_context(llcx, bitcode.unwrap_or(&[]));
let llglobal = llvm::LLVMAddGlobal(
llmod,
val_ty(llconst).to_ref(),
"rustc.embedded.module\0".as_ptr() as *const _,
);
llvm::LLVMSetInitializer(llglobal, llconst);
let section = if cgcx.opts.target_triple.contains("-ios") {
"__LLVM,__bitcode\0"
} else {
".llvmbc\0"
};
llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _);
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
let llconst = C_bytes_in_context(llcx, &[]);
let llglobal = llvm::LLVMAddGlobal(
llmod,
val_ty(llconst).to_ref(),
"rustc.embedded.cmdline\0".as_ptr() as *const _,
);
llvm::LLVMSetInitializer(llglobal, llconst);
let section = if cgcx.opts.target_triple.contains("-ios") {
"__LLVM,__cmdline\0"
} else {
".llvmcmd\0"
};
llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _);
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
}
pub(crate) struct CompiledModules {
pub modules: Vec<CompiledModule>,
pub metadata_module: CompiledModule,

View file

@ -86,6 +86,7 @@ fn main() {
fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> {
let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?;
let cflags = env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden -O2";
run(Command::new("sh")
.current_dir(&native.out_dir)
@ -98,7 +99,7 @@ fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> {
.arg("--disable-host-shared")
.arg(format!("--host={}", build_helper::gnu_target(target)))
.arg(format!("--build={}", build_helper::gnu_target(host)))
.env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden -O2"));
.env("CFLAGS", cflags));
run(Command::new(build_helper::make(host))
.current_dir(&native.out_dir)