bnsmb
Recognized Contributor / XDA University Professor
For phones without root access this approach is not possible.
Instead, the Termux app can be used: Termux is a full featured Linux environment including the clang toolchain. But Termux is a closed environment -- as long as you stay in Termux it's okay. But it's difficult to use Termux executables or executables created with the clang compiler in Termux, outsite of the Termux environment (See here for details about using Termux)
Therefore, I created a tar archive with the clang19 toolchain and other required tools to compile binaries with clang version 19 on the phone:
clang19_toolchain-v1.5.0_release_21.09.2025_.tar.gz
The tar file contains a clang19 toolchain that must be installed in the directory /data/local/tmp/sysroot.
The toolchain contains :
clang 19.0 binaries and files
make
cmake
ninja
the autoconf tools, libtool, and m4
pkg-config, pkgconf
gnupatch
binutils (addr2line ar as c++filt elfedit gprof ld ld.bfd nm objcopy objdump ranlib readelf size strings strip)
bison
flex
perl
python
pip
meson
texinfo
tcl
gdb
rsync
wget
curl
sshd/ssh
git
man
bash
nano
vi
tmux
openvpn
and some other tools -- all configured for the target directory /data/local/tmp/sysroot.
Most of the binaries in the tar file are compiled as static binary or as dynamic binary that only require the standard libraries from the Android OS.
The necesssary files to compile executables and libraries using clang in Android from the Android NDK are also part of the tar file.
As of 21.09.2025 the files from the Android NDK versions r27b, r27c, r27d, and r28b are part of the tar file.
To install the clang19 toolchain, these steps must be carried out:
First copy the tar flle to the phone
Note:
All commands below should be done in an adb shell by the standard user for adb shells -- that is the user shell. No root access is required for the commands.
Unpack the tar file in the directory
/data/local/tmp
The toolchain is then installed in the directory
/data/local/tmp/sysroot
Notes:
The unpacked tar file occupies about 2.7 GB space.
The path /data/local/tmp/sysroot is hardcoded in some of the binaries (e.g. the config files are expected to be in the directory /data/local/tmp/sysroot/etc), therefore the executables from the tar file may not work as expected if the tar file is installed in another directory. And be aware that the tar file must be installed on a partition with a Linux filesystem (like ext3 or ext4) - the installation in a partition formatted with the fat or extfat filesystem does not work.
After unpacking the tar file, prepare the clang19 toolchain environment with this command:
/data/local/tmp/sysroot/create_clang_env.sh
The script create_clang_env.sh creates the necessary directories and files for the clang19 toolchain. The script also initializes the OpenSSH config files and creates the necessary ssh host keys to start the sshd on the phone.
The script only needs to be executed once (but it can be executed more than once without problems).
ASUS_I006D:/data/local/tmp/sysroot $ date
Sun Sep 21 11:45:02 CEST 2025
ASUS_I006D:/data/local/tmp/sysroot $
ASUS_I006D:/data/local/tmp/sysroot $ ./create_clang_env.sh
Initializing the clang environment in /data/local/tmp/sysroot ...
The user executing this script is "shell"; the current home directory is "/data/local/tmp/sysroot/home/shell" ...
The directory "/data/local/tmp/sysroot/home/shell" already exists
Processing the certificate files ...
Copying the certificates from "/system/etc/security/cacerts" to "/data/local/tmp/sysroot/etc/security/cacerts" ...
Creating the file "/data/local/tmp/sysroot/etc/security/ca-certificates.crt" ...
.................................................................................................................................................
... done:
-rw-rw-rw- 1 shell shell 218118 2025-09-21 11:45 /data/local/tmp/sysroot/etc/security/ca-certificates.crt
Configuring the certificate bundle file "/data/local/tmp/sysroot/etc/security/ca-certificates.crt" for git ...
The certificate bundle file for git is "/data/local/tmp/sysroot/etc/security/ca-certificates.crt"
(Use "git config --global http.sslCAInfo <cert_bundle_file>" to change that)
Processing the tar files with the NDKs in the directory "/data/local/tmp/sysroot/usr/ndk/" ...
The tar files with NDKs found are:
-rw-rw-r-- 1 shell shell 58624967 2025-09-20 15:28 r27b.tar.gz
-rw-rw-r-- 1 shell shell 59746977 2025-09-20 15:28 r27c.tar.gz
-rw-rw-r-- 1 shell shell 59737567 2025-09-20 15:28 r27d.tar.gz
-rw-rw-r-- 1 shell shell 72213190 2025-09-20 15:28 r28b.tar.gz
Processing the tar file "r27b.tar.gz" ...
The tar file contains the NDK "r27b"
Unpacking the tar file "r27b.tar.gz" ...
... tar file "r27b.tar.gz" succesfully unpacked
Processing the tar file "r27c.tar.gz" ...
The tar file contains the NDK "r27c"
Unpacking the tar file "r27c.tar.gz" ...
... tar file "r27c.tar.gz" succesfully unpacked
Processing the tar file "r27d.tar.gz" ...
The tar file contains the NDK "r27d"
Unpacking the tar file "r27d.tar.gz" ...
... tar file "r27d.tar.gz" succesfully unpacked
Processing the tar file "r28b.tar.gz" ...
The tar file contains the NDK "r28b"
Unpacking the tar file "r28b.tar.gz" ...
... tar file "r28b.tar.gz" succesfully unpacked
OK, the directory with the default NDK "/data/local/tmp/sysroot/usr/ndk/r27d" exists
Uncompressing the compressed files in "/data/local/tmp/sysroot/usr/bin" ...
No compressed executables found in "/data/local/tmp/sysroot/usr/bin"
Creating the config file for vim /data/local/tmp/sysroot/home/shell/.vimrc ...
Correcting the SELinux context for the directory "/data/local/tmp/sysroot/var/tmp" ...
Executing now "/data/local/tmp/sysroot/create_ssh_env.sh" ...
Initializing the ssh environment in /data/local/tmp/sysroot ...
OK; the user executing this script is "shell"
The directory "/data/local/tmp/sysroot/var" already exists
Creating the directory "/data/local/tmp/sysroot/var/mail" ...
Creating the directory "/data/local/tmp/sysroot/var/empty" ...
Creating the directory "/data/local/tmp/sysroot/var/run" ...
The directory "/data/local/tmp/sysroot/home" already exists
The directory "/data/local/tmp/sysroot/home" already exists
Creating the ssh host key "/data/local/tmp/sysroot/etc/ssh/ssh_host_ecdsa_key" ...
Generating public/private ecdsa key pair.
Your identification has been saved in /data/local/tmp/sysroot/etc/ssh/ssh_host_ecdsa_key
Your public key has been saved in /data/local/tmp/sysroot/etc/ssh/ssh_host_ecdsa_key.pub
The key fingerprint is:
SHA256:7fjYbwuFID2nhPwYdisEvkxgPt1zBdqfNCIrNaOGRdw shell@localhost
The key's randomart image is:
+---[ECDSA 256]---+
| o.o. ... |
| o =.+E= . |
| o = / X + |
| * * # @ + |
| . * + S = . |
| . . . o . |
| . o |
| + .. |
| . ooo. |
+----[SHA256]-----+
Creating the ssh host key "/data/local/tmp/sysroot/etc/ssh/ssh_host_ed25519_key" ...
Generating public/private ed25519 key pair.
Your identification has been saved in /data/local/tmp/sysroot/etc/ssh/ssh_host_ed25519_key
Your public key has been saved in /data/local/tmp/sysroot/etc/ssh/ssh_host_ed25519_key.pub
The key fingerprint is:
SHA256:qmXJTiooO65KJbXgzqoKDMVnU6vqL87tyjaIH+pmERo shell@localhost
The key's randomart image is:
+--[ED25519 256]--+
| . |
| . . . |
| .o.+ . |
|Eooo.o |
|o+.o. S |
|*.o. . o |
|oB+ B |
|XB=o B |
|^OBB* . |
+----[SHA256]-----+
Creating the ssh host key "/data/local/tmp/sysroot/etc/ssh/ssh_host_rsa_key" ...
Generating public/private rsa key pair.
Your identification has been saved in /data/local/tmp/sysroot/etc/ssh/ssh_host_rsa_key
Your public key has been saved in /data/local/tmp/sysroot/etc/ssh/ssh_host_rsa_key.pub
The key fingerprint is:
SHA256:CvZ03e7AjLm6kfvIusVFzRItw8BfxB3E5KSMI0Nzkww shell@localhost
The key's randomart image is:
+---[RSA 3072]----+
| .E=+=.==. |
| ..o*B++o |
| o.=+= . |
| +.+ . |
| o . S . . |
| . = = = . |
| B o + . |
| o + . o |
| oo*+o . |
+----[SHA256]-----+
The file "/data/local/tmp/sysroot/etc/ssh/sshd_config" already exists
(The template for the file "/data/local/tmp/sysroot/etc/ssh/sshd_config" in this tar archive is "/data/local/tmp/sysroot/etc/ssh/sshd_config.new" )
The file "/data/local/tmp/sysroot/etc/ssh/ssh_config" already exists
(The template for the file "/data/local/tmp/sysroot/etc/ssh/ssh_config" in this tar archive is "/data/local/tmp/sysroot/etc/ssh/ssh_config.new" )
Creating the empty file "/data/local/tmp/sysroot/etc/ssh/authorized_keys" ...
To enable access via ssh add your public ssh key to the file
/data/local/tmp/sysroot/etc/ssh/authorized_keys
To start the sshd use the command
/data/local/tmp/sysroot/usr/sbin/sshd
The sshd then listens on the port 9022
To connect to the sshd on this machine use the command
ssh -p 9022 192.168.1.148
To copy a file via scp to this machine use the command
scp -P 9022 [source_file] 192.168.1.148:[targetfile|targetdir]
To connect to other machines using ssh from this phone use
/data/local/tmp/sysroot/usr/bin/ssh [hostname]
To make the ssh binaries available via PATH variable execute
source /data/local/tmp/sysroot/init_ssh_env
Use the command
source /data/local/tmp/sysroot/bin/init_clang19_env
to init the clang19 session in an adb shell
ASUS_I006D:/data/local/tmp/sysroot $
To use the clang19 toolchain, open an adb shell and source the script to init the environment:
source /data/local/tmp/sysroot/bin/init_clang19_env
or
. /data/local/tmp/sysroot/bin/init_clang19_env
init_clang19_env sets some environment variables and adds the directories with the compiler and tools to the variable PATH.
If root access is enabled on the phone, the script init_clang19_env also
- enables Socket access for the user shell (this is necessary to run tmux as user shell)
- enables creating hard links for the user shell
- enables access to FIFOs for the user shell
These config changes are optional and not required to use the clang19 toolchain. The config changes are only temporay until the next reboot.
If the clang toolchain is installed in another directory this command can be used to initialize the clang toolchain:
CLANG_SYSROOT="<dir_with_the_clang19_toolchain>" source ${CLANG_SYSROOT}/bin/init_clang19_env
Using this command, the script uses the correct directory in the environment variables. But be aware that the hardcoded directories in the libraries and executables are still using /data/local/tmp/sysroot.
ASUS_I006D:/data/local/tmp/sysroot $ date
Sun Sep 21 11:47:21 CEST 2025
ASUS_I006D:/data/local/tmp/sysroot $
ASUS_I006D:/data/local/tmp/sysroot $ source bin/init_clang19_env
The toolchain directory used is "/data/local/tmp/sysroot"
Checking if the current CPU can execute binaries for arm64 CPUs using the binary "/data/local/tmp/sysroot/bin/testcpu" ...
OK, the current CPU can execute executables for arm64 CPUs.
Running as user "shell"
Preparing the clang environment for creating binaries for the CPU type aarch64
Using clang 19
Using the NDK /data/local/tmp/sysroot/usr/ndk/r27d (environment variable NDK_DIR)
Using the sysroot directory /data/local/tmp/sysroot/usr/ndk/r27d/sysroot (environment variable SYSROOT)
Using the target root directory /data/local/tmp/develop/sysroot (environment variable TARGET_ROOT)
Environment variables used:
PATH is now: /data/local/tmp/develop/sysroot/usr/bin:/product/bin:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/system_ext/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin:/data/local/tmp/sysroot/usr/bin:/data/local/tmp/sysroot/bin:/data/local/tmp/sysroot/usr/clang19/bin
LD_LIBRARY_PATH: :/data/local/tmp/sysroot/usr/lib:/data/local/tmp/sysroot/usr/ndk/r27d/sysroot/usr/lib/aarch64-linux-android:/data/local/tmp/sysroot/usr/clang19/lib
API is now: 31
NDK_DIR is now: /data/local/tmp/sysroot/usr/ndk/r27d
SYSROOT is now: /data/local/tmp/sysroot/usr/ndk/r27d/sysroot
CFLAGS are now: -I/data/local/tmp/sysroot/usr/include -I/data/local/tmp/sysroot/usr/clang19/include -I/data/local/tmp/sysroot/usr/ndk/r27d/include -I/data/local/tmp/sysroot/usr/ndk/r27d/sysroot/usr/include/aarch64-linux-android -I/data/local/tmp/sysroot/usr/ndk/r27d/sysroot/usr/include -I/data/local/tmp/develop/sysroot/usr/include --sysroot=/data/local/tmp/sysroot/usr/ndk/r27d/sysroot
CPPFLAGS are now: -I/data/local/tmp/sysroot/usr/include -I/data/local/tmp/sysroot/usr/clang19/include -I/data/local/tmp/sysroot/usr/ndk/r27d/include -I/data/local/tmp/sysroot/usr/ndk/r27d/sysroot/usr/include/aarch64-linux-android -I/data/local/tmp/sysroot/usr/ndk/r27d/sysroot/usr/include -I/data/local/tmp/develop/sysroot/usr/include --sysroot=/data/local/tmp/sysroot/usr/ndk/r27d/sysroot
CXXFLAGS are now: -I/data/local/tmp/sysroot/usr/include -I/data/local/tmp/sysroot/usr/clang19/include -I/data/local/tmp/sysroot/usr/ndk/r27d/include -I/data/local/tmp/sysroot/usr/ndk/r27d/sysroot/usr/include/aarch64-linux-android -I/data/local/tmp/sysroot/usr/ndk/r27d/sysroot/usr/include -I/data/local/tmp/develop/sysroot/usr/include --sysroot=/data/local/tmp/sysroot/usr/ndk/r27d/sysroot
LDFLAGS are now: -L/data/local/tmp/sysroot/usr/lib -L/data/local/tmp/sysroot/usr/ndk/r27d/sysroot/usr/lib/aarch64-linux-android/31 -L/data/local/tmp/sysroot/usr/ndk/r27d/sysroot/usr/lib/aarch64-linux-android -L/data/local/tmp/develop/sysroot/usr/lib -B/data/local/tmp/sysroot/usr/ndk/r27d/sysroot/usr/lib/aarch64-linux-android/31/ --sysroot=/data/local/tmp/sysroot/usr/ndk/r27d/sysroot -lc
CC is now: /data/local/tmp/sysroot/usr/clang19/bin/clang
CXX is now: /data/local/tmp/sysroot/usr/clang19/bin/clang++
CPP is now: /data/local/tmp/sysroot/usr/clang19/bin/clang-cpp
CXXCPP is now: /data/local/tmp/sysroot/usr/clang19/bin/clang-cpp
AR is now: /data/local/tmp/sysroot/usr/clang19/bin/llvm-ar
AS is now: /data/local/tmp/sysroot/usr/clang19/bin/llvm-as
LD is now: /data/local/tmp/sysroot/usr/clang19/bin/lld
RANLIB is now: /data/local/tmp/sysroot/usr/clang19/bin/llvm-ranlib
STRIP is now: /data/local/tmp/sysroot/usr/clang19/bin/llvm-strip
PKG_CONFIG is now: /data/local/tmp/sysroot/usr/clang19/bin/pkg-config
PKG_CONFIG_PATH is now: :/data/local/tmp/sysroot/usr/lib/pkgconfig/:/data/local/tmp/develop/sysroot/usr/lib/pkgconfig/
Checking the clang binary ...
clang version 19.0.0git (https://android.googlesource.com/toolchain/llvm-project b3a530ec6537146650e42be89f1089e9a3588460)
Target: aarch64-unknown-linux-android
Thread model: posix
InstalledDir: /data/local/tmp/sysroot/usr/clang19/bin
Define some aliase ...
sysroot='cd /data/local/tmp/sysroot; pwd'
setlibpath='export LD_LIBRARY_PATH=:/data/local/tmp/sysroot/usr/lib:/data/local/tmp/sysroot/usr/ndk/r27d/sysroot/usr/lib/aarch64-linux-android:/data/local/tmp/sysroot/usr/clang19/lib'
addlib='LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/data/local/tmp/develop/sysroot/usr/lib '
vi=/data/local/tmp/sysroot/usr/bin/vi
find=/data/local/tmp/sysroot/usr/bin/find
tar=/data/local/tmp/sysroot/usr/bin/tar
bash=/data/local/tmp/sysroot/usr/bin/bash
sed=/data/local/tmp/sysroot/usr/bin/sed
awk=/data/local/tmp/sysroot/usr/bin/awk
dd=/data/local/tmp/sysroot/usr/bin/dd
nano=/data/local/tmp/sysroot/usr/bin/nano
curl=/data/local/tmp/sysroot/usr/bin/curl
Root access is enabled on this machine
Enabling hard links for the user "shell" ...
Enabling creating and using fifos for the user "shell" ...
Setting the variable "SSL_CERT_FILE" to "/data/local/tmp/sysroot/etc/security/ca-certificates.crt" ...
[clang19 toolchain] ASUS_I006D:/data/local/tmp/sysroot $
Now you can compile programs on the phone with clang or clang++ in an adb shell using the configure scripts from the source code of most Unix tools .
Note that init_clang19_env must be executed in every new adb session once before the toolchain can be used.
Use
sh /data/local/tmp/sysroot/bin/init_clang19_env help
[clang19 toolchain] ASUS_I006D:/data/local/tmp/sysroot $ date
Sun Sep 21 11:56:05 CEST 2025
[clang19 toolchain] ASUS_I006D:/data/local/tmp/sysroot $
[clang19 toolchain] ASUS_I006D:/data/local/tmp/sysroot $ source bin/init_clang19_env help
Usage: . /data/local/tmp/sysroot/bin/init_clang19_env [-h|--help] [init] [var=value] [examples] [nocpucheck]
init - clear the used enviroment variables at script start
var=value - set the environment variable "var" to "value" at start of the script
examples - print compile examples
nocpucheck - disable the CPU check
Supported environment variables are:
CHECK_CPU="${CHECK_CPU:=${__TRUE}}"
TMPDIR="${TMPDIR:=/data/local/tmp}"
CLANG_SYSROOT="${CLANG_SYSROOT:=/data/local/tmp/sysroot}"
TARGET_ROOT="${TARGET_ROOT:=/data/local/tmp/develop/sysroot}"
CLANG_VERSION="${CLANG_VERSION:=19}"
CLANG_DIR="${CLANG_DIR:=${CLANG_SYSROOT}/usr/clang${CLANG_VERSION}}"
NDK="${NDK:=r27d}"
NDK_DIR="${NDK_DIR:=${CLANG_SYSROOT}/usr/ndk/${NDK}}"
SYSROOT="${SYSROOT:=${NDK_DIR}/sysroot}"
API=${API:=31}
To use another toolchain base directory use this syntax:
CLANG_SYSROOT=/data/local/tmp/sysroot source ${CLANG_SYSROOT}/bin/init_clang19_env
[clang19 toolchain] ASUS_I006D:/data/local/tmp/sysroot $
The default API level configured in the init script is 31; this API version was introduced in Android 12 (-> the binaries created with this clang19 toolchain should work with Android 12 and newer versions)
(see https://source.android.com/docs/setup/reference/build-numbers for the list of supported API levels)
To use another API level use the syntax
source /data/local/tmp/sysroot/bin/init_clang19_env_help API=[API level]
Example:
source /data/local/tmp/sysroot/bin/init_clang19_env API=28
Note that some symbols that are standard in the libc of Linux are only defined in the libc of Android versions with newer API levels. To test in which libc version a symbol is defined, the executable nm can be used.
Example:
ASUS_I006D:/ # for i in /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/*/libc.so ; do echo "*** $i: "; nm $i | grep __fpending ; done
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/21/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/22/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/23/libc.so:
00000000000140c8 T __fpending
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/24/libc.so:
00000000000150c8 T __fpending
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/25/libc.so:
00000000000150c8 T __fpending
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/26/libc.so:
00000000000160c8 T __fpending
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/27/libc.so:
00000000000160c8 T __fpending
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/28/libc.so:
00000000000180c8 T __fpending
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/29/libc.so:
00000000000180c8 T __fpending
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/30/libc.so:
000000000001a0c8 T __fpending
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/31/libc.so:
000000000001a0c8 T __fpending
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/32/libc.so:
000000000001a0c8 T __fpending
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/33/libc.so:
000000000001a0c8 T __fpending
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/34/libc.so:
000000000001a0c8 T __fpending
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/35/libc.so:
000000000001a0c8 T __fpending
ASUS_I006D:/ #
-> the symbol __fpending is defined in the libc from API version 23 and newer.
ASUS_I006D:/data/local/tmp/develop/done/cpython314 $ ./python
CANNOT LINK EXECUTABLE "./python": cannot locate symbol "close_range" referenced by "/data/local/tmp/develop/done/cpython314/python"...
1|ASUS_I006D:/data/local/tmp/develop/done/cpython314 $
check the libc.so from Android for the missing symbol "close_range":
ASUS_I006D:/data/local/tmp/sysroot/home/shell # for i in /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/*/libc.so ; do echo "*** $i: "; nm $i | grep close_range ; done
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/21/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/22/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/23/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/24/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/25/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/26/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/27/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/28/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/29/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/30/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/31/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/32/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/33/libc.so:
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/34/libc.so:
000000000001cb50 T close_range
*** /data/local/tmp/sysroot/usr/ndk/r27b/sysroot/usr/lib/aarch64-linux-android/35/libc.so:
000000000001cb50 T close_range
ASUS_I006D:/data/local/tmp/sysroot/home/shell #
-> API 34 is Android 14 so this binary does not work on Android 13 or older versions.
The important directories in the tar file are:
| Directory | Content | Comment |
| /data/local/tmp/sysroot/bin | a few binaries and symbolic links for the tools | |
| /data/local/tmp/sysroot/usr/bin | binaries for the tools | |
| /data/local/tmp/sysroot/usr/lib | libraries for the tools | |
| /data/local/tmp/sysroot/usr/libexec | helper files and binaries for the tools | |
| /data/local/tmp/sysroot/etc | config files for the tools | |
| /data/local/tmp/sysroot/usr/include/ | some include files that might be used to compile the binaries | |
| /data/local/tmp/sysroot/usr/share | data files for the tools | |
| /data/local/tmp/sysroot/usr/ndk/#ndkversion# | #ndkversion# is the NDK version; as of 19.05.2025 the NDK versions in the tar archive are r27b and r27c | |
| /data/local/tmp/sysroot/usr/clang19/ | directory tree with the clang files | |
| /data/local/tmp/sysroot/usr/clang19/bin/ | directory with the binaries for clang | |
It's recommended to create another directory structure for the compiled binaries and libraries, e.g. :
/data/local/tmp/develop/sysroot/usr/
/data/local/tmp/develop/sysroot/usr/bin
/data/local/tmp/develop/sysroot/usr/lib
/data/local/tmp/develop/sysroot/usr/include
The init script /data/local/tmp/sysroot/bin/init_clang19_env adds the directories in
/data/local/tmp/develop/sysroot/usr
to the variables CFLAGS and LDFLAGS if they exist (see the script file for details)
The tar file also contains some simple C, C++, and assembler programs to test the compiler. Use the parameter ex or example for the script init_clang19_env to print the instructions to compile these sample files e.g.:
ASUS_I006D:/ $ source /data/local/tmp/sysroot/bin/init_clang19_env ex
The toolchain directory used is "/data/local/tmp/sysroot"
Running as user "shell"
Preparing the clang environment for creating binaries for the CPU type aarch64
...
To test the clang environment use
cd /data/local/tmp/sysroot
clang ${CFLAGS} ${LDFLAGS} -o helloworld_in_c helloworld_in_c.c && ./helloworld_in_c
To test the C++ compiler use
cd /data/local/tmp/sysroot
clang++ ${CPPFLAGS} ${LDFLAGS} -o helloworld_in_c++ ./helloworld_in_c++.cpp && ./helloworld_in_c++
To test the assembler from CLANG use
cd /data/local/tmp/sysroot
clang -nostdlib -static -Wl,--entry=_start -o helloworld_in_assembler helloworld_in_assembler.s && ./helloworld_in_assembler
To test the assembler from the binutils use
cd /data/local/tmp/sysroot
/data/local/tmp/sysroot/usr/bin/as -o helloworld_in_assembler_for_as.o helloworld_in_assembler_for_as.s && /data/local/tmp/sysroot//usr/bin/ld -o helloworld_in_assembler_for_as helloworld_in_assembler_for_as.o && ./helloworld_in_assembler_for_as
[clang19 toolchain] ASUS_I006D:/ $
[clang19 toolchain] [shell@localhost /]$ cd /data/local/tmp/sysroot
[clang19 toolchain] [shell@localhost /data/local/tmp/sysroot]$
[clang19 toolchain] [shell@localhost /data/local/tmp/sysroot]$ clang ${CFLAGS} ${LDFLAGS} -o helloworld_in_c helloworld_in_c.c && ./helloworld_in_c
Hello, World from a C program!
Compiled with Clang 19.0.0
[clang19 toolchain] [shell@localhost /data/local/tmp/sysroot]$
[clang19 toolchain] [shell@localhost /data/local/tmp/sysroot]$ clang++ ${CPPFLAGS} ${LDFLAGS} -o helloworld_in_c++ ./helloworld_in_c++.cpp && ./helloworld_in_c++
Hello, World from a C++ program!
Compiled with Clang 19.0.0
Compiler version: Clang 19.0.0git (https://android.googlesource.com/toolchain/llvm-project b3a530ec6537146650e42be89f1089e9a3588460)
[clang19 toolchain] [shell@localhost /data/local/tmp/sysroot]$
[clang19 toolchain] [shell@localhost /data/local/tmp/sysroot]$ clang -nostdlib -static -Wl,--entry=_start -o helloworld_in_assembler helloworld_in_assembler.s && ./helloworld_in_assembler
Hello, World from an assembler program compiled with clang!
[clang19 toolchain] [shell@localhost /data/local/tmp/sysroot]$
[clang19 toolchain] [shell@localhost /data/local/tmp/sysroot]$ /data/local/tmp/sysroot/usr/bin/as -o helloworld_in_assembler_for_as.o helloworld_in_assembler_for_as.s && /data/local/tmp/sysroot//usr/bin/ld -o helloworld_in_assembler_for_as helloworld_in_assembler_for_as.o && ./helloworld_in_assembler_for_as
Hello, World from an assembler program compiled with as and ld from the binutils!
[clang19 toolchain] [shell@localhost /data/local/tmp/sysroot]$
Notes
The binaries in the toolchain are tested in Android 13, Android 14, Android 15, and (partially) Android 16; they should also work in Android 12..
As of 21.09.2025, the tar file contains these program versions:
[clang19 toolchain] ASUS_I006D:/data/local/tmp/sysroot $ date
Sun Sep 21 11:49:19 CEST 2025
[clang19 toolchain] ASUS_I006D:/data/local/tmp/sysroot $
[clang19 toolchain] ASUS_I006D:/data/local/tmp/sysroot $ grep "^#" README | cut -c2-
The tools included in the tar file with the clang19 toolchain are:
clang 19.0.0
cmake 4.0.1
ninja 1.12.1 and 1.13.1
make 4.4.1
meson 1.7
binutils 2.44 (addr2line ar as c++filt elfedit gprof ld ld.bfd nm objcopy objdump ranlib readelf size strings strip)
autoconf 2.72
automake 1.17
m4 1.4.20
libtool 2.5.3
patch 2.8 (gnupatch)
patchelf 0.18
GNU help2man 1.49.3
pkg-config 0.29
pkgconf 2.30
autopoint 0.23
texinfo 7.2
bash 5.2.37
bison 3.8
flex 2.6.4
gdb 16.3 (dynamically and statically linked binaries)
rsync 3.4.1
wget 2.1.0
curl 8.13.0
perl 5.40
python 3.14
pip 25.0.1
tcl 9.0
sqlite3 3.50.1
sshd/ssh 10.0p2
git 2.49
gpg 1.4.3
dig 9.11.37
nano 8.6 and nano 6.4
vim 9.1-672
ed 1.21
bvi /bmore 1.5.0
man 2.13
tmux 3.5a
tar 1.35
dd 9.5.58
jq 1.7.1
gawk 5.3.2
grep 3.12
gsed 4.9
diff 3.11
bc 1.08.2
less 679
htop 3.4.1
btop 1.4.4 (btop needs root access)
Android SDK build tools 35.0.2 (aidl zipalign aapt aapt2 dexdump split-select e2fsdroid sqlite3 fastboot sload_f2fs hprof-conv etc1tool mke2fs make_f2fs adb make_f2fs_casefold veridex)
( the binaries are from this ZIP file: https://github.com/lzhiyong/android-sdk-tools/releases/download/35.0.2/android-sdk-tools-static-aarch64.zip )
OpenVPN 2.7 (openvpn requires root access)
unfsd 0.11.0 (a userland NFS daemon usable by non-root user; the default exports file for this binary is /data/local/tmp/sysroot/etc/exports)
protoc v32.1.0 (currently the binary only)
various compression tools:
7zz 25.00
bzip2 1.0.8
zip 3.0
unzip 5.52
lz4 v1.10.0
lzop 1.04
compress 5.0
uncompress 5.0
zstd 1.5.6
pigz 2.8
xz 5.8.1
gunzip 1.13
gzip 1.13
unrar 5.91
lzip 1.25
[clang19 toolchain] ASUS_I006D:/data/local/tmp/sysroot $
The include file sysroot/usr/include/add_missing_definitions.h contains dummy definitions for common functions and definitions from Linux that are not available in Android.
The file is also available here: add_missing_definitions.h
To use the file, add the statement
#include <add_missing_definitions.h>
to the source file.
As of 21.05.2025 the include files add these symbols:
// Please note that you must remove the definitions for functions that already exist in the source code from this include file.
// If not, error messages like this are displayed when compiling your source code:
//
// command.c:(.text+0x348): multiple definition of `catclose'
// array.o:array.c:(.text+0x348): first defined here
//
// Therefore, either edit this file before using it or copy only the necessary parts to your source files
// This file defines
// __GNUC_PREREQ
// quad_t
// u_quad_t
// short
//
// This file defines the functions
// strverscmp
// versionsort
// getdtablesize
// index
// rindex
// catopen
// catgets
// catclose
// nl_langinfo
// getpwent
// endpwent
// CloseSocket
//
The file is also available here: add_missing_definitions.h
The dummy library sysroot/usr/lib/libmylib.so can be used to create libraries that are needed in the Makefile of a tool but are not necessary in Android (like libpthread.so).
Simply create a symbolic link for the missing library to libmylib.so, e.g.
cd /datda/local/tmp/sysroot/usr/lib
ln -s ./libmylib.so ./libptrhead.so
The file is also available here: libmylib.so
wget2, curl, and git from the tar file use the certificates from the bundle file /data/local/tmp/sysroot/etc/security/ca-certificates.crt. This file is created by the script create_clang_env.sh with all certificates found in /system/etc/security/cacerts.
If git complains about an invalid SSL certificate, like this
ASUS_I006D:/data/local/tmp/develop/test $ git clone https://github.com/git/git
Cloning into 'git'...
fatal: unable to access 'https://github.com/git/git/': SSL peer certificate or SSH remote key was not OK
128|ASUS_I006D:/data/local/tmp/develop/test $
git_no_ssl_verify
(see https://git-scm.com/book/be/v2/Git-Internals-Environment-Variables for other environment variables used by git)
In case of an error when executing a self compiled binary, I recommend to create a binary with debug infos and execute the binary from within the GNU debugger gdb, which is part of the toolchain
(see https://www.sourceware.org/gdb/ for details about the GNU debugger)
To create a binary with debugging infos use the compiler switches "-g -O0" and do not use the linker switch "-s"
If there is no gzip on the phone to unpack the tar file, download the gzip binary from here.
The tar file contains also the OpenSSH binaries and scripts as described in this HowTo: How to connect to Android via ssh as user shell without root access
see these posts and HowTos for examples using the clang19 toolchain:
How to compile jq in Android using the clang19 toolchain
How to compile nano in Android with the clang19 toolchain on the phone
How to compile Perl in Android with the clang19 toolchain on the phone
How to compile bash in Android with the clang19 toolchain on the phone
How to compile Python in Android with the clang19 toolchain on the phone
see also Troubleshooting some common problems for compiling programs for Android for how to fix some common problems compiling binaries for Android
TroubleShooting
An error like this
[clang19 toolchain] [shell@localhost /]$ /data/local/tmp/sysroot/usr/clang19/bin/clang-19
CANNOT LINK EXECUTABLE "/data/local/tmp/sysroot/usr/clang19/bin/clang-19": cannot locate symbol "_ZTTNSt6__ndk114basic_ifstreamIcNS_11char_traitsIcEEEE" referenced by "/data/local/tmp/sysroot/usr/clang19/lib/libclang-cpp.so"...
[clang19 toolchain] [shell@localhost /]$
is caused by an incompatible libc++_shared.so on the phone, e.g.:
[clang19 toolchain] [shell@localhost /]$ ldd /data/local/tmp/sysroot/usr/clang19/bin/clang-19 | grep libc++_shared.so
libc++_shared.so => /system/lib64/libc++_shared.so (0x7bf528a000)
[clang19 toolchain] [shell@localhost /]$
To fix the error, change the LD_LIBRARY_PATH so that the libc++_shared.so is used by clang, e.g.:
[clang19 toolchain] TB351FU:/ $ ldd /data/local/tmp/sysroot/usr/clang19/bin/clang-19 | grep libc++_shared.so
libc++_shared.so => /data/local/tmp/sysroot/usr/lib/libc++_shared.so (0x7a9b687000)
[clang19 toolchain] TB351FU:/ $
The toolchain can also be used in an ssh session to the phone (the sshd binary is part of the tar file with the toolchain).
The toolchain can also be used in adb sessions connected via WiFi -- see the section How to enable adb via WiFi with a fixed TCP port for instructions to enable adb via WiFi with a fixed TCP port.
see the post How to install clang20 on phones without root access for the documentation for an additional tar archive with clang20.
A git repository with libraries and include files that can be used to create executables with the clang19 toolchain in Android is available on github:
https://github.com/bnsmb/libraries-and-include-files-for-Android-on-arm64-CPUs/
To use the files from that repository with the clang19 toolchain, download the repository to the phone
cd /data/local/tmp/
git clone https://github.com/bnsmb/libraries-and-include-files-for-Android-on-arm64-CPUs.git
and move the sysroot directory from the repository to the directory /data/local/tmp/develop before initializing the clang19 toolchain.
Update 11.07.2025
See these posts for how to use overlay mounts to install a clang19 toolchain (Note: to use overlay mounts root access is required)
Using a virtual disk with a clang19 toolchain for an overlay mount
Using a virtual disk with Perl 5.42 and a minimal clang19 toolchain for an overlay mount
Update 22.10.2025
see Using a virtual disk with a clang21 toolchain and Android NDK r29 for an overlay mount for the documentation for a virtual disk with clang21 and the Android NDK r29 (Note: the approach used in this guide needs root acces)
added links to examples for using the clang19 toolchain
25.01.2025
added the info about the git repository with libraries and include files for Android
24.03.2025
updated the docoumentation to match the release v1.2.0 23.03.2025
21.05.2025
updated the docoumentation to match the release v1.3.0 21.05.2025
11.07.2025
added the links to the post with infos about using overlay mounts
21.07.2025
updated the docoumentation to match the release v1.4.0 21.07.2025
21.09.2025
updated the docoumentation to match the release v1.5.0 21.09.2025
28.10.2025
Updated the link to the instructions to compile Perl using the clang19 toolchain
added the Trouble Shooting section