How to compile Rust command line tools for Termux
Tags: android, rust, linux, architecture
Published: 2022-01-16 04:09:00

In this tutorial I gonna show you how you could compile and run Rust programs directly on your Android device with pretty much the same experience you would have on your Linux machine. But first, let's go to the basics.

### What is Rust

[Rust](https://www.rust-lang.org/) is a compiled system's programming language focused on safety and performance, being used by the Linux Kernel, Google, Microsoft and others for building embedded systems, webassembly tools and (you guessed) command line apps.

### What is Termux

[Termux](https://termux.com/) is a terminal emulator for accessing your Android OS, since Android is UNIX-like, most of the commands you gonna be working with are basically the same on any Linux Distribution like Ubuntu or Debian, it also comes with it's own package manager called pkg. checkout the [Wiki](https://wiki.termux.com/wiki/Main_Page) for more info on that.

### Why you should read this tutorial?

If you are already aware of how Termux works or want to learn how to directly compile Rust for different architectures, this tutorial is totally for you.

## Nuff Talking

First you gonna need some things:

- Git
- Rust
- Curl
- Android NDK and SDK
- SCP
- Unzip
- Python
- Nano (any text editor of your preference)

Ok... so let's get the requirements, first run on your terminal (I assume you are using a Debian-based machine or WSL with either Ubuntu or Debian installed):
```
sudo apt update && sudo apt install -y nano git curl unzip python
```
Now let's install Rust, they provide us an easy way of installing using the following command (it is going to ask you some things but just go for the default option provided):
```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
Now finally the Android Requirements, it's gonna be a litte harder but I'm gonna try to make it all in one command:
```
mkdir $HOME/Android && \
cd $HOME/Android && \
mkdir sdk && \
wget -O sdk-tools.zip https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip && \
unzip sdk-tools.zip && rm sdk-tools.zip && \
mv tools ./sdk/tools && \
cd ./sdk/tools/bin && yes | ./sdkmanager --licenses && \
./sdkmanager "build-tools;29.0.2" "patcher;v4" "platform-tools" "platforms;android-29" "sources;android-29" "ndk-bundle" && \
echo "export ANDROID_SDK=\$HOME/Android/sdk" >> $HOME/.bashrc && \
echo "export ANDROID_NDK=\$ANDROID_SDK/ndk-bundle" >> $HOME/.bashrc && \
echo "export PATH=\$PATH:\$ANDROID_SDK/platform-tools:\$ANDROID_SDK/tools/bin" >> $HOME/.bashrc && \
source $HOME/.bashrc && cd $HOME
```
BTW, I know it's a huge command, but it's is either that or have Android Studio installed (and maybe you don't really want that :P), but what is does is install Android SDK Tools, configure them and add them to your path so you can use them without having to specify the entire path.

### Configuring the NDK
Now that you have Android NDK you have to configure the toolchain for Rust to use it, rust will compile againt the mobile architectures so we gonna need a toolchain for arm64, arm and x86. NDK provide us a python script for creating a toolchain, All we have to run is:
```
mdkdir $HOME/Android/toolchains && \
cd $HOME/Android/toolchains && \
$ANDROID_NDK/build/tools/make_standalone_toolchain.py --api 26 --arch arm64 --install-dir ./arm64 && \
$ANDROID_NDK/build/tools/make_standalone_toolchain.py --api 26 --arch arm --install-dir ./arm && \
$ANDROID_NDK/build/tools/make_standalone_toolchain.py --api 26 --arch x86 --install-dir ./x86
```
Ok, now we have to tell rust where to find our toolchain with a config file, it will tell cargo (Rust's package manager) where to look for when trying to compile for those architectures, so with `nano $HOME/.cargo/config` paste the following content
```
[target.aarch64-linux-android]
ar = "$HOME/Android/toolchains/arm64/bin/aarch64-linux-android-ar"
linker = "$HOME/Android/toolchains/arm64/bin/aarch64-linux-android-clang"

[target.armv7-linux-androideabi]
ar = "$HOME/Android/toolchains/arm/bin/arm-linux-androideabi-ar"
linker = "$HOME/Android/toolchains/arm/bin/arm-linux-androideabi-clang"

[target.i686-linux-android]
ar = "$HOME/Android/toolchains/x86/bin/i686-linux-android-ar"
linker = "$HOME/Android/toolchains/x86/bin/i686-linux-android-clang"
```
Let's add our compilation targets for rust using the `rustup` command:
```
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android
```
FINALLY we are ready!!!!

### Compiling a command line tool

I'm not going to make a command line tool from scratch, I'm gonna use something someone already made and shared the source code on Github. Let's use for example [Dust](https://github.com/bootandy/dust), as the description says: "Like du but more intuitive".

First clone the repo:
```
git clone https://github.com/bootandy/dust
cd dust
```
Before compiling the tool checkout your what's your Android Architecture, in my example I have an arm64 (aarch64) device, but you could have a different one, on Termux run `uname -m` to get this information.

Build the project with
```
cargo build --target aarch64-linux-android --release
```
if you navigate into `target/aarch64-linux-android/release` and run `file ./dust` you probably gonna have something similar to this:

```
ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /system/bin/linker64, with debug_info, not stripped
```
YOU DID IT !!! but... how do I use it on my android phone? And why can't I execute it on my Linux machine when I try to run `./dust`? 

First the second question, what you compiled is a aarch64 binary which it's [linker](https://en.wikipedia.org/wiki/Linker_(computing)) points to the Android linker path.
The way we gonna tranfer the content of your Linux machine all the way to termux is via the `scp` command, in other words it's ssh but for copying files.

Instead of having all those files to send let's make rust build a single binary, so it's going to be easier to transfer, for that run the following command, navigate back to dust base directory and then:
```
cargo install --target aarch64-linux-android --path . --root $HOME/Android/binaries
```
it's going to generate a single binary on `$HOME/Android/binaries/bin`, let's cd into there:
```
cd $HOME/Android/binaries/bin
```
Great!!! now all we have to do is move the file over the network to Termux and bob's your uncle.

### Copying the file with SCP

#### on Termux
Before opening the app go to 'Settings > Apps > Termux > Permissions > Storage' and enable storage, now you can tranfer the file with any problems, but let's install some required tools
```
# This has to be executed on Termux, not on Linux
pkg update && pkg upgrade
pkg install net-tools openssh
```
That's all, now we need the required information for copying over the file:

- User -> running `whoami` on Termux
- Local Network IP -> run `ifconfig` and find your wlan0 ip address
- Download Path -> we don't have it, so let's create one
 
On Termux, run:
```
mkdir $HOME/binaries
echo "export PATH=\$PATH:\$HOME/binaries" >> $HOME/.bashrc
source $HOME/.bashrc
```
Now inside the binaries folder run `pwd` and `passwd` to setup a default password.

Finally run this command to start your local ssh server
```
sshd -p 2222 -d
```

#### on Linux
The only thing you have to run here is
```
scp -P 2222 $HOME/Android/binaries/bin/dust <TERMUX_USER>@<TERMUX_IP>:<TERMUX_BINARIES_PATH>
```

There you have it, if you now run `dust` on Termux it's going to work just fine

### Thanks for Reading!!
I really appreciate if you liked this tutorial, no need for share or anything just let me know if you liked it or how can I improve