Add scripts & docs which support creating an Android toolchain on Linux (dotnet/corec...
authorFrederik Carlier <frederik.carlier@quamotion.mobi>
Tue, 7 Feb 2017 18:19:31 +0000 (19:19 +0100)
committerJan Vorlicek <janvorli@microsoft.com>
Tue, 7 Feb 2017 18:19:31 +0000 (19:19 +0100)
* Add scripts & docs which support creating an Android toolchain on Linux

Commit migrated from https://github.com/dotnet/coreclr/commit/05ec3cea1f58eec67f85de09e8869e9239e6c94d

docs/coreclr/building/android.md [new file with mode: 0644]
src/coreclr/cross/build-android-rootfs.sh [new file with mode: 0755]

diff --git a/docs/coreclr/building/android.md b/docs/coreclr/building/android.md
new file mode 100644 (file)
index 0000000..cfb509d
--- /dev/null
@@ -0,0 +1,102 @@
+Cross Compilation for Android on Linux
+======================================
+
+Through cross compilation, on Linux it is possible to build CoreCLR for arm64 Android.
+
+Requirements
+------------
+
+You'll need to generate a toolchain and a sysroot for Android. There's a script which takes care of the required steps.
+
+Generating the rootfs
+---------------------
+
+To generate the rootfs, run the following command in the `coreclr` folder:
+
+```
+cross/init-android-rootfs.sh
+```
+
+This will download the NDK and any packages required to compile Android on your system. It's over 1 GB of data, so it may take a while.
+
+
+Cross compiling CoreCLR
+-----------------------
+Once the rootfs has been generated, it will be possible to cross compile CoreCLR. 
+
+When cross compiling, you need to set both the `CONFIG_DIR` and `ROOTFS_DIR` variables.
+
+To compile for arm64, run:
+
+```
+CONFIG_DIR=`realpath cross/android/arm64` ROOTFS_DIR=`realpath cross/android-rootfs/toolchain/arm64/sysroot` ./build.sh cross arm64 skipgenerateversion skipmscorlib cmakeargs -DENABLE_LLDBPLUGIN=0
+```
+
+The resulting binaries will be found in `bin/Product/Linux.BuildArch.BuildType/`
+
+Running the PAL tests on Android
+--------------------------------
+
+You can run the PAL tests on an Android device. To run the tests, you first copy the PAL tests to your Android phone using
+`adb`, and then run them in an interactive Android shell using `adb shell`:
+
+To copy the PAL tests over to an Android phone:
+```
+adb push bin/obj/Linux.arm64.Debug/src/pal/tests/palsuite/ /data/local/tmp/coreclr/src/pal/tests/palsuite
+adb push cross/android/toolchain/arm64/sysroot/usr/lib/libuuid.so.1 /data/local/tmp/coreclr/lib
+adb push cross/android/toolchain/arm64/sysroot/usr/lib/libintl.so /data/local/tmp/coreclr/lib
+adb push cross/android/toolchain/arm64/sysroot/usr/lib/libandroid-support.so /data/local/tmp/coreclr/lib/
+adb push cross/android/toolchain/arm64/sysroot/usr/lib/libandroid-glob.so /data/local/tmp/coreclr/lib/
+adb push src/pal/tests/palsuite/paltestlist.txt /data/local/tmp/coreclr
+adb push src/pal/tests/palsuite/runpaltests.sh /data/local/tmp/coreclr/
+```
+
+Then, use `adb shell` to launch a shell on Android. Inside that shell, you can launch the PAL tests:
+```
+LD_LIBRARY_PATH=/data/local/tmp/coreclr/lib ./runpaltests.sh /data/local/tmp/coreclr/
+```
+
+Debugging coreclr on Android
+----------------------------
+
+You can debug coreclr on Android using a remote lldb server which you run on your Android device.
+
+First, push the lldb server to Android:
+
+```
+adb push cross/android/lldb/2.2/android/arm64-v8a/lldb-server /data/local/tmp/
+```
+
+Then, launch the lldb server on the Android device. Open a shell using `adb shell` and run:
+
+```
+adb shell
+cd /data/local/tmp
+./lldb-server platform --listen *:1234
+```
+
+After that, you'll need to forward port 1234 from your Android device to your PC:
+```
+adb forward tcp:1234 tcp:1234
+```
+
+Finally, install lldb on your PC and connect to the debug server running on your Android device:
+
+```
+lldb-3.9
+(lldb) platform select remote-android
+  Platform: remote-android
+ Connected: no
+(lldb) platform connect connect://localhost:1234
+  Platform: remote-android
+    Triple: aarch64-*-linux-android
+OS Version: 23.0.0 (3.10.84-perf-gf38969a)
+    Kernel: #1 SMP PREEMPT Fri Sep 16 11:29:29 2016
+  Hostname: localhost
+ Connected: yes
+WorkingDir: /data/local/tmp
+
+(lldb) target create coreclr/pal/tests/palsuite/file_io/CopyFileA/test4/paltest_copyfilea_test4
+(lldb) env LD_LIBRARY_PATH=/data/local/tmp/coreclr/lib
+(lldb) run
+```
diff --git a/src/coreclr/cross/build-android-rootfs.sh b/src/coreclr/cross/build-android-rootfs.sh
new file mode 100755 (executable)
index 0000000..7627294
--- /dev/null
@@ -0,0 +1,145 @@
+#!/usr/bin/env bash
+
+usage()
+{
+    echo "Creates a toolchain and sysroot used for cross-compiling for Android."
+    echo.
+    echo "Usage: $0 [BuildArch] [ApiLevel]"
+    echo.
+    echo "BuildArch is the target architecture of Android. Currently only arm64 is supported."
+    echo "ApiLevel is the target Android API level. API levels usually match to Android releases. See https://source.android.com/source/build-numbers.html"
+    echo.
+    echo "By default, the toolchain and sysroot will be generated in cross/android-rootfs/toolchain/[BuildArch]. You can change this behavior"
+    echo "by setting the TOOLCHAIN_DIR environment variable"
+    echo.
+    echo "By default, the NDK will be downloaded into the cross/android-rootfs/android-ndk-r13b directory. If you already have an NDK installation,"
+    echo "you can set the NDK_DIR environment variable to have this script use that installation of the NDK."
+    exit 1
+}
+
+__ApiLevel=21 # The minimum platform for arm64 is API level 21
+__BuildArch=arm64
+__AndroidArch=aarch64
+
+for i in "$@"
+    do
+        lowerI="$(echo $i | awk '{print tolower($0)}')"
+        case $lowerI in
+        -?|-h|--help)
+            usage
+            exit 1
+            ;;
+        arm64)
+            __BuildArch=arm64
+            __AndroidArch=aarch64
+            ;;
+        *[0-9])
+            __ApiLevel=$i
+            ;;
+        *)
+            __UnprocessedBuildArgs="$__UnprocessedBuildArgs $i"
+            ;;
+    esac
+done
+
+# Obtain the location of the bash script to figure out where the root of the repo is.
+__CrossDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+__Android_Cross_Dir="$__CrossDir/android-rootfs"
+__NDK_Dir="$__Android_Cross_Dir/android-ndk-r13b"
+__libunwind_Dir="$__Android_Cross_Dir/libunwind"
+__lldb_Dir="$__Android_Cross_Dir/lldb"
+__ToolchainDir="$__Android_Cross_Dir/toolchain/$__BuildArch"
+
+if [[ -n "$TOOLCHAIN_DIR" ]]; then
+    __ToolchainDir=$TOOLCHAIN_DIR
+fi
+
+if [[ -n "$NDK_DIR" ]]; then
+    __NDK_Dir=$NDK_DIR
+fi
+
+echo "Target API level: $__ApiLevel"
+echo "Target architecture: $__BuildArch"
+echo "NDK location: $__NDK_Dir"
+echo "Target Toolchain location: $__ToolchainDir"
+
+# Download the NDK if required
+if [ ! -d $__NDK_Dir ]; then
+    echo Downloading the NDK into $__NDK_Dir
+    mkdir -p $__NDK_Dir
+    wget -nv -nc --show-progress https://dl.google.com/android/repository/android-ndk-r13b-linux-x86_64.zip -O $__Android_Cross_Dir/android-ndk-r13b-linux-x86_64.zip
+    unzip -q $__Android_Cross_Dir/android-ndk-r13b-linux-x86_64.zip -d $__Android_Cross_Dir
+fi
+
+if [ ! -d $__lldb_Dir ]; then
+    mkdir -p $__lldb_Dir
+    echo Downloading LLDB into $__lldb_Dir
+    wget -nv -nc --show-progress https://dl.google.com/android/repository/lldb-2.3.3614996-linux-x86_64.zip -O $__Android_Cross_Dir/lldb-2.3.3614996-linux-x86_64.zip
+    unzip -q $__Android_Cross_Dir/lldb-2.3.3614996-linux-x86_64.zip -d $__lldb_Dir
+fi
+
+# Create the RootFS for both arm64 as well as aarch
+rm -rf $__Android_Cross_Dir/toolchain
+
+echo Generating the $__BuildArch toolchain
+$__NDK_Dir/build/tools/make_standalone_toolchain.py --arch $__BuildArch --api $__ApiLevel --install-dir $__ToolchainDir
+
+# Install the required packages into the toolchain
+rm -rf $__Android_Cross_Dir/deb/
+rm -rf $__Android_Cross_Dir/tmp
+
+mkdir -p $__Android_Cross_Dir/deb/
+mkdir -p $__Android_Cross_Dir/tmp/$arch/
+wget -nv -nc http://termux.net/dists/stable/main/binary-$__AndroidArch/libicu_58.2_$__AndroidArch.deb -O $__Android_Cross_Dir/deb/libicu_58.2_$__AndroidArch.deb
+wget -nv -nc http://termux.net/dists/stable/main/binary-$__AndroidArch/libicu-dev_58.2_$__AndroidArch.deb -O $__Android_Cross_Dir/deb/libicu-dev_58.2_$__AndroidArch.deb
+wget -nv -nc http://termux.net/dists/stable/main/binary-$__AndroidArch/libuuid-dev_1.0.3_$__AndroidArch.deb -O $__Android_Cross_Dir/deb/libuuid-dev_1.0.3_$__AndroidArch.deb
+wget -nv -nc http://termux.net/dists/stable/main/binary-$__AndroidArch/libuuid_1.0.3_$__AndroidArch.deb -O $__Android_Cross_Dir/deb/libuuid_1.0.3_$__AndroidArch.deb
+wget -nv -nc http://termux.net/dists/stable/main/binary-$__AndroidArch/libandroid-glob-dev_0.3_$__AndroidArch.deb -O $__Android_Cross_Dir/deb/libandroid-glob-dev_0.3_$__AndroidArch.deb
+wget -nv -nc http://termux.net/dists/stable/main/binary-$__AndroidArch/libandroid-glob_0.3_$__AndroidArch.deb -O $__Android_Cross_Dir/deb/libandroid-glob_0.3_$__AndroidArch.deb
+wget -nv -nc http://termux.net/dists/stable/main/binary-$__AndroidArch/libandroid-support-dev_13.10_$__AndroidArch.deb -O $__Android_Cross_Dir/deb/libandroid-support-dev_13.10_$__AndroidArch.deb
+wget -nv -nc http://termux.net/dists/stable/main/binary-$__AndroidArch/libandroid-support_13.10_$__AndroidArch.deb -O $__Android_Cross_Dir/deb/libandroid-support_13.10_$__AndroidArch.deb
+wget -nv -nc http://termux.net/dists/stable/main/binary-$__AndroidArch/liblzma-dev_5.2.3_$__AndroidArch.deb  -O $__Android_Cross_Dir/deb/liblzma-dev_5.2.3_$__AndroidArch.deb
+wget -nv -nc http://termux.net/dists/stable/main/binary-$__AndroidArch/liblzma_5.2.3_$__AndroidArch.deb -O $__Android_Cross_Dir/deb/liblzma_5.2.3_$__AndroidArch.deb
+wget -nv -nc http://termux.net/dists/stable/main/binary-$__AndroidArch/libcurl-dev_7.52.1_$__AndroidArch.deb -O $__Android_Cross_Dir/deb/libcurl-dev_7.52.1_$__AndroidArch.deb
+wget -nv -nc http://termux.net/dists/stable/main/binary-$__AndroidArch/libcurl_7.52.1_$__AndroidArch.deb -O $__Android_Cross_Dir/deb/libcurl_7.52.1_$__AndroidArch.deb
+
+echo Unpacking Termux packages
+dpkg -x $__Android_Cross_Dir/deb/libicu_58.2_$__AndroidArch.deb $__Android_Cross_Dir/tmp/$__AndroidArch/
+dpkg -x $__Android_Cross_Dir/deb/libicu-dev_58.2_$__AndroidArch.deb $__Android_Cross_Dir/tmp/$__AndroidArch/
+dpkg -x $__Android_Cross_Dir/deb/libuuid-dev_1.0.3_$__AndroidArch.deb $__Android_Cross_Dir/tmp/$__AndroidArch/
+dpkg -x $__Android_Cross_Dir/deb/libuuid_1.0.3_$__AndroidArch.deb $__Android_Cross_Dir/tmp/$__AndroidArch/
+dpkg -x $__Android_Cross_Dir/deb/libandroid-glob-dev_0.3_$__AndroidArch.deb $__Android_Cross_Dir/tmp/$__AndroidArch/
+dpkg -x $__Android_Cross_Dir/deb/libandroid-glob_0.3_$__AndroidArch.deb $__Android_Cross_Dir/tmp/$__AndroidArch/
+dpkg -x $__Android_Cross_Dir/deb/libandroid-support-dev_13.10_$__AndroidArch.deb $__Android_Cross_Dir/tmp/$__AndroidArch/
+dpkg -x $__Android_Cross_Dir/deb/libandroid-support_13.10_$__AndroidArch.deb $__Android_Cross_Dir/tmp/$__AndroidArch/
+dpkg -x $__Android_Cross_Dir/deb/liblzma-dev_5.2.3_$__AndroidArch.deb $__Android_Cross_Dir/tmp/$__AndroidArch/
+dpkg -x $__Android_Cross_Dir/deb/liblzma_5.2.3_$__AndroidArch.deb $__Android_Cross_Dir/tmp/$__AndroidArch/
+dpkg -x $__Android_Cross_Dir/deb/libcurl-dev_7.52.1_$__AndroidArch.deb $__Android_Cross_Dir/tmp/$__AndroidArch/
+dpkg -x $__Android_Cross_Dir/deb/libcurl_7.52.1_$__AndroidArch.deb $__Android_Cross_Dir/tmp/$__AndroidArch/
+
+cp -R $__Android_Cross_Dir/tmp/$__AndroidArch/data/data/com.termux/files/usr/* $__ToolchainDir/sysroot/usr/
+
+# Prepare libunwind
+if [ ! -d $__libunwind_Dir ]; then
+    git clone https://android.googlesource.com/platform/external/libunwind/ $__libunwind_Dir
+fi
+
+cd $__libunwind_Dir
+git checkout android-6.0.0_r26
+git checkout -- .
+git clean -xfd
+
+# libunwind is available on Android, but not included in the NDK.
+echo Building libunwind
+autoreconf --force -v --install 2> /dev/null
+./configure CC=$__ToolchainDir/bin/$__AndroidArch-linux-android-clang --with-sysroot=$__ToolchainDir/sysroot --host=x86_64 --target=$__AndroidArch-eabi --disable-coredump --prefix=$__ToolchainDir/sysroot/usr 2> /dev/null
+make > /dev/null
+make install > /dev/null
+
+# This header file is missing
+cp include/libunwind.h $__ToolchainDir/sysroot/usr/include/
+
+echo Now run:
+echo CONFIG_DIR=\`realpath cross/android/arm64\` ROOTFS_DIR=\`realpath $__ToolchainDir/sysroot\` ./build.sh cross arm64 skipgenerateversion skipmscorlib cmakeargs -DENABLE_LLDBPLUGIN=0
+