rust-universal-template icon indicating copy to clipboard operation
rust-universal-template copied to clipboard

Template for creating Rust libraries with bindings to iOS, Android, WebAssembly and more

Rust Universal Template

Swift 4.1 Rustc Version 1.25+ CircleCI Carthage compatible

Template for creating universal Rust libraries with bindings to iOS/macOS (Swift), Android (Java/JNI), JavaScript (WebAssembly), and more.

Goals

  • [ ] iOS / macOS
    • [x] Swift Framework template
    • [x] Run cargo via Xcode External Build System
    • [x] Carthage support
    • [ ] CocoaPods support
    • [ ] Automated Rust => Swift binding generation
    • [x] Example iOS app
  • [ ] Android / Java
    • [ ] Gradle library template
    • [ ] Automated Rust => Java/JNI binding generation
    • [x] Pure Java example
    • [ ] Example Android app
  • [ ] Web Browsers / JavaScript
    • [ ] JavaScript / WebAssembly template
    • [ ] Automated Rust => JavaScript binding generation (wasm-bindgen)
    • [ ] Example app
  • [ ] General
    • [ ] Automated Rust => C binding generation (cbindgen)
    • [ ] Create cookiecutter template
    • [ ] Documention and examples for best practices when using Rust from other languages

Setup

Install Rust via Rustup:

$ curl https://sh.rustup.rs -sSf | sh

Make sure the Rust binaries are added to your PATH (e.g. inside ~/.profile). This is usually performed automatically for you by rustup.

export PATH="$HOME/.cargo/bin:$PATH"

iOS

Install the iOS targets for your selected toolchain:

$ rustup target add aarch64-apple-ios armv7-apple-ios x86_64-apple-ios i386-apple-ios

Install cargo-lipo for generating universal iOS libraries:

$ cargo install cargo-lipo

Bitcode

If you want Bitcode support you'll need to use a Rust nightly 1.2.7+ build (as of 4-27-2018). Unfortunately there still seems to be some issues with Bitcode so it is disabled for now. For more information see issue https://github.com/rust-lang/rust/issues/35968.

$ rustup toolchain install nightly
$ rustup target add aarch64-apple-ios armv7-apple-ios x86_64-apple-ios i386-apple-ios --toolchain nightly
$ rustup default nightly

Android

Install Android NDK (tested on version r16b):

$ brew cask install android-ndk

Add ANDROID_NDK_HOME to your bash profile (e.g. ~/.profile):

export ANDROID_NDK_HOME="/usr/local/share/android-ndk"

Install Android Rust targets:

$ rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android

Run build-android.sh. This will create a standalone NDK toolchain and in the NDK directory if needed, and then run cargo build for all Android targets.

$ ./build-android.sh

Java

To regenerate the Java JNI bindings, you need to first compile the Java with javac and then run javah to generate a C header. This generated header HelloWorld.h shows us the expected method signature for the JNI function.

# Compile Java
$ javac Source/Java/HelloWorld.java
# Generate C header JNI interface
$ javah -classpath Source/Java -d Source/Java HelloWorld

The corresponding Rust source code can be found in Source/Rust/java/src/lib.rs. We must first compile it, so the output shared library (libexample.dylib on macOS) can be found by Java.

$ cargo build --features "java" --release

Finally, we can run our Java code that calls into the Rust code:

$ javac Examples/Java/HelloWorld/Main.java -classpath Source/Java
$ java -Djava.library.path=target/release -classpath "Source/Java:Examples/Java/HelloWorld" Main
Hello, from Rust!!

Install Visual Studio Code (optional)

VS Code offers an IDE-like experiene for developing your Rust code, including some rough LLDB debugging support.

Structure

Source/Rust

The src folder contains all of our Rust library source code (.rs) and a manually created C header file (example.h) exporting a few symbols of interest from our Rust code. The build output is a static library called libexample.a.

ExampleObjC.framework

This iOS/macOS framework contains a Objective-C wrapper around the the C interface exposed by example.h.

ExampleSwift.framework

This iOS/macOS framework contains a Swift wrapper around the the C interface exposed by example.h.

Reference

Tools

  • android-rs-glue - Glue between Rust and Android, including cargo-apk command
  • cargo-lipo - Cargo subcommand to automatically create universal libraries for iOS.
  • cbindgen - A project for generating C bindings from Rust code
  • wasm-bindgen - Interoperating JavaScript and Rust
  • rust-bindgen - Automatically generates Rust FFI bindings to C (and some C++) libraries

Examples

Articles

License

MIT