Skip to content

Commit e3a4ff0

Browse files
authored
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.
2 parents a9eb01a + 4fea9cd commit e3a4ff0

File tree

5 files changed

+41
-24
lines changed

5 files changed

+41
-24
lines changed

src/librustc_codegen_llvm/back/write.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -651,10 +651,8 @@ pub(crate) unsafe fn codegen(
651651
"LLVM_module_codegen_embed_bitcode",
652652
&module.name[..],
653653
);
654-
embed_bitcode(cgcx, llcx, llmod, Some(data));
654+
embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
655655
}
656-
} else if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Marker) {
657-
embed_bitcode(cgcx, llcx, llmod, None);
658656
}
659657

660658
if config.emit_ir {
@@ -777,8 +775,8 @@ pub(crate) unsafe fn codegen(
777775
/// * __LLVM,__cmdline
778776
///
779777
/// It appears *both* of these sections are necessary to get the linker to
780-
/// recognize what's going on. For us though we just always throw in an empty
781-
/// cmdline section.
778+
/// recognize what's going on. A suitable cmdline value is taken from the
779+
/// target spec.
782780
///
783781
/// Furthermore debug/O1 builds don't actually embed bitcode but rather just
784782
/// embed an empty section.
@@ -789,9 +787,10 @@ unsafe fn embed_bitcode(
789787
cgcx: &CodegenContext<LlvmCodegenBackend>,
790788
llcx: &llvm::Context,
791789
llmod: &llvm::Module,
792-
bitcode: Option<&[u8]>,
790+
cmdline: &str,
791+
bitcode: &[u8],
793792
) {
794-
let llconst = common::bytes_in_context(llcx, bitcode.unwrap_or(&[]));
793+
let llconst = common::bytes_in_context(llcx, bitcode);
795794
let llglobal = llvm::LLVMAddGlobal(
796795
llmod,
797796
common::val_ty(llconst),
@@ -800,14 +799,15 @@ unsafe fn embed_bitcode(
800799
llvm::LLVMSetInitializer(llglobal, llconst);
801800

802801
let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
803-
|| cgcx.opts.target_triple.triple().contains("-darwin");
802+
|| cgcx.opts.target_triple.triple().contains("-darwin")
803+
|| cgcx.opts.target_triple.triple().contains("-tvos");
804804

805805
let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" };
806806
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
807807
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
808808
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
809809

810-
let llconst = common::bytes_in_context(llcx, &[]);
810+
let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
811811
let llglobal = llvm::LLVMAddGlobal(
812812
llmod,
813813
common::val_ty(llconst),

src/librustc_codegen_ssa/back/write.rs

+9-15
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,6 @@ pub enum BitcodeSection {
6868
// No bitcode section.
6969
None,
7070

71-
// An empty bitcode section (to placate tools such as the iOS linker that
72-
// require this section even if they don't use it).
73-
Marker,
74-
7571
// A full, uncompressed bitcode section.
7672
Full,
7773
}
@@ -101,6 +97,7 @@ pub struct ModuleConfig {
10197
pub emit_ir: bool,
10298
pub emit_asm: bool,
10399
pub emit_obj: EmitObj,
100+
pub bc_cmdline: String,
104101

105102
// Miscellaneous flags. These are mostly copied from command-line
106103
// options.
@@ -147,14 +144,8 @@ impl ModuleConfig {
147144
|| sess.opts.cg.linker_plugin_lto.enabled()
148145
{
149146
EmitObj::Bitcode
150-
} else if need_crate_bitcode_for_rlib(sess) {
151-
let force_full = need_crate_bitcode_for_rlib(sess);
152-
match sess.opts.optimize {
153-
config::OptLevel::No | config::OptLevel::Less if !force_full => {
154-
EmitObj::ObjectCode(BitcodeSection::Marker)
155-
}
156-
_ => EmitObj::ObjectCode(BitcodeSection::Full),
157-
}
147+
} else if need_bitcode_in_object(sess) {
148+
EmitObj::ObjectCode(BitcodeSection::Full)
158149
} else {
159150
EmitObj::ObjectCode(BitcodeSection::None)
160151
};
@@ -211,6 +202,7 @@ impl ModuleConfig {
211202
false
212203
),
213204
emit_obj,
205+
bc_cmdline: sess.target.target.options.bitcode_llvm_cmdline.clone(),
214206

215207
verify_llvm_ir: sess.verify_llvm_ir(),
216208
no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes,
@@ -372,10 +364,12 @@ pub struct CompiledModules {
372364
pub allocator_module: Option<CompiledModule>,
373365
}
374366

375-
fn need_crate_bitcode_for_rlib(sess: &Session) -> bool {
376-
sess.opts.cg.embed_bitcode
367+
fn need_bitcode_in_object(sess: &Session) -> bool {
368+
let requested_for_rlib = sess.opts.cg.embed_bitcode
377369
&& sess.crate_types.borrow().contains(&CrateType::Rlib)
378-
&& sess.opts.output_types.contains_key(&OutputType::Exe)
370+
&& sess.opts.output_types.contains_key(&OutputType::Exe);
371+
let forced_by_target = sess.target.target.options.forces_embed_bitcode;
372+
requested_for_rlib || forced_by_target
379373
}
380374

381375
fn need_pre_lto_bitcode_for_incr_comp(sess: &Session) -> bool {

src/librustc_target/spec/aarch64_apple_ios.rs

+12
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ pub fn target() -> TargetResult {
1919
eliminate_frame_pointer: false,
2020
max_atomic_width: Some(128),
2121
abi_blacklist: super::arm_base::abi_blacklist(),
22+
forces_embed_bitcode: true,
23+
// Taken from a clang build on Xcode 11.4.1.
24+
// These arguments are not actually invoked - they just have
25+
// to look right to pass App Store validation.
26+
bitcode_llvm_cmdline: "-triple\0\
27+
arm64-apple-ios11.0.0\0\
28+
-emit-obj\0\
29+
-disable-llvm-passes\0\
30+
-target-abi\0\
31+
darwinpcs\0\
32+
-Os\0"
33+
.to_string(),
2234
..base
2335
},
2436
})

src/librustc_target/spec/aarch64_apple_tvos.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub fn target() -> TargetResult {
1919
eliminate_frame_pointer: false,
2020
max_atomic_width: Some(128),
2121
abi_blacklist: super::arm_base::abi_blacklist(),
22+
forces_embed_bitcode: true,
2223
..base
2324
},
2425
})

src/librustc_target/spec/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,10 @@ pub struct TargetOptions {
783783
// If we give emcc .o files that are actually .bc files it
784784
// will 'just work'.
785785
pub obj_is_bitcode: bool,
786+
/// Whether the target requires that emitted object code includes bitcode.
787+
pub forces_embed_bitcode: bool,
788+
/// Content of the LLVM cmdline section associated with embedded bitcode.
789+
pub bitcode_llvm_cmdline: String,
786790

787791
/// Don't use this field; instead use the `.min_atomic_width()` method.
788792
pub min_atomic_width: Option<u64>,
@@ -939,6 +943,8 @@ impl Default for TargetOptions {
939943
allow_asm: true,
940944
has_elf_tls: false,
941945
obj_is_bitcode: false,
946+
forces_embed_bitcode: false,
947+
bitcode_llvm_cmdline: String::new(),
942948
min_atomic_width: None,
943949
max_atomic_width: None,
944950
atomic_cas: true,
@@ -1278,6 +1284,8 @@ impl Target {
12781284
key!(main_needs_argc_argv, bool);
12791285
key!(has_elf_tls, bool);
12801286
key!(obj_is_bitcode, bool);
1287+
key!(forces_embed_bitcode, bool);
1288+
key!(bitcode_llvm_cmdline);
12811289
key!(max_atomic_width, Option<u64>);
12821290
key!(min_atomic_width, Option<u64>);
12831291
key!(atomic_cas, bool);
@@ -1505,6 +1513,8 @@ impl ToJson for Target {
15051513
target_option_val!(main_needs_argc_argv);
15061514
target_option_val!(has_elf_tls);
15071515
target_option_val!(obj_is_bitcode);
1516+
target_option_val!(forces_embed_bitcode);
1517+
target_option_val!(bitcode_llvm_cmdline);
15081518
target_option_val!(min_atomic_width);
15091519
target_option_val!(max_atomic_width);
15101520
target_option_val!(atomic_cas);

0 commit comments

Comments
 (0)