File | Date | Author | Commit |
---|---|---|---|
.github | 2023-01-01 |
![]() |
[65bf9f] Initial commit |
patches | 2023-01-01 |
![]() |
[65bf9f] Initial commit |
submodules | 2023-01-01 |
![]() |
[65bf9f] Initial commit |
tools | 2023-01-01 |
![]() |
[65bf9f] Initial commit |
.editorconfig | 2023-01-01 |
![]() |
[65bf9f] Initial commit |
.gitattributes | 2023-01-01 |
![]() |
[65bf9f] Initial commit |
.gitmodules | 2023-01-01 |
![]() |
[65bf9f] Initial commit |
LICENSE | 2023-01-01 |
![]() |
[65bf9f] Initial commit |
README.md | 2023-01-01 |
![]() |
[65bf9f] Initial commit |
build.sh | 2023-01-01 |
![]() |
[65bf9f] Initial commit |
A GCC cross-compiler targeting Android.
This version of GCC uses the patchset from the TUR port of GCC for Android, with additional patches to improve cross-compilation and enable its usage in Gradle projects as a replacement for Clang.
Using Pino in Gradle projects is a bit tricky. Both CMake and ndk-build are heavily tied to the NDK's internal structure, which makes it difficult to completely replace Clang with GCC without risking breaking something in the build process.
For this to work, you will need to have both Pino (GCC) and Google's NDK (Clang) installed.
First, ensure that the NDK (Clang) is already installed. If you are using ndk-build or CMake with Gradle and have built your project at least once on your machine, it is very likely that the NDK is already installed. If you're unsure, go to the root directory of your project and run ./gradlew clean
:
$ ./gradlew clean
Starting a Gradle Daemon (subsequent builds will be faster)
> Configure project :
Checking the license for package NDK (Side by side) 25.1.8937393 in /home/ubuntu/sdk/licenses
License for package NDK (Side by side) 25.1.8937393 accepted.
Preparing "Install NDK (Side by side) 25.1.8937393 v.25.1.8937393".
"Install NDK (Side by side) 25.1.8937393 v.25.1.8937393" ready.
Installing NDK (Side by side) 25.1.8937393 in /home/ubuntu/sdk/ndk/25.1.8937393
"Install NDK (Side by side) 25.1.8937393 v.25.1.8937393" complete.
"Install NDK (Side by side) 25.1.8937393 v.25.1.8937393" finished.
> Task :externalNativeBuildCleanDebug
> Task :externalNativeBuildCleanRelease
> Task :clean UP-TO-DATE
BUILD SUCCESSFUL in 44s
3 actionable tasks: 2 executed, 1 up-to-date
If you see messages like Install NDK [...]
after running the above command, then Gradle just installed the NDK for you. If you don't see any messages like this, then either the NDK is already installed or the project you are trying to compile is not using the NDK at all.
[!NOTE]
It might happen that the project is not using the NDK directly, but instead through some other build system that is not CMake or ndk-build. In that case, you will need to figure out how to use Pino with those third-party setups on your own.
Pino provides a utility tool named ndk-patch
that can be used to patch the NDK so that Gradle picks up our GCC toolchain instead of Clang. Running it will output something like this:
$ ./pino/bin/ndk-patch
- Symlinking /home/runner/pino/bin/clang to /usr/local/lib/android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
- Symlinking /home/runner/pino/bin/clang++ to /usr/local/lib/android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++
- Removing /usr/local/lib/android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so
- Removing /usr/local/lib/android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/i686-linux-android/libc++_shared.so
- Removing /usr/local/lib/android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/libc++_shared.so
- Removing /usr/local/lib/android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so
+ Done
Essentially, it overrides the NDK's clang
/clang++
commands with alternatives that call gcc
/g++
instead. It also deletes the NDK's built-in libc++ shared libraries to prevent the Android Gradle plugin from automatically bundling them into the APK when using -ANDROID_STL=c++_shared
.
After patching the NDK, you are almost ready to go and compile the project. Just run ./gradlew clean
before compiling it to make sure compiled objects from previous builds (Clang) don't interfere with the new build.
Changing the build workflow further (i.e., Gradle, CMake, ndk-build) is usually not required unless your project relies on features that are not available on GCC (e.g., using Clang-specific compiler/linker flags or features), which might cause build errors.
ANDROID_STL=c++_static
will also have no effect.The Clang NDK provides a single, unified CMake toolchain for cross-compilation, typically located at <ndk_prefix>/build/cmake/android.toolchain.cmake
. However, we are following a different approach: instead of using a unified toolchain for all targets, we provide a separate toolchain for each architecture/API level supported by the NDK. These toolchains can be found in <pino_prefix>/usr/local/share/pino/cmake
:
$ ls <pino_prefix>/usr/local/share/pino/cmake
aarch64-unknown-linux-android.cmake
aarch64-unknown-linux-android21.cmake
aarch64-unknown-linux-android22.cmake
...
arm-unknown-linux-androideabi.cmake
arm-unknown-linux-androideabi21.cmake
arm-unknown-linux-androideabi22.cmake
...
i686-unknown-linux-android.cmake
i686-unknown-linux-android21.cmake
i686-unknown-linux-android22.cmake
...
riscv64-unknown-linux-android.cmake
riscv64-unknown-linux-android35.cmake
...
x86_64-unknown-linux-android.cmake
x86_64-unknown-linux-android21.cmake
x86_64-unknown-linux-android22.cmake
So, instead of configuring your project like this...
$ cmake \
-DCMAKE_TOOLCHAIN_FILE='<ndk_prefix>/build/cmake/android.toolchain.cmake' \
-DANDROID_ABI='armeabi-v7a' \
-DANDROID_PLATFORM='android-24' \
...
...do this instead:
$ cmake \
-DCMAKE_TOOLCHAIN_FILE='<pino_prefix>/usr/local/share/pino/cmake/arm-unknown-linux-androideabi24.cmake' \
...
For convenience, Pino also provides helper scripts that can be used to set up an environment suitable for cross-compiling projects based on Autotools and similar tools. These scripts can be found in <pino_prefix>/usr/local/share/pino/autotools
:
$ ls <pino_prefix>/usr/local/share/pino/autotools
aarch64-unknown-linux-android.sh
aarch64-unknown-linux-android21.sh
aarch64-unknown-linux-android22.sh
...
arm-unknown-linux-androideabi.sh
arm-unknown-linux-androideabi21.sh
arm-unknown-linux-androideabi22.sh
...
i686-unknown-linux-android.sh
i686-unknown-linux-android21.sh
i686-unknown-linux-android22.sh
...
riscv64-unknown-linux-android.sh
riscv64-unknown-linux-android35.sh
...
x86_64-unknown-linux-android.sh
x86_64-unknown-linux-android21.sh
x86_64-unknown-linux-android22.sh
They are meant to be source
d by you whenever you want to cross-compile a project:
# Set up the environment for cross-compilation
$ source <pino_prefix>/usr/local/share/pino/autotools/aarch64-unknown-linux-android21.sh
# Configure & build the project
$ ./configure --host="${CROSS_COMPILE_TRIPLET}"
$ make
Pino includes a portable APT-like package manager that works with APT repositories. You can use it to install additional third-party libraries from the Termux repository and use them during cross-compilation.
You can install packages to a specific system root using the corresponding <triplet><api_level>-nz
command inside the <pino_prefix>/bin
directory:
# Install zlib and zstd
$ aarch64-unknown-linux-android21-nz \
--install 'zlib;zstd'
There is also an apt
script wrapper around nz
that allows you to install packages using the familiar apt install
syntax:
# Install zlib and zstd
$ aarch64-unknown-linux-android21-apt install \
zlib \
zstd
To enable Pino to use libraries from nz's system root during the build, set the PINO_NZ
environment variable:
$ export PINO_NZ=1
The current release is based on GCC 15 and supports cross-compiling software to all major Android architectures (arm
, arm64
, x86
, and x86_64
). There is also experimental support for the riscv64
architecture.
You can obtain releases from the releases page.