- Notifications
You must be signed in to change notification settings - Fork7
Geal/rust_on_mobile
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
- Create the Rust library
- export some symbols with libc (for iOS)
- use rusty-cheddar to generate the headers, or write them manually
- install
cargo-lipo
:cargo install cargo-lipo
- install the required toolchains:
- rustup target add aarch64-apple-ios
- rustup target add armv7-apple-ios
- rustup target add armv7s-apple-ios
- rustup target add i386-apple-ios
- rustup target add x86_64-apple-ios
- install the cocoapods:
sudo gem install cocoapods
(cfhttps://cocoapods.org/ ) - use the command
pod lib create InRustWeTrustKit
to create the pod with an example app - remove the
.git
folder in the pod - move the podspec file at the root of the project
- change
InRustWeTrustKit/Example/Podfile
to point to the pod at../../
instead of../
- update the
source_files
path in the podspec fromInRustWeTrustKit/Classes/**/*
toInRustWeTrustKit/InRustWeTrustKit/Classes/**/*
- add the
prepare_command
in the podspec file to build the library - use
pod lib lint --verbose
to verify the podspec file cd InRustWeTrustKit/Example && pod install --verbose
to test building with the example app
CocoaPods have a lot of requirements to push them to the repo, like having a validLICENSE file, making a different branch for every version, and storing every podspecfile in a github repository, so be prepared to spend some time fighting those issues.
- download the Android NDK
- Create the
rust-jni
project to host the JNI interface:cargo new rust-jni
. It will generate a dylib - add the original project as dependency by path
- create the JNI export functions
- write a
.cargo/config
file with the following content (adjust the paths, platform and SDK version accordingly):[target.arm-linux-androideabi]ar = "/usr/local/Cellar/android-ndk/r11c/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ar"linker = "/Users/geal/dev/rust_on_mobile/rust-jni/linker-wrapper.sh"
- the
rust-jni/linker-wrapper.sh
file was a ugly hack I needed to link when a link option was unavailable with the linker version, not sure it's still needed cargo build --target=arm-linux-androideabi
cp target/arm-linux-androideabi/debug/libinrustwetrust.so ../android/src/main/jniLibs/armeabi/libinrustwetrust.so
cp target/arm-linux-androideabi/debug/libinrustwetrust.so ../android/src/main/jniLibs/armeabi-v7a/libinrustwetrust.so
(we should probably build with another arch there)
- create an Android library project with Android studio, put it in the
android/
directory - create the classes corresponding to the exported interface
- load the library. The dylibs should be in
src/main/jniLibs/<arch>/
in settings.gradle:
include ':InRustWeTrust'project(':InRustWeTrust').projectDir = new File('<PATH_TO>/rust_on_mobile/android')
in build.gradle:
dependencies { compile project(path: ':InRustWeTrust')}
in gradle.properties:android.useDeprecatedNdk=true
in local.properties (update paths accordingly):
sdk.dir=/path/to/android-sdk-macosxndk.dir=/usr/local/Cellar/android-ndk/r11c
In the app's code,import com.geal.InRustWeTrust;
andLog.d("TEST", "result: "+Integer.toString(InRustWeTrust.add(1, 2)));
Right now, the exported C symbols will also end up in the Android library
Can we generate the Java classes?Can we avoid writingJava_com_etc
?maybe with a compiler plugin
The current way for iOS is to generate a so-called "universal binary" that will contain code for alltargeted architectures. Apple decided that since binaries are becoming large (well, not that largecompared to all the Retina aware icons, but I digress), they will make a library format containingLLVM bitcode that will be precompiled by Apple, so that you only receive the binaries for your archwhen you download an app (cfhttp://lowlevelbits.org/bitcode-demystified/ for more info).
We can generate LLVM bitcode with Rust, but there's an incompatibility in the formats.Apple's clang uses the following version:
$ xcrun clang -vApple LLVM version 7.0.2 (clang-700.1.81)Target: x86_64-apple-darwin14.5.0Thread model: posix
From what I understand, Rust uses LLVM 3.8.1.
Apparently, The flag used to ship bitcode in the library is available from LLVM 3.8.1, but Apple used itin its 3.7 fork before contributing it back. So the bitcode generated by rustc could be incompatible:
$ cd inrustwetrust/$ cargo rustc -- --emit llvm-ir[...]$ xcrun clang -c target/debug/inrustwetrust.lltarget/debug/inrustwetrust.ll:9:133: error: expected value token ...{ %str_slice, %str_slice, i32 } { %str_slice { i8* getelementptr inbounds ([30 x i8], [30 x i8]* @str6... ^1 error generated.
So it looks like right now, it's impossible to generate an iOS library from Rust using the bitcode format.
Exception unwinding is apparently incompatible between Rust and ObjectiveC because of compact unwinding
Linking the app can fail with the following error:
ld: too many personality routines for compact unwind to encode for architecture x86_64
This can be fixed by passing-Wl,-keep_dwarf_unwind -Wl,-no_compact_unwind
as "other linker flags".From what I understand, Objective C has a different exception unwinding system that is not usingthe dwarf based one like Rust.
Another idea would be to remove exception unwinding from the rust code, with apanic=abort
, butthat means any exception would generate a crash in the Rust code, which is not a great solution.
About
Resources
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Uh oh!
There was an error while loading.Please reload this page.