Rollup merge of #71970 - thombles:ios-bitcode-improvements, r=alexcrichton
Improve bitcode generation for Apple platforms Some improvements for iOS bitcode support suggested by Alex over at https://github.com/getditto/rust-bitcode/issues/9. r? @alexcrichton This improves Rust's bitcode generation so that provided you have a compatible LLVM version, Rust targeting iOS should work out of the box when compiled into bitcode-enabled apps, and when submitted to the App Store. I've tested these changes using Xcode 11.4.1 and Apple's vendored LLVM, [tag `swift-5.2.3-RELEASE`](https://github.com/apple/llvm-project/releases/tag/swift-5.2.3-RELEASE). 1. Force `aarch64-apple-ios` and `aarch64-apple-tvos` targets to always emit full bitcode sections, even when cargo is trying to optimise by invoking `rustc` with `-Cembed-bitcode=no`. Since Apple recommends bitcode on iOS and requires it on tvOS it is likely that this is what developers intend. Currently you need to override the codegen options with `RUSTFLAGS`, which is far from obvious. 2. Provide an LLVM cmdline in the target spec. Apple's bitcode verification process looks for some arguments. For Rust modules to be accepted we must pretend they were produced similarly. A suitable default is provided in `TargetOptions` for iOS, copied directly from the a clang equivalent section. In the context of Apple platforms, the predominant purpose of bitcode is App Store submissions, so simulator and 32-bit targets are not relevant. I'm hoping that the cmdline strings will not be a maintenance burden to keep up-to-date. If the event of any future incompatibilities, hopefully a custom target config would offer enough flexibility to work around it. It's impossible to say for sure. Due to unrelated build errors I haven't been able to build and test a full tvOS toolchain. I've stopped short of providing a similar `bitcode_llvm_cmdline` until I can actually test it.
This commit is contained in:
commit
e3a4ff0d76
@ -651,10 +651,8 @@ pub(crate) unsafe fn codegen(
|
||||
"LLVM_module_codegen_embed_bitcode",
|
||||
&module.name[..],
|
||||
);
|
||||
embed_bitcode(cgcx, llcx, llmod, Some(data));
|
||||
embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
|
||||
}
|
||||
} else if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Marker) {
|
||||
embed_bitcode(cgcx, llcx, llmod, None);
|
||||
}
|
||||
|
||||
if config.emit_ir {
|
||||
@ -777,8 +775,8 @@ pub(crate) unsafe fn codegen(
|
||||
/// * __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.
|
||||
/// recognize what's going on. A suitable cmdline value is taken from the
|
||||
/// target spec.
|
||||
///
|
||||
/// Furthermore debug/O1 builds don't actually embed bitcode but rather just
|
||||
/// embed an empty section.
|
||||
@ -789,9 +787,10 @@ unsafe fn embed_bitcode(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
llcx: &llvm::Context,
|
||||
llmod: &llvm::Module,
|
||||
bitcode: Option<&[u8]>,
|
||||
cmdline: &str,
|
||||
bitcode: &[u8],
|
||||
) {
|
||||
let llconst = common::bytes_in_context(llcx, bitcode.unwrap_or(&[]));
|
||||
let llconst = common::bytes_in_context(llcx, bitcode);
|
||||
let llglobal = llvm::LLVMAddGlobal(
|
||||
llmod,
|
||||
common::val_ty(llconst),
|
||||
@ -800,14 +799,15 @@ unsafe fn embed_bitcode(
|
||||
llvm::LLVMSetInitializer(llglobal, llconst);
|
||||
|
||||
let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
|
||||
|| cgcx.opts.target_triple.triple().contains("-darwin");
|
||||
|| cgcx.opts.target_triple.triple().contains("-darwin")
|
||||
|| cgcx.opts.target_triple.triple().contains("-tvos");
|
||||
|
||||
let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" };
|
||||
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
|
||||
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
|
||||
|
||||
let llconst = common::bytes_in_context(llcx, &[]);
|
||||
let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
|
||||
let llglobal = llvm::LLVMAddGlobal(
|
||||
llmod,
|
||||
common::val_ty(llconst),
|
||||
|
@ -68,10 +68,6 @@ pub enum BitcodeSection {
|
||||
// No bitcode section.
|
||||
None,
|
||||
|
||||
// An empty bitcode section (to placate tools such as the iOS linker that
|
||||
// require this section even if they don't use it).
|
||||
Marker,
|
||||
|
||||
// A full, uncompressed bitcode section.
|
||||
Full,
|
||||
}
|
||||
@ -101,6 +97,7 @@ pub struct ModuleConfig {
|
||||
pub emit_ir: bool,
|
||||
pub emit_asm: bool,
|
||||
pub emit_obj: EmitObj,
|
||||
pub bc_cmdline: String,
|
||||
|
||||
// Miscellaneous flags. These are mostly copied from command-line
|
||||
// options.
|
||||
@ -147,14 +144,8 @@ impl ModuleConfig {
|
||||
|| sess.opts.cg.linker_plugin_lto.enabled()
|
||||
{
|
||||
EmitObj::Bitcode
|
||||
} else if need_crate_bitcode_for_rlib(sess) {
|
||||
let force_full = need_crate_bitcode_for_rlib(sess);
|
||||
match sess.opts.optimize {
|
||||
config::OptLevel::No | config::OptLevel::Less if !force_full => {
|
||||
EmitObj::ObjectCode(BitcodeSection::Marker)
|
||||
}
|
||||
_ => EmitObj::ObjectCode(BitcodeSection::Full),
|
||||
}
|
||||
} else if need_bitcode_in_object(sess) {
|
||||
EmitObj::ObjectCode(BitcodeSection::Full)
|
||||
} else {
|
||||
EmitObj::ObjectCode(BitcodeSection::None)
|
||||
};
|
||||
@ -211,6 +202,7 @@ impl ModuleConfig {
|
||||
false
|
||||
),
|
||||
emit_obj,
|
||||
bc_cmdline: sess.target.target.options.bitcode_llvm_cmdline.clone(),
|
||||
|
||||
verify_llvm_ir: sess.verify_llvm_ir(),
|
||||
no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes,
|
||||
@ -372,10 +364,12 @@ pub struct CompiledModules {
|
||||
pub allocator_module: Option<CompiledModule>,
|
||||
}
|
||||
|
||||
fn need_crate_bitcode_for_rlib(sess: &Session) -> bool {
|
||||
sess.opts.cg.embed_bitcode
|
||||
fn need_bitcode_in_object(sess: &Session) -> bool {
|
||||
let requested_for_rlib = sess.opts.cg.embed_bitcode
|
||||
&& sess.crate_types.borrow().contains(&CrateType::Rlib)
|
||||
&& sess.opts.output_types.contains_key(&OutputType::Exe)
|
||||
&& sess.opts.output_types.contains_key(&OutputType::Exe);
|
||||
let forced_by_target = sess.target.target.options.forces_embed_bitcode;
|
||||
requested_for_rlib || forced_by_target
|
||||
}
|
||||
|
||||
fn need_pre_lto_bitcode_for_incr_comp(sess: &Session) -> bool {
|
||||
|
@ -19,6 +19,18 @@ pub fn target() -> TargetResult {
|
||||
eliminate_frame_pointer: false,
|
||||
max_atomic_width: Some(128),
|
||||
abi_blacklist: super::arm_base::abi_blacklist(),
|
||||
forces_embed_bitcode: true,
|
||||
// Taken from a clang build on Xcode 11.4.1.
|
||||
// These arguments are not actually invoked - they just have
|
||||
// to look right to pass App Store validation.
|
||||
bitcode_llvm_cmdline: "-triple\0\
|
||||
arm64-apple-ios11.0.0\0\
|
||||
-emit-obj\0\
|
||||
-disable-llvm-passes\0\
|
||||
-target-abi\0\
|
||||
darwinpcs\0\
|
||||
-Os\0"
|
||||
.to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
|
@ -19,6 +19,7 @@ pub fn target() -> TargetResult {
|
||||
eliminate_frame_pointer: false,
|
||||
max_atomic_width: Some(128),
|
||||
abi_blacklist: super::arm_base::abi_blacklist(),
|
||||
forces_embed_bitcode: true,
|
||||
..base
|
||||
},
|
||||
})
|
||||
|
@ -783,6 +783,10 @@ pub struct TargetOptions {
|
||||
// If we give emcc .o files that are actually .bc files it
|
||||
// will 'just work'.
|
||||
pub obj_is_bitcode: bool,
|
||||
/// Whether the target requires that emitted object code includes bitcode.
|
||||
pub forces_embed_bitcode: bool,
|
||||
/// Content of the LLVM cmdline section associated with embedded bitcode.
|
||||
pub bitcode_llvm_cmdline: String,
|
||||
|
||||
/// Don't use this field; instead use the `.min_atomic_width()` method.
|
||||
pub min_atomic_width: Option<u64>,
|
||||
@ -939,6 +943,8 @@ impl Default for TargetOptions {
|
||||
allow_asm: true,
|
||||
has_elf_tls: false,
|
||||
obj_is_bitcode: false,
|
||||
forces_embed_bitcode: false,
|
||||
bitcode_llvm_cmdline: String::new(),
|
||||
min_atomic_width: None,
|
||||
max_atomic_width: None,
|
||||
atomic_cas: true,
|
||||
@ -1278,6 +1284,8 @@ impl Target {
|
||||
key!(main_needs_argc_argv, bool);
|
||||
key!(has_elf_tls, bool);
|
||||
key!(obj_is_bitcode, bool);
|
||||
key!(forces_embed_bitcode, bool);
|
||||
key!(bitcode_llvm_cmdline);
|
||||
key!(max_atomic_width, Option<u64>);
|
||||
key!(min_atomic_width, Option<u64>);
|
||||
key!(atomic_cas, bool);
|
||||
@ -1505,6 +1513,8 @@ impl ToJson for Target {
|
||||
target_option_val!(main_needs_argc_argv);
|
||||
target_option_val!(has_elf_tls);
|
||||
target_option_val!(obj_is_bitcode);
|
||||
target_option_val!(forces_embed_bitcode);
|
||||
target_option_val!(bitcode_llvm_cmdline);
|
||||
target_option_val!(min_atomic_width);
|
||||
target_option_val!(max_atomic_width);
|
||||
target_option_val!(atomic_cas);
|
||||
|
Loading…
x
Reference in New Issue
Block a user