Use Rust (instead of C++) to develop some algorithms used in Flutter in a real app used in the *production environment* - Is it mature enough? Will I face troubles? Do you suggest it? Has anyone used it?

By the way, as a side remark:

neon is required for running android 6.0, thus all devices you could have today must support arm neon.

(ref: Some phones do not support Neon - can ncnn work on them? · Issue #3256 · Tencent/ncnn · GitHub)

Note that you can do these sorts of checks in Rust (e.g. is_x86_feature_detected!()) to dynamically switch between equivalent functions which may use faster instructions on different machines.

Check out the core::arch module docs for ways SIMD can be used directly in Rust while also avoiding "bad instruction" crashes when certain instructions aren't supported.

3 Likes

I can only help you with iOS, because I don't know Android, but on iOS, you will meet tooling problems with basically any language other than the C family and Swift (i.e., those officially endorsed by Apple). But Rust is "just another" LLVM-based, compiled language. If you compile your Rust code with Cargo upfront, as a library, then bindgen and link it to your project, it won't be any more painful than doing the same with a C library.

Right now building for iOS is a little sub-optimal: Archiving an iOS app that links against code built with 1.52-nightly yields an LLVM ld error · Issue #83106 · rust-lang/rust · GitHub. Apple/Xcode have been clamping down on linking against code built with a version of llvm that emits attributes that the Xcode LLVM doesn't understand, at least when uploading/publishing to the app store. To put it simply, you will have to keep track of which version of llvm your rust toolchain is using and possibly pin your toolchain to a version that is in the current xcode compatibility window. This will impact you most if you need to use nightly rust for something because it's generally ahead of the Xcode llvm. It might be that in the upcoming few stable releases you can just rely on the stable rust to build and everything will be fine, however in my scenario I needed rust nightly so that I could specify custom targets (and build the standard lib) to work around a rust <-> iOS llvm target triple issue. The annoying thing is the code runs fine when built with the newer llvm, it's more of an Apple/Xcode policy to reject binaries that include unknown attributes.

So not as painless as it could/should be but no less possible. I do look forward to the day I don't need rust nightly to build for iOS. And even so, since neither project (xcode or rust) is responsible for keeping versions lined up, even on stable rust there may always be a need to pin to an xcode compatible toolchain version (until the day rust uses an unmodified release of llvm) at least when generating iOS binaries.

1 Like

Thanks for the information! That is a problem... :confused: So how did you solve it?
By the way shall we use nightly rust in production environment - is it stable enough or not?

I build my iOS code with something like:

cargo +nightly-2021-07-24 build \
      -Z unstable-options --profile $PROFILE \
      -Z build-std \
      --target <custom-target-spec-to-work-around-ios-target-issue>.json

The +nightly-2021-07-24 instructs cargo to use the release of the toolchain from that date, which is the last version of the nightly toolchain that uses llvm 12. If you look at the table in the issue, llvm 12 is the maximum Xcode 13 supports (such conveniently confusing numbers). This nightly is the last release of a rust 1.55 nightly (and consequently the last release of the stable 1.53 toolchain; nightly is two versions ahead of stable). Aside: it would be super nice to be able to install a nightly toolchain by version, e.g. nightly-1.55 rather than date.

I believe rust 1.56 includes fixes for the all of the remaining builtin ios targets, however rust 1.56 bumped the default llvm to version 13, for which there is no corresponding Xcode release. Looking at the linked Wikipedia table, the trend seems to be for Xcode to update llvm version in a minor release perhaps midway through its major version lifespan which historically tends to last 1 year... so perhaps 6 months down the road you'll be able to build rust for iOS on stable rust again.

By the way shall we use nightly rust in production environment - is it stable enough or not?

It's not so much about runtime stability. I've never experienced a problem in that regard. It's more that if you embrace nightly features you are responsible for compile time breakage since the apis presented by the features haven't stabilized, specifically, not that the code itself is unstable. I've yet to ever have nightly break (I don't think ever but if it did it didn't take more than 30 seconds to update to some new type or name or whatever). And I've never had safe rust crash whatsoever nightly or otherwise.

4 Likes

Since Apple is the #1 force behind LLVM, I would kinda expect them to properly support older and newer versions of their very own compiler backend, though. It's hard not to see Xcode/the iOS toolchain at fault here (but of course shifting the blame doesn't fix the actual linker error, either).

1 Like

To add to this, @fzyzcjy: of course you don't have to use nightly features — and I'd say you shouldn't, since you are asking about a production environment. Note that unstable features still require explicit #![feature(...)] attributes even on nightly, so unless you specifically opt into those, your code won't be exposed to breakage by default, not even on nightly.

1 Like

I don’t know about the mobile side but I was involved on a commercial project that used Rust for our proprietary code and interfaced with OpenCV without too much bother. I don’t know the details as I didn’t write that part of the code, but certainly it wasn’t a big problem. In general I would think that unless you are already a highly competent C++ programmer you shouldn’t worry about what micro optimizations you’re getting or not getting - run with Rust. You’ll get a much better development experience and any performance difference will almost certainly not be noticeable. </opinion>

4 Likes

@H2CO3 @dcow-uno The most appealing nightly feature for me, up to now, is (partially) NEON support. If I understand correctly, I can use it (partially) if I use the nightly toolchain and enable some feature flag.
Well, since you provide opposite suggestions on using nightly or not, I may first try not to touch it until one day I have to.
Thanks for suggestions!

@dcow-uno

This nightly is the last release of a rust 1.55 nightly (and consequently the last release of the stable 1.53 toolchain; nightly is two versions ahead of stable).

I am a bit confused. I am using Rust stable 1.55 + XCode 12.4 (according to your suggestion I can upgrade to 13). The problem is, if your 1.55nightly=1.53 has problem, then my stable1.55=nightly1.57(?) will also have problems?

@pierznj Thanks for the information!

Well NEON might actually be somewhat of an exception. If the very point of your code is to accelerate computations using NEON, of course you can use it. However, many (most?) nightly features are such that they don't enable something that isn't possible, they merely make some things more convenient (for some definition of convenience). I was mainly referring to those features. But if you are almost at the assembly level, and are using the feature flag to enable platform-specific, low-level details, then the risk is not really breaking backwards compatibility, it is instead breaking cross-platform compatibility, which you are fine with.

1 Like

@H2CO3 Yes, I am using it in android and ios mobile phones. I can accept slowness in computers (so no neon is ok for x86). So based on your suggestions, I will try to use the nightly and see whether it works. Thanks!

@H2CO3 @dcow-uno Indeed nightly is described as "unstable". Originally I thought it mean "not safe - you will be in trouble". But now I know it just means api may change later.

Nightly does two things:

  • First, you can use unstable flags and unstable language features. These are still opt-in. You’ll have to explicitly pass -Z … options to rustc, or manually add #[feature(…)] attributes to your source code to get access to anything that could change in the future. So while nightly allows access to unstable features, you still cannot accidentally use any unstable features/APIs that lead to breakage in the future.
  • Second, nightly is less tested. If a compiler bug makes a bunch of crates stop compiling, potentially including yours, with nightly, such a bug will be in the compiler you use. Bugs that make the compiler actually misbehave are far less common, but there’s a slight risk, too. The stable compiler is already tested for 6 weeks as beta before it gets released; the tests also include crater runs, testing all public crates on crates.io and github to avoid any compiler regressions (i.e. code stops compiling or tests stop passing). But nightly compiler still only contains reviewed code that also passed the compiler test suite, so the risk is limited.

Much of the unstable features / API that rust offers is still in development. Nightly has another advantage over stable that comes into play here: It’s more up-to-date. A nightly compiler is always 6-12 weeks newer than the latest stable compiler. By making unstable features only available on nightly, we can avoid people running into any problems with these under-development unstable features that are actually already fixed (at least if the fix is at least 1 day old).

The up-to-date-ness of nightly of course also means that you can use it to gain access to stable features/API earlier. Using beta, you can access any new stable feature 6 weeks early, using nightly you can get some features up to 12 weeks early. E.g. right now, Rust 2021 edition is already available on beta and nightly.

4 Likes

@steffahn Thanks for your information! Now I have a mixed feeling, and not sure whether I dare to use nightly in order to use NEON...

Note that, as your godbolt link above demonstrates, you do not need nightly to use -C target-feature=+neon and benefit from auto vectorization. You only need nightly to manually use the SIMD intrinsics in core::arch or inline assembly. There are also some community crates that enable some SIMD functions on stable.

2 Likes

It's hard not to see Xcode/the iOS toolchain at fault here (but of course shifting the blame doesn't fix the actual linker error, either).

I mean it's certainly their fault for being pedantic, but they're also not technically wrong (so good luck convincing them to walk back). It's not so much backwards compatibility, that shouldn't have a problem. Their tooling is encountering unknown attributes from an llvm from the future, who knows what those mean and whether the code is actually compatible with their linker or wether it just happens to work. They're being conservative.

It's also worth noting that rust, not Xcode, needs its own fork of llvm. That's certainly not something Apple is on the hook for supporting even though it may be in their interest to have mainline llvm support rust. Apple doesn't even allow you to use open source releases of their own Swift compiler toolchain when submitting to the app store, you have to use the toolchain bundled with Xcode, and that's entirely 1st party. It is no less frustrating for sure.

1 Like

At my company, we solve this by building the Rust toolchain from source, linked against an LLVM that matches our Xcode version. Our process for doing this is based on this repository from Ditto, another company shipping Rust code on iOS.

Our custom toolchain is only required when making builds that get pushed to the app store. Builds for other platforms, or for development and testing, can use normal Rust binaries from rustup.

5 Likes

I am a bit confused. I am using Rust stable 1.55 + XCode 12.4 (according to your suggestion I can upgrade to 13). The problem is, if your 1.55nightly=1.53 has problem, then my stable1.55=nightly1.57(?) will also have problems?

Indeed, it is confusing. You probably can't archive for the app store with your 1.55 stable (llvm 12) + xcode 12.4 (llvm 11) setup and would need to use Xcode 13 once you decided to submit the app. Everything will work otherwise up to the point of Archiving a build.

If you use +nightly without any other specifier and stable is at 1.55, then nightly is at 1.57. AFAIK 1.57-nightly would have the problem of the llvm base version being 13, but has otherwise includes fixes for all the target issues (they landed in 1.56), so once a newer Xcode comes around that can handle llvm version 13, you could just build like cargo +nightly build. Otherwise you have to wait till stable 1.56 to get the fixes but stable 1.56 is not compatible with any currently known Xcode.

At this point you should probably just try it out and post any additional color to the issue I created. Who knows maybe something about your setup works or doesn't work in different ways. Specifically I'm building my rust library code into an XCFramework (which you'll probably want to do so you can integrate using swift package manager) and it's possible Xcode only cares about the issue I have to workaround in that specific scenario. I mostly just wanted to make sure you didn't get the impression that everything would just work out of the box, because at the moment I am dubious of any such claim.

1 Like

At my company, we solve this by building the Rust toolchain from source, linked against an LLVM that matches our Xcode version. Our process for doing this is based on this repository from Ditto, another company shipping Rust code on iOS.

Our custom toolchain is only required when making builds that get pushed to the app store. Builds for other platforms, or for development and testing, can use normal Rust binaries from rustup .

Ah right, this is the other solution. We should probably make the jump to doing this as well. I didn't know about that repo at the time I set our build up and didn't feel the overhead of building a custom rust against the Apple llvm was quite in scope at the time since we were just getting everything bootstrapped, but with this prior art from Ditto, it's probably lowers the barrier enough to give it a go. Thanks for sharing!

2 Likes