Compiling Rust Apps for Termux with nix-shell
I've been building a program to track how I spend my time, and a couple of the requirements are an interface on my phone, and sync between multiple devices. Since I haven't built an android app in forever, I decided to target termux, at least initially. This will allow me to use the app and test out the synchronization protocol without a ton of upfront effort into building a graphical user interface.
Cross Compiling for termux
The first thing we need to cross compile to termux is a cross compiler. rustc
is a cross compiler by default, but with some important caveats: rustc
needs a
linker and a pre-made rust stdlib for the target platform.
I use the wonderful NixOS as my dev environment, so we will be using nix-shell
to get the dependencies we need. In your project's directory, create an
android.nix
file and put the following code inside it.
# android.nix let # Get the mozilla nixpkg overlay for a convient rust installation moz_overlay = import ( builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz ); native-pkgs = import <nixpkgs> { overlays = [ moz_overlay ]; }; pkgs = import <nixpkgs> { crossSystem = native-pkgs.lib.systems.examples.armv7a-android-prebuilt; }; # Get the latest stable compiler version and install the armv7 android target with it rust = (native-pkgs.rustChannels.stable.rust.override { targets = [ "armv7-linux-androideabi" ]; }); in # Note the call to `pkgs` here, instead of `native-pkgs` pkgs.callPackage ( {mkShell, cargo}: # mkShell will drop us into a shell that has a $CC for the target platform mkShell { nativeBuildInputs = [ rust ]; } ) {}
Running nix-shell android.nix
will drop you into a shell with cargo
and an
armv7 c compiler. Before we can build the rust project, we have to inform cargo
to use said compiler for linking armv7 executables. Open .cargo/config
(in
your project's directory) and put the following in:
[target.armv7-linux-androideabi] linker = "armv7a-unknown-linux-androideabi-clang"
Now we can build our project termux! We simply start nix-shell
and then tell
cargo to compile the project:
$ nix-shell android.nix --run "cargo build --target=armv7-linux-androideabi"
Now just push the executable to your android device.
$ adb push target/armv7-linux-androideabi/debug/cli /storage/self/primary/our-cli-app
And then run the app from termux.
$ cp /storage/self/primary/our-cli-app ./ $ chmod ./our-cli-app $ ./our-cli-app --help
Results
It works! :O
Resources
- https://nixos.wiki/wiki/Cross_Compiling
- https://matthewbauer.us/blog/beginners-guide-to-cross.html
- https://github.com/NixOS/nixpkgs/blob/master/lib/systems/examples.nix
- https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/androidndk-pkgs/androidndk-pkgs.nix
- https://github.com/NixOS/nixpkgs/pull/56540