• Home
  • Blog

Mobile-app core in Rust #2: Setup environment

2024-11-16T05:32:00-0800
  • #rust
  • #rust-mobile-core
  • #ios
  • #android

This entry is the second in the #rust-mobile-core series. Today, I will cover setting up the environment for developing an app using this architecture.

Environment setup can be divided into tasks that you need to do only once and tasks that need to be done for each project. This entry will cover the former.

Once you complete the steps in this entry, you should be able to build my sample project. I will explain how to do that at the end of this post.

Install Required Software

Obviously, you'll need Android Studio for Android development and Xcode for iOS development. Please install them if they aren't already on your system.

I use Linux for Android development and macOS for iOS development, so my explanations will be based on those environments. For Android Studio, there should be no significant differences between Linux and macOS except for file paths, so adapt accordingly.

Installing the NDK (Android Only)

If you are developing an Android app, in addition to Android Studio itself, you'll need to install the NDK.

To install the NDK, select Tools -> SDK Manager from the Android Studio menu. Then, select the SDK Tools tab in the middle of the page.

Make sure to check the box for Show Package Details in the bottom right to specify the NDK version.

The screen should look something like this:

install ndk

Here, select 22.1.7171670 for the NDK version, then click OK or Apply to install it.

Why Use an Older Version of the NDK?

I started developing with this architecture about two years ago. At that time, with the then-latest NDK version, Rust library builds would seem successful but result in an error at runtime due to missing symbols. While simpler libraries were unaffected, more complex libraries that used various crates had a high probability of encountering this issue. Eventually, I resolved this by downgrading to version 22, after which the problem disappeared. Since then, I've been sticking with this version.

However, I haven't tried newer NDK versions since then, so if anyone has information on the current state of the NDK, I'd be happy to hear it.

Modifying the NDK to Enable Rust Library Builds

By default, trying to build a Rust library with the NDK might result in errors such as missing libgcc.a or libunwind.a. With version 22.1.7171670, you'll likely see an error indicating that libunwind.a could not be found, as follows:

= note: ld: error: unable to find library -lunwind
        clang: error: linker command failed with exit code 1 (use -v to see invocation)

You can solve this by creating a libunwind.a file in the same directory as libgcc.a, with the following content:

INPUT(-lgcc)

In newer NDK versions, the roles of libunwind and libgcc may be reversed, in which case creating a libgcc.a file referring to libunwind should solve the problem.

Below is the shell script I used:

find ~/Android/Sdk/ndk/22.1.7171670/toolchains -name libgcc.a | while read libgcc_path; do
  dir_path=$(dirname "$libgcc_path")
  echo 'INPUT(-lgcc)' > "$dir_path/libunwind.a"
done

Adding NDK to PATH

If you installed the NDK in the default location, it should be at the following paths:

  • Linux: ~/Android/Sdk/ndk/22.1.7171670
  • macOS: ~/Library/Android/sdk/ndk/22.1.7171670

If it's in a different location, adjust accordingly. The directory that needs to be added to PATH is as follows:

  • Linux: ~/Android/Sdk/ndk/22.1.7171670/toolchains/llvm/prebuilt/linux-x86_64/bin
  • macOS: ~/Library/Android/sdk/ndk/22.1.7171670/toolchains/llvm/prebuilt/darwin-x86_64/bin

This completes the NDK-side setup.

Installing Rust

I assume readers of this series already have experience with Rust, so I won't go into much detail on installing Rust itself. For this post, I'll assume Rust is installed via rustup.

Adding Mobile Targets for Rust

Please add the following targets. Here, we're only targeting 64-bit architectures. If you want to support older 32-bit devices, you'll need to add those targets as well.

  • For Android:
    • aarch64-linux-android
    • x86_64-linux-android
  • For iOS:
    • aarch64-apple-ios
    • aarch64-apple-ios-sim

If you're using an Intel Mac, add x86_64-apple-ios instead of aarch64-apple-ios-sim.

You can add the targets with the following commands:

# targets for Android
rustup target add arch64-linux-android x86_64-linux-android

# targets for iOS
rustup target add aarch64-apple-ios aarch64-apple-ios-sim

Configuring Cargo

Open ~/.cargo/config.toml and add the following:

[target.aarch64-linux-android]
linker = "aarch64-linux-android30-clang"

[target.x86_64-linux-android]
linker = "x86_64-linux-android30-clang"

Installing cargo-lipo

For building iOS libraries, cargo-lipo makes it easy to create universal libraries without needing to do it manually. Install it with the following command:

cargo install cargo-lipo

Verifying the Setup

After completing the setup, you should be able to build my sample project. Follow the steps below to try building the project.

The sample project can be found here:

https://github.com/typester/auth2/

Android

Use the following command to generate the Rust library and Kotlin bindings:

cd ./core
./build-android-lib.sh

Once the build completes without errors, you should be able to open the android directory in Android Studio and run the app.

iOS

Use the following command to build the Rust library:

cd ./core
cargo lipo --release
cargo build --release --target aarch64-apple-ios-sim

Once this completes without errors, you should be able to open ios/Auth2.xcodeproj in Xcode and run the app.

Summary

In this entry, I summarized the setup process for the #rust-mobile-core environment. Setting up Android development can be a bit of a hassle, but once it's done, you won't need to worry about it anymore, so let's get through this initial effort.

Next time, I'll write about how to start a project and the setup needed for each project.

Copyright © 2024 by Daisuke Murase.

Powered by org-mode.