Tydus / howto-standalone-toolchain.md
NDK (Native Develop Toolkit) is a toolchain from Android official, originally for users who writes native C/C++ code as JNI library. It’s not designed for compiling standalone programs (./a.out) and not compatible with automake/cmake etc.
What is Standalone Toolchain
«Standalone» refers to two meanings:
- The program is standalone (has nothing connect to NDK, and don’t need helper scripts to run it)
- The toolchain is made for building standalone programs and libs, and which can used by automake etc.
(Optional) Why NDK is hard to use
By default, NDK uses android flavor directory structure when it’s finding headers and libs, which is different from GNU flavor, so the compiler cannot find them. For Example:
/home/tyeken8/Desktop/elab/geo/android-ndk-r9d/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.8/../../../../arm-linux-androideabi/bin/ld: error: cannot open crtbegin_dynamic.o: No such file or directory /home/tyeken8/Desktop/elab/geo/android-ndk-r9d/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.8/../../../../arm-linux-androideabi/bin/ld: error: cannot open crtend_android.o: No such file or directory /home/tyeken8/Desktop/elab/geo/android-ndk-r9d/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.8/../../../../arm-linux-androideabi/bin/ld: error: cannot find -lc /home/tyeken8/Desktop/elab/geo/android-ndk-r9d/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.8/../../../../arm-linux-androideabi/bin/ld: error: cannot find -ldl collect2: error: ld returned 1 exit status
Although we can manuall specify the path (someone wrote a program called «agcc» to handle this automatically, but still not good), it’s really annoying.
- Download Android NDK
from https://developer.android.com/tools/sdk/ndk/index.html - Extract the NDK
tar xf android-ndk-r9d-*.tar.bz2 && cd android-ndk-r9d - Make GNU Android Toolchain from NDK
build/tools/make-standalone-toolchain.sh —toolchain=arm-linux-androideabi-4.8 —platform=android-19 —install-dir=../toolchain - Delete the NDK (Yes, we don’t need it any more)
cd .. && rm -rf android-ndk-r9d - Test the native toolchain
cd toolchain/bin
echo «main()<>» | ./arm-linux-androideabi-gcc -x c —
file a.out # a.out: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped - (Optional) Now you can use it as a standard GNU toolchain
For example: ./configure —prefix=/opt/android —host=arm-linux-androideabi && make && make install
[Android NDK]Toolchains of LLVM and GCC
LLVM is an umbrela project now, and it contains multiple modular and reusable compiler and toolchain technologies. You can check more details at The LLVM Compiler Infrastructure.
For Android NDK, llvm became the default toolchain since r13b and gcc was removed since r18b.
According to toolchains directory toolchains/llvm/prebuilt/darwin-x86_64 , llvm supports all the ABIs, i.e. x86, x86_64, arm, arm64.
Probably there will be only one llvm directory under toolchains directory in future NDK releases when all the gcc related tools, headers and libs are completely ported to llvm.
Updates
Just did a quick test on different NDK revisions to check the configurations for —gcc-toolchain and —sysroot which are for cross compilation.
On r16b
--target=armv7-none-linux-androideabi --gcc-toolchain=~/ndks/android-ndk-r16b/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64 --sysroot=~/ndks/android-ndk-r16b/sysroot
On r17c
--target=armv7-none-linux-androideabi --gcc-toolchain=~/ndks/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64 --sysroot=~/ndks/android-ndk-r17c/sysroot
On r18b
--target=armv7-none-linux-androideabi19 --gcc-toolchain=~/ndks/android-ndk-r18b/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64 --sysroot=~/ndks/android-ndk-r18b/sysroot
On r19b
--target=armv7-none-linux-androideabi19 --gcc-toolchain=~/ndks/android-ndk-r19b/toolchains/llvm/prebuilt/darwin-x86_64 --sysroot=~/ndks/android-ndk-r19b/toolchains/llvm/prebuilt/darwin-x86_64/sysroot
As seen above, before NDK r19b, NDK uses clang compiler but the —gcc-toolchain and —sysroot are configured as the older paths for build tools, headers and libs.
But, since NDK r19b, the —gcc-toolchain and —sysroot are configured as the new tool chains llvm, i.e. toolchains/llvm/prebuilt/darwin-x86_64 , and the tools (e.g. ranlib, ar, strip, etc) header files and libraries of “llvm version” will be used.
Also, note that toolchains/llvm/prebuilt/darwin-x86_64 contains the support for all the Android ABIs, i.e. aarch64-linux-android for arm64-v8a, arm-linux-androideabi for armeabi-v7a, i686-linux-android for x86, x86_64-linux-android for x86_64.
So, you can try out the NDK r19b if you want to purely use llvm toolchains.
How to install Android NDK on Ubuntu Linux ?
The Android NDK is a toolset that lets you implement parts of your app in native code, using languages such as C and C++. For certain types of apps, this can help you reuse code libraries written in those languages.
To install and configure the NDK, follow these steps:
Download android ndk Linux 64 bit from http://developer.android.com/ndk/downloads/index.html , when we written this post, the latest Android version is R23B, which we downloaded and copied to /home/myuser/Android directory. Now, Lets extract this zip as,
$ unzip android-ndk-r23b-linux.zip
This will extract as “Extracting android-ndk-r23b” into folder “android-ndk-r23b” in ~/Android directory. When uncompressed, the NDK files are contained in a directory called android-ndk- . You can rename the NDK directory if necessary and you can move it to any location on your computer.
Export the NDK path into environment variables,
$ export PATH=$PATH:/home/myuser/Android/android-ndk-r23b
OR You can also edit your ~/.bashrc file and append above line to add NDK permanently to your path to avoid typing above command always.
Check if ndk-build is added to environment,
$ which ndk-build /home/myuser/Android/android-ndk-r23b/ndk-build
Sometimes, you may need to set NDK_HOME evnvironment variable which you can do the same way as above,
$ export NDK_HOME=/home/myuser/Android/android-ndk-r23b
Cross compiling C/C++ programs for Android using NDK Toolchains
If you are using NDK version more than r19, the toolchains which comes as part of NDK zip can be used and we no longer need to generate toolchain using script make-standalone-toolchain.sh for versions before r19. Below post will describe how we can compile native C/C++ programs using NDK.
The first step is to make sure you have installed NDK by following our article at “How to install Android NDK on Ubuntu 16.04 / 18.04” By the time of writing this article Android NDK version was r20, so below section of compiling C programs for Android using NDK version more than r19 is most suitable for you.
Compiling C/C++ programs for Android using NDK version more than r19
Lets write a simple helloworld program as,
#include int main(int argc, char **argv)
Assuming you have installed Android NDK at /home/myuser/android_ndk/android-ndk-r20/ [Your version might be more than r20] , export the toolchain path as below,
$ export PATH=$PATH:/home/myuser/android_ndk/android-ndk-r20/toolchains/llvm/prebuilt/linux-x86_64/bin
Now, connect your device using adb and verify what is the processor type using adb command as,
$ adb shell cat /proc/cpuinfo | grep Processor Processor : AArch64 Processor rev 4 (aarch64)
As you can see above, our Android device is 64 bit ARM processor, hence we will use related clang command as below,
$ aarch64-linux-android29-clang -o helloworld helloworld.c
$ file helloworld helloworld: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /system/, not stripped
Now, you can push this executable helloworld to your Android device for verifying the result.
Compiling C/C++ programs for Android using NDK less than r19
For NDK versions below r19, we have to generate the toolchain using make-standalone-toolchain.sh script as,
$ bash ./android_ndk/android-ndk-r20/build/tools/make-standalone-toolchain.sh --arch=arm64 --install-dir=./android_toolchain/ HOST_OS=linux HOST_EXE= HOST_ARCH=x86_64 HOST_TAG=linux-x86_64 HOST_NUM_CPUS=8 BUILD_NUM_CPUS=16 Toolchain installed to ./android_toolchain/.
As you can see above, make-standalone-toolchain.sh script generates the toolchain at android_toolchain directory present in your current working directory. The tools required to compile C/C++ programs resides in android_toolchain/bin/ directory and we can export the path same as we did above,
$ export PATH=$PATH:/home/myuser/android_toolchain/bin/
Now, you can compile the C program as,
$ aarch64-linux-android29-clang -o helloworld helloworld.c