-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support Apple app store bitcode #35968
Comments
Dynamically loading LLVM is certainly not an option. The LLVM API is less stable than its bitcode and, if we build against LLVM x.y, then having LLVM x.z instead of x.y will almost certainly break rustc. Just link to the system LLVM statically (like
Just link the system LLVM (statically) for apple distributions. In my experience it already works kinda well.
Okay… so, the thing is that LLVM bitcode format is kinda stable between versions of LLVM. Does apple do something unusual to make that not true, or is the bitcode format used not LLVM altogether (i.e. has apple specific stuff)? I feel like I heard all the way back in 2013-ish that using LLVM bitcode as distribution format is stupid. I certainly agree; does distributing native binary libraries not work anymore for iOS? |
I’m also very interested in what would happen when Apple upgrades to LLVM version with incompatible bitcode format internally and people still compile stuff with old compilers. |
I experimented briefly with this, i.e. output bitcode during cargo builds, then tried to create a static library with the bitcode included. When I tried to llvm-link against the bitcode library, I got an incompatible LLVM version from the bitcode. I don't have an easy test to reproduce this, but my guess is there is just a dumb version check that denies linking between different LLVM versions? Or, I just did something entirely wrong. I will try to come up with a test case when I have some time to look at this again. |
It would be useful to have exact error message from llvm-link. |
@bluejekyll LLVM has a number of bitcode files in its test directory. Tests against these bitcode files are run continuously (llvm-dis-3.8/opt-3.8 understands a 3 year old bitcode file from 3.2 just fine, for example), so it must be some apple stuff. |
This is somewhat easier said than done - as far as I'm aware, the only blessed apple-llvm version for App Store uploads is the one shipped with the current Xcode. This also potentially means maintaining the LLVM bindings for two LLVM versions (not necessarily two neighbouring minor versions, either). I don't think it's valid to just use an old version of apple-llvm.
I think they avoid this by only allowing the latest Xcode to submit apps (and I'm pretty sure it's burned into the output image which LLVM version you used). IIRC, the bitcode is packaged for each architecture, since cross-architecture bitcode isn't generated by clang (I think that's an anti-goal of clang and bitcode in general). It's stored in a section for each object file so at the very least it's duplicated. That could be part of why someone mentioned that bitcode might not be the best way of going about this. I feel a bit like all of the recommended solutions are somewhat icky. The least messy way I can think of is to allow different targets to overload the codegen behaviour and have the Apple codegen path be in a dynamic crate. (Which would just be the regular codegen path compiled against apple-llvm.) Since this bug mentions the App Store, is it worth talking about the exception handling story here? (i.e. |
@nagisa thanks for letting me know this. It gives me hope that there might still be a solution here, and that I was probably doing something wrong. |
@ricky26 good points.
Isn’t Xcode LLVM on apple the same thing as system LLVM? I meant the Xcode LLVM then. We would have to make sure xcode is always the most recent version when shipping rustc trains. Of course the way apple does things rules out us producing a valid apple bitcode with an old version of rustc and essentially forces us throw all the benefits our stability story provides out the window, and I don’t see any way this could be fixed.
We already maintain¹ support for LLVM versions 3.7 through 3.9 (and potentially trunk). As long as Xcode’s LLVM is not some ancient version, I think we’re good in that regard. If Xcode LLVM is really some ancient/custom/etc version, then I don’t see us being able to support this feature at all, then. Especially since we have no option of sending patches to that LLVM in order to add the features we need. I also wouldn’t want to lock rustc into supporting 3.7 forever in case Apple decided to not update Xcode LLVM until 2038. ¹: however, if rustc was built against LLVM x.y, it must be linked to LLVM x.y exactly. |
@nagisa The C++ API is unstable, but we use the C API and have had a lot of success supporting multiple versions of LLVM at once. I don't see the difference in terms of API support.
We could just blanket ship Apple's LLVM for all apple platforms, but this means coupling our LLVM to Apples for even desktop machine code generation, and precludes the option of supporting iOS bitcode on non-apple hosts.
The bitcode format is not stable between versions.
It does work today. It is not the preferred method and it's not obvious it will continue to be supported.
@ricky26 We successfully maintain compatibility between several versions of LLVM. As long as Apple's and ours don't drift too far apart it should be doable, but there's always the risk of such great breakage that the divide can't be crossed, and I know there are major API changes coming. |
From this page https://gist.github.com/yamaya/2924292:
|
That is not true. We have (quite large!) a number of bindings to C++ APIs in form of rustllvm. There’s a number of cases where we compile that wrapper depending on the version of LLVM compiled against. In case version of LLVM used and compiled against does not match, you’ll get dynamic linker errors, or worse, run into issues at runtime.
If Apple does not want to take bitcode generated by anything else than their fork of LLVM, then I don’t see how we could do anything here short of maintaining a similar fork and reverse-engineering their internal patches.
Sure, but it is quite fair to assume¹ that bitcode between various revisions of LLVM known as 3.7.0, for example, is sufficiently compatible for purposes of generating bitcode for consumption by another build of LLVM from 3.7.0 series. Its certainly better than linking to libLLVM dynamically. ¹: especially given that bitcode from 3.2 series is still compatible with 3.8 LLVM, even if its a very small specimen. |
Some notes:
|
cc @rust-lang/compiler |
Would be curious to hear how other programming languages plan on dealing with this. In particular mono and go. |
Unity's answer to this problem is il2cpp - building all of their IL assemblies into C++ code. Relevant golang bug: golang/go#12682; the suggestion there seems to be that they could use the LLVM go toolchain (which isn't as featured as the standard go toolchain). All in all, the story for bitcode support outside of Apple is poor. |
Mono proper goes via apple LLVM it would appear: http://tirania.org/blog/archive/2015/Sep-02.html |
One stumbling block will be that you cannot carry inline assembly in bitcode :( For the mono story I had a quick exchange with Miguel de Icaza about what Mono does for the curious: https://twitter.com/mitsuhiko/status/769458873237434368 |
@mitsuhiko You can have inline assembly in bitcode on iOS and tvOS, but not watchOS, for some reason. |
Any movement on this? I don't feel at all good about using Rust on iOS without a plan for supporting bitcode. Apple has a history of making optional things like this non-optional fairly suddenly, and indeed bitcode is already required on watchOS and tvOS.
This approach (by @ricky26) seems to be the most natural to me as a rustc user. |
I don't believe anything has changed on this recently to my knowledge at least. With LLVM's recent announcement about versioning they indicated that bitcode should (I think) always be loadable by future versions of LLVM. That may mean that this issue is "solved" on a fundamental level, but it'd still require a more ergonomic interface to extract all the bitcode. |
Are there any updates on this? |
This commenter on HackerNews has succeeded in using Bitcode generated from Rust on macOS and iOS. The thread has some detailed information on how to enable bitcode for rust binaries, which sounds like a great news! |
As the commenter in question, quick notes:
|
Does bitcode work now? Did anybody try? |
@volodg I'm a rust novice. However, I ran through this tutorial with the latest rust nightly (at time of writing It seems like the markers are there..
But I get the following error when building for iOS device (simulator works):
That's as far as I got. |
I succeeded to link |
Two years later I can answer this - for deploying to physical devices or creating Xcode archives an empty cmdline is fine, however for App Store submissions Apple performs validation of the clang command line. I’ve put a longer description in this PR, which includes a hacky patch to make it work: getditto/rust-bitcode#7 I’d like to upstream this somehow but the options are not appealing. Do we make up some clang options when targeting iOS? Do we provide an envvar to choose exactly how to lie in case Apple changes their validation rules? I’d be happy to make the change if there’s a reasonable choice here. |
-Cembed-bitcode=no does not work for ios target. there are still bitcode section in .a file |
Hi, after years, is there any updates? Thanks! In other words, is there anyone who successfully make an app with Rust to deploy to apple store? |
We have an app using rust In the stores. No Bitcode required unless you want to support Apple Watch so far |
@extrawurst Thank you very much! So if I understand correctly: I just need to disable bitcode, and everything would be fine? |
If you do want the bitcode for some reason or another, the scripts we maintain at $work continue to function for building iOS apps with bitcode and submitting to the app store, up to Xcode 13. More broadly though I'm not aware of any changes regarding Apple's forks of LLVMs and the difficulty of making this work with mainline Rust development. |
@thombles Thank you! |
I've encountered an issue that looks similar:
I'm pretty sure that bitcode is disabled, since it works if I use rust 1.55 (before upgrade to LLVM 12) and xcode project is configured to disable bitcode. |
Not anymore 😛 https://developer.apple.com/documentation/xcode-release-notes/xcode-14-release-notes
|
Does that mean we no longer need to use a specialized toolchain like https://github.com/getditto/rust-bitcode, and can instead safely disable bitcode in our XCode app? |
Yes. |
@thombles makes a good point here:
I'd also take "Xcode 15 is announced", on the assumption that if anything goes awry we'll hear about it by then, but if anyone wants to reap this issue before then, they're welcome to it. |
fwiw we currently ship macOS (non-store) & iOS (TestFlight & Store) with a Rust library driving most of our core functionality. We've never used bitcode since we didn't target any of the previously bitcode requiring platforms. |
No surprises really, but I've confirmed that the standard Rust toolchain is working fine all the way to App Store validation using Xcode 14. I've added a notice to |
Closing as per the comment above. |
Bitcode is the future of Apple's app distribution and we don't support it now. Doing so is tricky because Apple choses whatever rev of LLVM they want and upgrade it per their whims. We can't couple our LLVM to theirs because we have our own needs and can't be forced to upgrade whenever Apple decides.
Here are some options:
I think the LLVM dynamic loading and defer-to-alternate-rustc solutions are most promising.
cc https://users.rust-lang.org/t/ios-rust-integration/6928/4
cc @bluejekyll
The text was updated successfully, but these errors were encountered: