Integrating Rust into the Android Open Source Project
security.googleblog.com
security.googleblog.com
>> This is problematic for Android devices where resources like memory and disk usage must be carefully managed because statically linking all crates into Rust binaries would result in excessive code duplication (especially in the standard library). However, our situation is also different from the standard host environment: we build Android using global decisions about dependencies. This means that nearly every crate is shareable between all users of that crate. Thus, we opt to link crates dynamically by default for device targets. This reduces the overall memory footprint of Rust in Android by allowing crates to be reused across multiple binaries which depend on them.
>> Since this is unusual in the Rust community, not all third-party crates support dynamic compilation. Sometimes we must carry small patches while we work with upstream maintainers to add support.
Having a dynamic linking option for Rust would be a tremendous improvement.
It would help to solve vendoring issues and hopefully improve interop with existing systems and programming languages.
Good dynamic linking support and enhanced interop with C would make it much easier to do a piece-wise replacement of C components with Rust components, allowing for a gradual migration in places where it makes sense to do so.
Also note that Android is more C++ than C. And C++-Rust integration is something Rust has already done in Firefox. The road is paved, at least partially. So I have high hope here in long term.
[1] https://android-developers.googleblog.com/2018/05/faster-ado...
I don't think this is really true.
The simple fact that Rust can't overload functions causes significant grief in a C++/Rust interface, for example.
Personally, I now see C++ as an evolutionary dead end--yes, it's going to continue to exist for a bit until we get a language that is ready for game programmers can use. After that, the fall of C++ will be fast.
This is especially true since we are now back to lots of projects side-stepping the C++ standard libraries. If you're going to do that, why use C++ in the first place?
The simplicity of C is much better suited to being a lingua franca, and much better languages are appearing that can finally be the "Successor to C".
https://developer.nvidia.com/cuda-zone
https://devblogs.microsoft.com/directx/
https://developer.apple.com/metal/
https://www.unrealengine.com/en-US/
https://www.crytek.com/cryengine
https://www.misra.org.uk/Activities/MISRAC/tabid/171/Default...
https://docs.microsoft.com/en-us/windows/apps/winui/
This is the kind of tooling and ecosystems that Rust still needs to build, besides a plain compiler + cargo.
I wonder how much of an obstacle the lack of the stable ABI and the inability to transparently use C headers still are.
I think the idea of this article is that you don’t need to understand two tool chains but instead can focus on the harder task of understanding two languages.
Rust does not consume C headers. For every function and data structure of the API surface you gonna need two language projections, C header and Rust source file. For large API surfaces, especially when both sides of the FFI evolve over time, bugs are inevitable.
The problem is not specific to Rust. It affects all languages, except C++ and Objective-C which are backward compatible.
You do not have to write these things, nor keep track of changes, by hand.
The most popular C library in the world is probably the standard one. Yet in https://github.com/rust-lang/libc I don’t see any glue automatically generated from C headers, everything’s written manually.
Other examples: https://github.com/servo/rust-png/ https://github.com/bozaro/lz4-rs
There are a few big reasons to consider avoiding parsing the C headers directly:
* The C headers might use features in C that are not compatible with the C parser or Rust ABI itself. (C unions used to be a big headache, and bitfields probably still are.). Manually specifying only what you want to import avoids that issue entirely.
* As an extended note to the above, many libraries (particularly your system's implementation of libc) are actually not written in any standard C dialect but instead have a lot of compiler-specific things tacked onto it that make it even more difficult to parse and handle correctly than regular C/C++.
* Parsing the C headers requires having them installed and being able to find them correctly. When you start dealing with cross-compilation toolchains, this can be a major hassle.
Yet, at least. I hope one day it can, transparently.
Having to maintain this interface between the language does come with its own set of problems but is well worth the tradeoff especially if you can spend most of your time in one language or the other.
The reason to pay this cost is that the alternatives are: (1) do nothing: keep developing solely in C, (2) rewrite the big C project in Rust in its entirety. The cost of option (1) is significant: memory safety errors contribute to 70% of defects not detected by test [1]. Even with static+dynamic checking tools, developers keep introducing bugs into C projects that aren't possible in safe Rust [2]. The cost of option (2) is significant risk. Big C projects have grown over time and have many implicit requirements already satisfied. Discovering all of those incidental bugs and features that are necessary takes a long time and scales with the size of the project.
[1] https://msrc-blog.microsoft.com/2019/07/16/a-proactive-appro...
[2] http://blog.vmsplice.net/2020/08/why-qemu-should-move-from-c...
(I have some ideas of what you may say but am curious! You clearly have strong feelings here.)
However, AOSP is massive. It is HUGE. And complicated to build. I really, really doubt this addition will make a huge deal.
This is the same for many of the huge projects adopting Rust. The worst one so far is the Linux kernel IMO, because at least that is mostly C and GNU Make. And yet even there, that still isn't that bad.
Also, as far as bugs at the interface, I'm pretty sure it's a wash. C and Rust are ABI compatible to the extent that matters. The "subtle bugs" are most likely going to be ones that could've existed without the additional complexity of a new language and an interface between them. It's no worse than say, JNI, which doesn't seem to be a serious issue.
I'm pretty sure the benefits of Rust can outweigh this cost. As long as you can build the project, you don't really need to understand 2 toolchains to contribute unless your contribution lands across a boundary between 2 toolchains. On a lot of really large projects this may already be the case anyways.
In whichever case, we should be careful not to overstate the complexity of integrating Rust and C. Specifically, bringing in any given C dependency means integrating its bespoke build system (and those of each transitive dependency) with that of your project (or more likely, you punt on reproducible builds and instead push the dependency hell onto every contributor) which doesn't strike me as considerably less work than integrating the Rust toolchain (and since Rust has sane, standard build/dependency tooling, it's pretty much a one-time cost rather than a once-per-dependency cost).