Difference between revisions of "Build D for Android"

From D Wiki
Jump to: navigation, search
(Update building sieve and basic GUI app)
(Add directions for future and link to tweaked LLVM)
(25 intermediate revisions by 2 users not shown)
Line 1: Line 1:
These instructions show you how to build D command-line executables and OpenGL ES GUI apps for Android, either by using [https://github.com/ldc-developers/ldc/releases/tag/v1.4.0 the Windows/linux compilers available here] or a native Android compiler.  There are separate steps for cross-compilation, ie building apps on a Windows or linux PC and running them on Android/ARM, versus native compilation, both building and running on your Android/ARM device itself.
+
These instructions show you how to build D command-line executables and OpenGL ES GUI apps for Android, either by using [https://github.com/ldc-developers/ldc/releases the desktop D compilers for Windows, Mac, or linux available here] or a native Android compiler.  There are separate steps for cross-compilation, ie building apps on a Windows/linux PC or Mac and running the app on Android, versus native compilation, both building and running on your Android device itself.
  
 
Since you cannot install the Android SDK on Android, I end by showing how to package a GUI Android app, a zip file called an .apk, from scratch, by using the tools available in the Termux app for Android, a terminal emulator app and open-source package manager/repository for Android devices.
 
Since you cannot install the Android SDK on Android, I end by showing how to package a GUI Android app, a zip file called an .apk, from scratch, by using the tools available in the Termux app for Android, a terminal emulator app and open-source package manager/repository for Android devices.
Line 5: Line 5:
 
==Prerequisites==
 
==Prerequisites==
 
===Cross-compilation===
 
===Cross-compilation===
* A command shell on your host PC, where you'll run the ldc cross-compiler
+
* A command shell on your host PC/Mac, where you'll run the ldc D compiler
 
** Either a DOS command prompt or Powershell should work on Windows.
 
** Either a DOS command prompt or Powershell should work on Windows.
** Any shell should work on linux, typical commands for the bash shell are shown.
+
** Any shell should work on Mac and linux, typical commands for the <tt>bash</tt> shell are shown.
 
* Android native toolchain, [https://developer.android.com/ndk/index.html the NDK] and optionally [https://developer.android.com/studio/index.html the SDK]
 
* Android native toolchain, [https://developer.android.com/ndk/index.html the NDK] and optionally [https://developer.android.com/studio/index.html the SDK]
** The SDK is necessary if you want to package a GUI app; the NDK is enough if you just want to build a command-line binary.
+
** The SDK is necessary to package a GUI app; the NDK is enough if you just want to build a command-line binary.
* The ldc D compiler, either 1.4 or later
+
** A recent version of the NDK, 15c or later, is required.  Older versions like r13b will not work.
 +
* The ldc D compiler, version 1.12 or later
 +
** It's best to use [https://github.com/ldc-developers/ldc/releases the official release from github], as it's built against [https://github.com/ldc-developers/llvm/releases a slightly tweaked LLVM] that supports emulated TLS on Android. If using ldc from your distro or elsewhere, make sure it was built against our tweaked LLVM, otherwise it will not compile properly for Android.
 +
** Note that all the samples below pass the <tt>-mcpu=cortex-a8</tt> flag to ldc when compiling for 32-bit Android/ARM. That is needed because ldc will otherwise choose LLVM's <tt>generic</tt> ARM CPU, which can sometimes break code-generation. You can pick a more recent 32-bit ARM CPU than <tt>cortex-a8</tt> as the baseline, but make sure both the runtime libraries and your code are built with the same baseline CPU.
 +
** The final ldc 1.12 release has a bug in the way emulated TLS is accessed by the runtime libraries on 32-bit ARM. Either use the ldc 1.13 beta instead or patch one file and rebuild the runtime libraries for 32-bit Android/ARM, ie do this after running the commands in the Setup section below.
 +
<syntaxhighlight lang=bash>
 +
cd droid32/ldc-src/
 +
curl -L -O https://raw.githubusercontent.com/termux/termux-packages/master/packages/ldc/ldc-druntime-tls.patch
 +
 
 +
patch -p1 < ldc-druntime-tls.patch
 +
cd ../..
 +
 
 +
# add the --reset flag to the command for your OS
 +
ldc-build-runtime --targetPreset=Android-arm --dFlags="-w;-mcpu=cortex-a8" --buildDir=droid32 --reset
 +
</syntaxhighlight>
 
* Common build tools
 
* Common build tools
** CMake and either Make or Ninja are required to build the runtime libraries for Android.  There are instructions below on setting them up.
+
** <tt>CMake</tt> and either <tt>Make</tt> or <tt>Ninja</tt> are required to build the D runtime libraries for Android.  There are instructions below on setting these tools up for Windows, Mac, and linux.
* Android/ARM, whether a device or emulator, to run your D code
+
* Android, whether a device or emulator, to run your D code
** The SDK comes with an emulator.  I use actual hardware, so that's what I'll discuss.  Make sure it's a 32-bit ARM device, as 64-bit ARM is not supported yet.
+
** The SDK comes with an emulator.  I use actual hardware, so that's what I'll discuss.
 
** If using a device, you need some way to transfer the app over.  There are several ways to do this, here are a few I've tried:
 
** If using a device, you need some way to transfer the app over.  There are several ways to do this, here are a few I've tried:
# Install an ssh server app on your Android device and scp the app over.  Alternately, set up an ssh server on your host PC, and use an ssh/scp client on Android to get the app.  This is what I do, by using the OpenSSH client in Termux.  
+
# Install an ssh server app on your Android device and scp the app over.  Alternately, set up an ssh server on your host PC/Mac, and use an ssh/scp client on Android to get the app.  This is what I do, by using the OpenSSH package in Termux.  
 
# Host the app in a web server and get it by using your Android browser or a downloader app.
 
# Host the app in a web server and get it by using your Android browser or a downloader app.
 
# [https://developer.android.com/studio/command-line/adb.html Setup the Android Debug Bridge (adb) on your device] and use the SDK tools to push your files over.
 
# [https://developer.android.com/studio/command-line/adb.html Setup the Android Debug Bridge (adb) on your device] and use the SDK tools to push your files over.
Line 22: Line 36:
 
===Native compilation===
 
===Native compilation===
 
* Termux for Android, available in [https://play.google.com/store/apps/details?id=com.termux&hl=en the official Play Store], [https://www.apkmirror.com/apk/fredrik-fornwall/termux/ APKMirror], or [https://f-droid.org/packages/com.termux/ F-Droid]
 
* Termux for Android, available in [https://play.google.com/store/apps/details?id=com.termux&hl=en the official Play Store], [https://www.apkmirror.com/apk/fredrik-fornwall/termux/ APKMirror], or [https://f-droid.org/packages/com.termux/ F-Droid]
** Check if it's a 32-bit ARM device by running "uname -m".  If it returns "armv7l", you're good.  If it says "aarch64," your 64-bit ARM device is not supported by ldc yet.
 
  
 
==Setup==
 
==Setup==
  
Once you're at a command prompt or have the Termux app installed, get the ldc compiler for Android and the NDK for cross-compilation, set some needed environment variables, and generate the runtime libraries for Android/ARM, which will be found in ldc-build-runtime.tmp/lib/.
+
Once you're at a command prompt or have the Termux app installed, get the ldc compiler for your OS and the NDK for cross-compilation, set some needed environment variables, and generate the runtime libraries for Android.
  
 
===Cross-compilation===
 
===Cross-compilation===
 
====Windows====
 
====Windows====
  
Download [https://cmake.org/download/ CMake] and the zip files for [https://developer.android.com/ndk/downloads/index.html one of the Android NDKs for Windows], [https://github.com/ldc-developers/ldc/releases/tag/v1.4.0 ldc 1.4], and either Make or [https://github.com/ninja-build/ninja/releases Ninja] (the following instructions assume Ninja).  Make sure unzip is available to unpack all the build tools, then add them to your path, set the path of the NDK and its C cross-compiler, and run ldc-build-runtime.  I show the commands for 64-bit Windows, should be similar for 32-bit, except the Ninja zip only comes with a 64-bit version.
+
Download [https://cmake.org/download/ CMake] and the zip files for [https://developer.android.com/ndk/downloads/ one of the Android NDKs for Windows], [https://github.com/ldc-developers/ldc/releases the latest ldc], and either Make or [https://github.com/ninja-build/ninja/releases Ninja] (the following instructions assume Ninja).  You will need [https://www.7-zip.org/download.html 7-Zip to unpack recent ldc releases]. Make sure <tt>unzip</tt> is available to unpack the rest of the build tools, then add them to your path, set the path of the NDK and its C cross-compiler, and run <tt>ldc-build-runtime</tt>.  I show the commands for 64-bit Windows, should be similar for 32-bit, except the Ninja zip only comes with a 64-bit version.
  
 
<syntaxhighlight lang=powershell>
 
<syntaxhighlight lang=powershell>
 
cd droid  # assuming all the zip files have been placed in a folder called droid
 
cd droid  # assuming all the zip files have been placed in a folder called droid
  
unzip cmake-3.9.2-win64-x64.zip
+
unzip cmake-3.11.4-win64-x64.zip
unzip ldc2-1.4.0-win64-msvc.zip
+
7z x ldc2-1.11.0-windows-x64.7z
unzip android-ndk-r15c-windows-x86_64.zip
+
unzip android-ndk-r17b-windows-x86_64.zip
 
unzip ninja-win.zip
 
unzip ninja-win.zip
  
set PATH=%PATH%;C:\Users\you\droid\cmake-3.9.2-win64-x64\bin;C:\Users\you\droid\ldc2-1.4.0-win64-msvc\bin;C:\Users\you\droid
+
set PATH=%PATH%;C:\Users\you\droid\cmake-3.11.4-win64-x64\bin;C:\Users\you\droid\ldc2-1.11.0-windows-x64\bin;C:\Users\you\droid
 +
 
 +
ldmd2 --version  # run this to check that ldc is in your path
 +
 
 +
set CC=C:\Users\you\droid\android-ndk-r17b\toolchains\llvm\prebuilt\windows-x86_64\bin\clang
 +
 
 +
ldc-build-runtime --ninja --targetPreset=Android-arm --dFlags="-w;-mcpu=cortex-a8" --buildDir=droid32
 +
 
 +
ldc-build-runtime --ninja --targetPreset=Android-aarch64 --buildDir=droid64
 +
 
 +
set NDK=C:\Users\you\droid\android-ndk-r17b
 +
</syntaxhighlight>
 +
 
 +
====Mac====
 +
 
 +
Download [https://cmake.org/download/ CMake], [https://developer.android.com/ndk/downloads/ the zip file for the Android NDK], [https://github.com/ldc-developers/ldc/releases the latest ldc], and either Make or [https://github.com/ninja-build/ninja/releases Ninja] (the following instructions assume Ninja).  CMake and Ninja can be installed from a package manager like [https://brew.sh Homebrew], but I'll show the manual install here.  Make sure <tt>unzip</tt> is available to unpack the NDK and <tt>tar</tt> for everything else.  After unpacking, add these tools to your path, including setting the path of the NDK and its C cross-compiler, and run <tt>ldc-build-runtime</tt>.
 +
 
 +
<syntaxhighlight lang=bash>
 +
cd droid  # assuming all the zip and tar files have been placed in a folder called droid
 +
 
 +
tar xf cmake-3.11.4-Darwin-x86_64.tar.gz
 +
tar xf ldc2-1.11.0-osx-x86_64.tar.xz
 +
unzip android-ndk-r17b-darwin-x86_64.zip
 +
unzip ninja-mac.zip
 +
 
 +
export PATH=$PATH:/Users/you/droid/cmake-3.11.4-Darwin-x86_64/CMake.app/Contents/bin:/Users/you/droid/ldc2-1.11.0-osx-x86_64/bin:/Users/you/droid
 +
 
 +
ldmd2 --version  # run this to check that ldc is in your path
  
ldc2 --version  # run this to check that ldc is in your path
+
export CC=/Users/you/droid/android-ndk-r17b/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang
  
set CC=C:\Users\you\droid\android-ndk-r15c\toolchains\llvm\prebuilt\windows-x86_64\bin\clang
+
ldc-build-runtime --ninja --targetPreset=Android-arm --dFlags="-w;-mcpu=cortex-a8" --buildDir=droid32
  
ldc-build-runtime --ninja --targetPreset=Android-arm
+
ldc-build-runtime --ninja --targetPreset=Android-aarch64 --buildDir=droid64
  
set NDK=C:\Users\you\droid\android-ndk-r15c
+
export NDK=/Users/you/droid/android-ndk-r17b
 +
export HOST=darwin-x86_64
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
====linux====
 
====linux====
  
Install needed packages, including optionally Ninja, as shown here for Ubuntu.  You will need tar to unpack ldc and unzip for the NDK.  Add ldc to your path and export the path of the NDK and its C cross-compiler, as shown here for bash, and run ldc-build-runtime.
+
Install needed packages, including optionally Ninja, as shown here for Ubuntu.  You will need <tt>tar</tt> to unpack ldc and <tt>unzip</tt> for the NDK.  Add ldc to your path and export the path of the NDK and its C cross-compiler, as shown here for bash, and run <tt>ldc-build-runtime</tt>.
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
sudo apt-get install build-essential cmake curl ninja unzip
+
sudo apt-get install cmake curl ninja-build unzip
 +
 
 +
curl -L -O https://dl.google.com/android/repository/android-ndk-r17b-linux-x86_64.zip
 +
 
 +
unzip android-ndk-r17b-linux-x86_64.zip
  
curl -L -O https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip
+
curl -L -O https://github.com/ldc-developers/ldc/releases/download/v1.11.0/ldc2-1.11.0-linux-x86_64.tar.xz
  
unzip android-ndk-r15c-linux-x86_64.zip
+
tar xf ldc2-1.11.0-linux-x86_64.tar.xz
 +
export PATH=$PATH:/path/to/your/ldc2-1.11.0-linux-x86_64/bin
  
curl -L -O https://github.com/ldc-developers/ldc/releases/download/v1.4.0/ldc2-1.4.0-linux-x86_64.tar.xz
+
ldmd2 --version  # check that ldc is in your path
  
tar xf ldc2-1.4.0-linux-x86_64.tar.xz
+
export CC=/path/to/your/android-ndk-r17b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
export PATH=$PATH:/path/to/your/ldc2-1.4.0-linux-x86_64/bin
 
ldc2 --version  # check that ldc is your path
 
  
export CC=/path/to/your/android-ndk-r15c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
+
ldc-build-runtime --targetPreset=Android-arm --dFlags="-w;-mcpu=cortex-a8" --buildDir=droid32
  
ldc-build-runtime --targetPreset=Android-arm
+
ldc-build-runtime --targetPreset=Android-aarch64 --buildDir=droid64
  
export NDK=/path/to/your/android-ndk-r15c
+
export NDK=/path/to/your/android-ndk-r17b
 +
export HOST=linux-x86_64
 +
</syntaxhighlight>
 +
 
 +
====Set environment variables====
 +
 
 +
The environment variables vary based on whether you want to target 32-bit or 64-bit ARM.
 +
 
 +
=====32-bit ARM=====
 +
 
 +
On linux or macOS:
 +
<syntaxhighlight lang=bash>
 +
export TRIPLE=armv7-none-linux-androideabi
 +
export DFLAGS="-mtriple=$TRIPLE -mcpu=cortex-a8"
 +
export LIBDIR=droid32
 +
 
 +
export NDK_ARCH=arch-arm
 +
export NDK_LINKER=arm-linux-androideabi-4.9
 +
export APK_DIR=armeabi-v7a
 +
</syntaxhighlight>
 +
 
 +
On Windows:
 +
<syntaxhighlight lang=powershell>
 +
set TRIPLE=armv7-none-linux-androideabi
 +
set DFLAGS=-mtriple=%TRIPLE% -mcpu=cortex-a8
 +
set LIBDIR=droid32
 +
 
 +
set NDK_ARCH=arch-arm
 +
set NDK_LINKER=arm-linux-androideabi-4.9
 +
set APK_DIR=armeabi-v7a
 +
</syntaxhighlight>
 +
 
 +
=====64-bit ARM=====
 +
 
 +
On linux/macOS:
 +
<syntaxhighlight lang=bash>
 +
export TRIPLE=aarch64-none-linux-android
 +
export DFLAGS="-mtriple=$TRIPLE"
 +
export LIBDIR=droid64
 +
 
 +
export NDK_ARCH=arch-arm64
 +
export NDK_LINKER=aarch64-linux-android-4.9
 +
export APK_DIR=arm64-v8a
 +
</syntaxhighlight>
 +
 
 +
On Windows:
 +
<syntaxhighlight lang=powershell>
 +
set TRIPLE=aarch64-none-linux-android
 +
set DFLAGS=-mtriple=%TRIPLE%
 +
set LIBDIR=droid64
 +
 
 +
set NDK_ARCH=arch-arm64
 +
set NDK_LINKER=aarch64-linux-android-4.9
 +
set APK_DIR=arm64-v8a
 +
</syntaxhighlight>
 +
 
 +
===== Set path to runtime =====
 +
 
 +
Finally, set the path to the runtime libraries you just built:
 +
 
 +
<syntaxhighlight lang=bash>
 +
# On linux
 +
export RTDIR=/path/to/your/$LIBDIR
 +
 
 +
# On Mac
 +
export RTDIR=/Users/you/droid/$LIBDIR
 +
 
 +
# On Windows
 +
set RTDIR=C:\Users\you\droid\%LIBDIR%
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 81: Line 193:
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
 
apt install ldc
 
apt install ldc
 +
</syntaxhighlight>
 +
 +
These instructions show you how to compile a GUI app for your device, but you'll need to know whether you're running 32-bit or 64-bit ARM. Run <syntaxhighlight lang=bash>uname -m</syntaxhighlight> in Termux and if it says <tt>aarch64</tt>, you're running 64-bit ARM. <tt>armv7l</tt> means you're running 32-bit ARM.
 +
 +
Note that you should pass the <tt>-mcpu=cortex-a8</tt> flag to ldc when compiling for 32-bit Android/ARM, even though the few samples below don't require it. See the explanation above in the <tt>Cross-compilation</tt> section for more details.
 +
 +
Set the <tt>APK_DIR</tt> environment variable to the right platform for your device:
 +
 +
====32-bit ARM====
 +
<syntaxhighlight lang=bash>
 +
export APK_DIR=armeabi-v7a
 +
</syntaxhighlight>
 +
 +
====64-bit ARM====
 +
<syntaxhighlight lang=bash>
 +
export APK_DIR=arm64-v8a
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
==Build a command-line executable==
 
==Build a command-line executable==
  
Now that we have a D compiler and runtime libraries for Android, let's try building a small program, [https://github.com/dlang/dmd/blob/master/samples/sieve.d the classic Sieve of Eratosthenes single-core benchmark], which finds all prime numbers up to a number you choose.
+
Now that we have a D compiler and runtime libraries for Android, let's try building a small program, [https://github.com/dlang/dmd/blob/master/samples/sieve.d the classic Sieve of Eratosthenes single-core benchmark], which finds all prime numbers up to a number you choose. Install the curl package in Termux if you're natively compiling, <tt>apt install curl</tt>.
 
 
===Cross-compilation===
 
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
 
# Load this link in your browser and download the file otherwise  
 
# Load this link in your browser and download the file otherwise  
curl -L -O https://raw.githubusercontent.com/dlang/dmd/master/samples/sieve.d
+
curl -L -O
 +
https://raw.githubusercontent.com/dlang/dmd/master/samples/sieve.d
  
# On linux
+
# On linux/macOS
ldc2 -mtriple=armv7-none-linux-android -L-L/path/to/your/ldc-build-runtime.tmp/lib
+
ldmd2 -L-L$RTDIR/lib -Xcc=--sysroot=$NDK/platforms/android-21/$NDK_ARCH
-Xcc=--sysroot=$NDK/platforms/android-21/arch-arm -Xcc=-fuse-ld=bfd -Xcc=-gcc-toolchain
+
-Xcc=-fuse-ld=bfd -Xcc=-gcc-toolchain
-Xcc=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 -Xcc=-target
+
-Xcc=$NDK/toolchains/$NDK_LINKER/prebuilt/$HOST
-Xcc=armv7-none-linux-androideabi -Xcc=-fpie -Xcc=-pie sieve.d
+
-Xcc=-target -Xcc=$TRIPLE -Xcc=-fpie -Xcc=-pie sieve.d
  
 
# On 64-bit Windows
 
# On 64-bit Windows
ldc2 -mtriple=armv7-none-linux-android -L-LC:\Users\you\droid\ldc-build-runtime.tmp\lib
+
ldmd2 -L-L%RTDIR%\lib -Xcc=--sysroot=%NDK%\platforms\android-21\%NDK_ARCH%
-Xcc=--sysroot=%NDK%\platforms\android-21\arch-arm -Xcc=-fuse-ld=bfd.exe -Xcc=-gcc-toolchain
+
-Xcc=-fuse-ld=bfd.exe -Xcc=-gcc-toolchain
-Xcc=%NDK%\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64 -Xcc=-target
+
-Xcc=%NDK%\toolchains\%NDK_LINKER%\prebuilt\windows-x86_64
-Xcc=armv7-none-linux-androideabi -Xcc=-fpie -Xcc=-pie sieve.d
+
-Xcc=-target -Xcc=%TRIPLE% -Xcc=-fpie -Xcc=-pie sieve.d
 +
 
 +
# Natively compiling in the Termux app for Android
 +
ldmd2 sieve.d
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Copy this sieve program onto an Android device or emulator and set its permissions with the chmod command. Here's how I do it in Termux, with an ssh server running on the host PC with IP address 192.168.1.37:
+
===Cross-compilation===
 +
 
 +
Copy this <tt>sieve</tt> program onto an Android device or emulator and set its permissions with the <tt>chmod</tt> command. Here's how I do it in Termux, with an ssh server running on the host PC/Mac with IP address 192.168.1.37:
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
Line 113: Line 245:
 
scp jo@192.168.1.37:sieve .
 
scp jo@192.168.1.37:sieve .
 
chmod 700 sieve
 
chmod 700 sieve
</syntaxhighlight>
 
 
===Native compilation===
 
<syntaxhighlight lang=bash>
 
apt install curl
 
 
curl -L -O https://raw.githubusercontent.com/dlang/dmd/master/samples/sieve.d
 
 
ldc2 sieve.d
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
===Run the sieve program===
 
===Run the sieve program===
The sieve program will tell you how many prime numbers there are in the first n integers, a limit you can specify.  Run this command to find how many primes there are in the first million integers:
+
The <tt>sieve</tt> program will tell you how many prime numbers there are in the first n integers, a limit you can specify.  Run this command to find how many primes there are in the first million integers:
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
Line 131: Line 254:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
If you built sieve successfully, it should return
+
If you built <tt>sieve</tt> successfully, it should return
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
Line 139: Line 262:
 
==Build a sample OpenGL ES 1.0 GUI app ported to D==
 
==Build a sample OpenGL ES 1.0 GUI app ported to D==
  
Clone [https://github.com/joakim-noah/android my android repository] or download its source, which contains several headers and sample OpenGL apps from the NDK translated to D, and build the Native Activity app, which is written completely in D.  As you'll see below, D code for an apk must be compiled to a shared library, which the Android runtime will call.
+
Clone [https://github.com/joakim-noah/android my android repository] or [https://github.com/joakim-noah/android/releases download its source in a zip file], which contains several headers and sample OpenGL apps from the NDK translated to D, and build the Native Activity app, which is written completely in D.  As you'll see below, D code for an apk must be compiled to a shared library, which the Android runtime will call.
 
 
===Cross-compilation===
 
  
On linux, you can just clone my git repo:
+
On linux or the Termux app, you can just clone my git repo (the same can be done on Mac and Windows if you install <tt>git</tt> first):
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
sudo apt-get install git
+
sudo apt-get install git # In Termux, apt install git
  
 
git clone https://github.com/joakim-noah/android.git
 
git clone https://github.com/joakim-noah/android.git
Line 156: Line 277:
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
curl -L -O https://github.com/joakim-noah/android/archive/tea.zip
+
curl -L -O https://github.com/joakim-noah/android/archive/build.zip
  
unzip tea.zip
+
unzip build.zip
cd android-tea/
+
cd android-build/
 
</syntaxhighlight>
 
</syntaxhighlight>
  
After getting the source, go to the sample app, compile the D source, then link the objects into a shared library and place it in the directory that the SDK expects.
+
After getting the source, go to the sample app, compile the D source, then link the objects into a shared library and place it in the right directory for your platform.
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
 
cd samples/native-activity/
 
cd samples/native-activity/
  
ldc2 -mtriple=armv7-none-linux-android -I../../ -c jni/main.d
+
ldmd2 -I../../ -c jni/main.d
  
ldc2 -mtriple=armv7-none-linux-android -I../../ -c ../../android/sensor.d
+
ldmd2 -I../../ -c ../../android/sensor.d
  
ldc2 -mtriple=armv7-none-linux-android -I../../ -c ../../android_native_app_glue.d
+
ldmd2 -I../../ -c ../../android_native_app_glue.d
  
mkdir -p libs/armeabi-v7a/  # On Windows, mkdir libs\armeabi-v7a
+
mkdir -p libs/$APK_DIR/  # On Windows, mkdir libs\%APK_DIR%
  
# On linux
+
# On linux/macOS
$CC -Wl,-soname,libnative-activity.so -shared --sysroot=$NDK/platforms/android-21/arch-arm
+
$CC -Wl,-soname,libnative-activity.so -shared --sysroot=$NDK/platforms/android-21/$NDK_ARCH
main.o sensor.o android_native_app_glue.o /path/to/your/ldc-build-runtime.tmp/lib/libphobos2-ldc.a
+
main.o sensor.o android_native_app_glue.o $RTDIR/lib/libphobos2-ldc.a
/path/to/your/ldc-build-runtime.tmp/lib/libdruntime-ldc.a -gcc-toolchain
+
$RTDIR/lib/libdruntime-ldc.a -gcc-toolchain
$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 -fuse-ld=bfd -target
+
$NDK/toolchains/$NDK_LINKER/prebuilt/$HOST -fuse-ld=bfd -target $TRIPLE -llog -landroid -lEGL -lGLESv1_CM
armv7-none-linux-androideabi -llog -landroid -lEGL -lGLESv1_CM
+
-o libs/$APK_DIR/libnative-activity.so
-o libs/armeabi-v7a/libnative-activity.so
 
  
 
# On 64-bit Windows
 
# On 64-bit Windows
%CC% -Wl,-soname,libnative-activity.so -shared --sysroot=%NDK%\platforms\android-21\arch-arm
+
%CC% -Wl,-soname,libnative-activity.so -shared --sysroot=%NDK%\platforms\android-21\%NDK_ARCH%
main.o sensor.o android_native_app_glue.o C:\Users\you\droid\ldc-build-runtime.tmp\lib\libphobos2-ldc.a
+
main.o sensor.o android_native_app_glue.o %RTDIR%\lib\libphobos2-ldc.a
C:\Users\you\droid\ldc-build-runtime.tmp\lib\libdruntime-ldc.a -gcc-toolchain
+
%RTDIR%\lib\libdruntime-ldc.a -gcc-toolchain
%NDK%\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64 -fuse-ld=bfd.exe -target
+
%NDK%\toolchains\%NDK_LINKER%\prebuilt\windows-x86_64 -fuse-ld=bfd.exe -target
armv7-none-linux-androideabi -llog -landroid -lEGL -lGLESv1_CM
+
%TRIPLE% -llog -landroid -lEGL -lGLESv1_CM
-o libs\armeabi-v7a\libnative-activity.so
+
-o libs\%APK_DIR%\libnative-activity.so
 +
 
 +
# In Termux
 +
mkdir -p lib/$APK_DIR/
 +
 
 +
$PREFIX/bin/clang -Wl,-soname,libnative-activity.so -shared main.o sensor.o
 +
android_native_app_glue.o $PREFIX/lib/libphobos2-ldc.a $PREFIX/lib/libdruntime-ldc.a
 +
-llog -landroid -lEGL -lGLESv1_CM -o lib/$APK_DIR/libnative-activity.so
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Finally, package the app as the SDK directs.  I document the older Ant approach, which is deprecated, replace it with the Gradle command from a newer SDK.  With Ant on linux, set the path to your SDK, then run these commands:
+
===Cross-compilation===
 +
 
 +
Finally, package the app as the SDK directs: at this point, it's just like building a regular Android app.  I document the older Ant approach, which is deprecated, replace it with the Gradle command from a newer SDK.  With Ant on Mac or linux, set the path to your SDK, then run these commands:
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
export SDK=/path/to/your/android-sdk-linux
+
export SDK=/path/to/your/android-sdk
 
$SDK/tools/android update project -p . -s --target 1
 
$SDK/tools/android update project -p . -s --target 1
 
ant debug
 
ant debug
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Transfer the resulting bin/NativeActivity-debug.apk to your Android device, again shown here by using scp from the Termux app.
+
Transfer the resulting <tt>bin/NativeActivity-debug.apk</tt> to your Android device, again shown here by using <tt>scp</tt> from the Termux app.
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
Line 207: Line 336:
  
 
===Native compilation===
 
===Native compilation===
 +
 +
[[#Package_an_Android_app_from_scratch_on_your_Android_device|Follow the instructions below to package this native shared library into an Android apk]].
 +
 +
===Install and run the sample GUI app===
 +
Go to <tt>Settings->Security</tt> on your Android device and allow installation of apps from unknown sources, ie from outside the Play Store, then go to <tt>/sdcard/Download</tt> in your file manager and choose the <tt>NativeActivity-debug</tt> apk to install it.  Open the app after installing or go to your app folder and run the app named <tt>NativeActivity</tt>: it'll show a black screen initially, then flash a bunch of colors when the screen is touched.
 +
 +
==Build a sample OpenGL ES 2.0 GUI app mostly written in D, with some Java==
 +
 +
This D app has not been ported to 64-bit Android/ARM yet, only 32-bit ARM compilation will work for now.
 +
 +
The app comes with a simple build script, which will build the D shared library for you, as long as the environment variables are set.
 +
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
apt install git
+
cd samples/Teapot/
  
git clone https://github.com/joakim-noah/android.git
+
# On linux/macOS
 +
./build-apk
 +
 
 +
# On 64-bit Windows
 +
call build-apk.bat
 +
</syntaxhighlight>
  
cd android/samples/native-activity/
+
Here are the contents of that script, so you can see what it's doing.  The Windows version, <tt>build-apk.bat</tt>, and the linux/macOS version, <tt>build-apk</tt>, only differ on the final link command, which I've pasted below.
  
ldc2 -I../../ -c jni/main.d
+
<syntaxhighlight lang=bash>
 +
ldmd2 -I../../ -c ../../ndk_helper/GLContext.d
 +
ldmd2 -I../../ -c ../../ndk_helper/JNIHelper.d
 +
ldmd2 -I../../ -c ../../ndk_helper/gestureDetector.d
 +
ldmd2 -I../../ -c ../../ndk_helper/perfMonitor.d
 +
ldmd2 -I../../ -c ../../ndk_helper/shader.d
 +
ldmd2 -I../../ -c ../../ndk_helper/tapCamera.d
  
ldc2 -I../../ -c ../../android/sensor.d
+
ldmd2 -I../../ -Ijni/ -Jjni/ -c jni/TeapotNativeActivity.d
 +
ldmd2 -I../../ -Jjni/ -c jni/TeapotRenderer.d
 +
ldmd2 -I../../ -c ../../android/sensor.d
  
ldc2 -I../../ -c ../../android_native_app_glue.d
+
ldmd2 -I../../ -c ../../android_native_app_glue.d
  
mkdir -p lib/armeabi-v7a/
+
mkdir -p libs/$APK_DIR/   # On Windows, mkdir libs\%APK_DIR%
  
$PREFIX/bin/clang -Wl,-soname,libnative-activity.so -shared main.o sensor.o
+
# Link command on linux/macOS
android_native_app_glue.o $PREFIX/lib/libphobos2-ldc.a $PREFIX/lib/libdruntime-ldc.a  
+
$CC -Wl,-soname,libTeapotNativeActivity.so -shared
-target armv7-none-linux-androideabi -llog -landroid -lEGL -lGLESv1_CM
+
--sysroot=$NDK/platforms/android-21/$NDK_ARCH TeapotNativeActivity.o sensor.o
-o lib/armeabi-v7a/libnative-activity.so
+
TeapotRenderer.o android_native_app_glue.o GLContext.o JNIHelper.o
</syntaxhighlight>
+
gestureDetector.o perfMonitor.o shader.o tapCamera.o
 +
$RTDIR/lib/libphobos2-ldc.a $RTDIR/lib/libdruntime-ldc.a -gcc-toolchain
 +
$NDK/toolchains/$NDK_LINKER/prebuilt/$HOST -fuse-ld=bfd
 +
-target $TRIPLE -llog -landroid -lEGL -lGLESv2
 +
-o libs/$APK_DIR/libTeapotNativeActivity.so
  
[[#Package_an_Android_app_from_scratch_on_your_Android_device|Follow the instructions below to package this native shared library into an Android apk]].
+
# Link command on 64-bit Windows
 +
%CC% -Wl,-soname,libTeapotNativeActivity.so -shared
 +
--sysroot=%NDK%\platforms\android-21\%NDK_ARCH% TeapotNativeActivity.o sensor.o
 +
TeapotRenderer.o android_native_app_glue.o GLContext.o JNIHelper.o
 +
gestureDetector.o perfMonitor.o shader.o tapCamera.o
 +
%RTDIR%\lib\libphobos2-ldc.a %RTDIR%\lib\libdruntime-ldc.a -gcc-toolchain
 +
%NDK%\toolchains\%NDK_LINKER%\prebuilt\windows-x86_64 -fuse-ld=bfd.exe
 +
-target %TRIPLE% -llog -landroid -lEGL -lGLESv2
 +
-o libs/%APK_DIR%/libTeapotNativeActivity.so
  
===Install and run the sample GUI app===
+
mkdir -p lib/$APK_DIR/
Go to Settings->Security on your Android device and allow installation of apps from unknown sources, ie from outside the Play Store, then go to /sdcard/Download in your file manager and choose the NativeActivity-debug apk to install it.  Open the app after installing or go to your app folder and run the app named NativeActivity: it'll show a black screen initially, then flash a bunch of colors when the screen is touched.
 
  
==Build a sample OpenGL ES 2.0 GUI app mostly written in D, with some Java==
+
# Link command in Termux
 +
clang -Wl,-soname,libTeapotNativeActivity.so -shared
 +
TeapotNativeActivity.o sensor.o TeapotRenderer.o
 +
android_native_app_glue.o GLContext.o JNIHelper.o
 +
gestureDetector.o perfMonitor.o shader.o
 +
tapCamera.o $PREFIX/lib/libphobos2-ldc.a
 +
$PREFIX/lib/libdruntime-ldc.a -llog -landroid
 +
-lEGL -lGLESv2 -o lib/$APK_DIR/libTeapotNativeActivity.so
 +
</syntaxhighlight>
  
 
===Cross-compilation===
 
===Cross-compilation===
This app comes with a simple script called build-apk, which will build the D shared library for you, as long as the LDC and NDK variables are set.
+
Package this shared library into an apk by using the SDK, as you would normally, and try installing and running it on your device.
 +
 
 +
===Native compilation===
 +
 
 +
Install the right Eclipse Java compiler package for your device (the ecj4.6 package if you're running Android 5 or 6), the Android dex tool, and other packages needed to build an Android apk. Generate any Java files needed, compile and dex them, then package everything up into an apk and sign it.
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
cd android/samples/Teapot/
+
apt install ecj dx aapt apksigner
./build-apk
+
 
 +
aapt package  -M ./AndroidManifest.xml -I $PREFIX/share/java/android-21.jar -J src/ -S res -m
 +
 
 +
ecj-21 -d ./obj -sourcepath src $(find src -type f -name "*.java")
 +
 
 +
dx --dex --output=./classes.dex ./obj/
 +
 
 +
aapt package  -M ./AndroidManifest.xml -S res -A assets -F teapot.apk
 +
 
 +
aapt add teapot.apk classes.dex lib/$APK_DIR/libTeapotNativeActivity.so
 +
 
 +
apksigner debug.ks teapot.apk teapot-signed.apk
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Here are the contents of that script, so you can see what it's doing.
+
Finally, move <tt>teapot-signed.apk</tt> into a public directory, from which you can install and run it.
  
<syntaxhighlight lang=bash>
+
==Changes for Android==
$LDC/bin/ldc2 -I../../ -c ../../ndk_helper/GLContext.d
 
$LDC/bin/ldc2 -I../../ -c ../../ndk_helper/JNIHelper.d
 
$LDC/bin/ldc2 -I../../ -c ../../ndk_helper/gestureDetector.d
 
$LDC/bin/ldc2 -I../../ -c ../../ndk_helper/perfMonitor.d
 
$LDC/bin/ldc2 -I../../ -c ../../ndk_helper/shader.d
 
$LDC/bin/ldc2 -I../../ -c ../../ndk_helper/tapCamera.d
 
  
$LDC/bin/ldc2 -I../../ -Ijni/ -Jjni/ -c jni/TeapotNativeActivity.d
+
Now that you've seen some examples, here's a description of changes to D that have been made for Android.
$LDC/bin/ldc2 -I../../ -Jjni/ -c jni/TeapotRenderer.d
 
$LDC/bin/ldc2 -I../../ -c ../../android/sensor.d
 
  
$LDC/bin/ldc2 -I../../ -c ../../android_native_app_glue.d
+
The Android environment doesn't support native Thread-Local Storage (TLS), which is integral to D, since [https://dlang.org/migrate-to-shared.html all static and global variables not explicitly marked shared/__gshared/immutable are thread-local by default in D]. The Android D runtime supports emulated TLS instead, but this requires some changes to the build process:
  
$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -Wl,-soname,libTeapotNativeActivity.so
+
# You must use the <tt>ld.bfd</tt> linker- see the use of <tt>-fuse-ld=bfd</tt> above- <tt>ld.gold</tt> won't do.
-shared --sysroot=$NDK/platforms/android-21/arch-arm TeapotNativeActivity.o sensor.o
+
# You must have a D <tt>main</tt> function, even for a shared library. [https://github.com/joakim-noah/android/blob/940bd899664db1f72a68d83bff197d55952089be/samples/native-activity/jni/main.d#L227 An empty D <tt>main</tt> can be put next to <tt>android_main</tt>], if you're using the default Android wrapper from my D android repo.
TeapotRenderer.o android_native_app_glue.o GLContext.o JNIHelper.o gestureDetector.o
+
# The ELF object with the D <tt>main</tt> function must be passed to the linker first.
perfMonitor.o shader.o tapCamera.o $LDC/lib/libphobos2-ldc.a $LDC/lib/libdruntime-ldc.a
 
-lgcc -gcc-toolchain $NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
 
-no-canonical-prefixes -fuse-ld=bfd -target armv7-none-linux-androideabi -Wl,--fix-cortex-a8
 
-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel
 
-Wl,--fatal-warnings -llog -landroid -lEGL -lGLESv2 -lc -lm -o libTeapotNativeActivity.so
 
</syntaxhighlight>
 
  
Package this shared library into an apk by using the SDK, as you would normally, and try installing and running it on your device.
+
All the examples above follow these rules, which are in place to make sure emulated TLS data is properly passed to the D garbage-collector.
  
===Native compilation===
+
If building a shared library and not a D command-line executable, you must also initialize and exit the D runtime by calling <tt>rt_init()</tt> and <tt>rt_term()</tt> before and after all D code is run, [https://github.com/joakim-noah/android/blob/4fbdbb1344725a593d8df1e008ba371c0e694a11/android_native_app_glue.d#L554 as has been done in the default Android wrapper] ([[Runtime internals|<tt>rt_init</tt>/<tt>rt_term</tt> are automatically inserted and run for a D executable]])Running multiple D shared libraries is currently unsupported on Android, only a single D shared library that statically links against the D runtime will work.
The steps are the same as above, except for a marginally different linker command, which is included in the build script but commented outHowever, this app requires compiling some Java code and the Java compilers in Termux aren't working at the moment, so I'll hold off on this for now.
 
  
 
==Package an Android app from scratch on your Android device==
 
==Package an Android app from scratch on your Android device==
  
Install aapt, the Android Asset Packaging Tool, and apksigner, a tool to create a hashed manifest and sign your apps.
+
Install <tt>aapt</tt>, the Android Asset Packaging Tool, and <tt>apksigner</tt>, a tool to create a hashed manifest and sign your apps.
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
Line 282: Line 455:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
I'll demonstrate with the NativeActivity app built above.
+
I'll demonstrate with the <tt>NativeActivity</tt> app built above.
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
cd android/samples/native-activity/
+
cd samples/native-activity/
 
aapt package -M AndroidManifest.xml -S res -F NativeActivity-debug-unsigned.apk
 
aapt package -M AndroidManifest.xml -S res -F NativeActivity-debug-unsigned.apk
aapt add NativeActivity-debug-unsigned.apk lib/armeabi-v7a/libnative-activity.so
+
aapt add NativeActivity-debug-unsigned.apk lib/$APK_DIR/libnative-activity.so
 
</syntaxhighlight>
 
</syntaxhighlight>
  
This simple app only requires three files, AndroidManifest.xml, resources.arsc, and lib/armeabi-v7a/libnative-activity.so, which you can check with the following aapt command.
+
This simple app only requires three files, <tt>AndroidManifest.xml</tt>, <tt>resources.arsc</tt>, and <tt>lib/$APK_DIR/libnative-activity.so</tt>, which you can check with the following <tt>aapt</tt> command.
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
Line 296: Line 469:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Now let's generate a hashed manifest, just like a Java jar file, and sign the app.  If you have your own Java Keystore already, just supply it to apksigner.  If not, apksigner will generate a self-signed Keystore file, which we name debug.ks below, which is good enough to sign and install debug apps on your own Android device.
+
Now let's generate a hashed manifest, just like a Java jar file, and sign the app.  If you have your own Java Keystore already, just supply it to <tt>apksigner</tt>.  If not, <tt>apksigner</tt> will generate a self-signed Keystore file, which we name <tt>debug.ks</tt> below, which is good enough to sign and install debug apps on your own Android device.
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
Line 302: Line 475:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
You should see three additional files in the apk, if you list its contents using the command above.  At this point, [[#Install_and_run_the_sample_GUI_app|you can install and run the signed app on your own device]].
+
You should see three additional files in the apk, if you list its contents using the command above.  At this point, [[#Install_and_run_the_sample_GUI_app|you can install and run the signed app on your own device]].  If you modify the app, you'll need to build the manifest and sign it again: make sure you use the <tt>debug.ks</tt> you created before or Android won't allow you to reinstall the same app with a newly generated key, unless you first uninstall the app.
  
 
===Sign your app using a certificate and OpenSSL===
 
===Sign your app using a certificate and OpenSSL===
Line 310: Line 483:
 
For a valid certificate for the final release, [https://developer.android.com/studio/publish/app-signing.html there's plenty of information online on how to generate one].  I'll just show how to create a self-signed certificate for debugging purposes.
 
For a valid certificate for the final release, [https://developer.android.com/studio/publish/app-signing.html there's plenty of information online on how to generate one].  I'll just show how to create a self-signed certificate for debugging purposes.
  
First, install the OpenSSL package in Termux.  Then, this OpenSSL command will generate a self-signed debug certificate, apk.cert, and a 2048-bit RSA private key, key.pem, which isn't encrypted with a password.  It will ask you for some signing info, for which I've shown what's used by the debug certificate in the Android SDK, but it doesn't matter what you enter, as it's ignored:
+
First, install the OpenSSL package in Termux.  Then, this OpenSSL command will generate a self-signed debug certificate, <tt>apk.cert</tt>, and a 2048-bit RSA private key, <tt>key.pem</tt>, which isn't encrypted with a password.  It will ask you for some signing info, for which I've shown what's used by the debug certificate in the Android SDK, but it doesn't matter what you enter, as it's ignored:
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
Line 318: Line 491:
  
 
....................................+++
 
....................................+++
...............................................................................................................................................................+++
 
 
writing new private key to 'key.pem'
 
writing new private key to 'key.pem'
 
-----
 
-----
Line 337: Line 509:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Now that we have a certificate- self-signed in this case, use your actual release certificate if you want to release the app- and private key, we use them to sign the app.  Since the apk is just a zip file, unzip it into a directory and use OpenSSL to generate a new signature file, CERT.RSA, then update the apk with the new signature, and copy the apk to a public user directory from which you can install it:
+
Now that we have a certificate- self-signed in this case, use your actual release certificate if you want to release the app- and private key, we use them to sign the app.  Since the apk is just a zip file, unzip it into a directory and use OpenSSL to generate a new signature file, <tt>CERT.RSA</tt>, then update the apk with the new signature, and copy the apk to a public user directory from which you can install it:
  
 
<syntaxhighlight lang=bash>
 
<syntaxhighlight lang=bash>
Line 355: Line 527:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
The OpenSSL commands to generate a certificate and sign the apk were taken [http://qistoph.blogspot.com/2012/01/manual-verify-pkcs7-signed-data-with.html from this 2012 blog post], you can follow it further to see what the signature consists of and verify it for yourself.  [https://nelenkov.blogspot.com/2013/04/android-code-signing.html This 2013 blog post was critical for me to understand how apk signing works], I used to run all those commands by hand until the apksigner package was added to the Termux package repo late last year.
+
The OpenSSL commands to generate a certificate and sign the apk were taken [http://qistoph.blogspot.com/2012/01/manual-verify-pkcs7-signed-data-with.html from this 2012 blog post], you can follow it further to see what the signature consists of and verify it for yourself.  [https://nelenkov.blogspot.com/2013/04/android-code-signing.html This 2013 blog post was critical for me to understand how apk signing works], I used to run all those commands by hand until the <tt>apksigner</tt> package was added to the Termux package repo.
 +
 
 +
==Directions for future work==
 +
 
 +
* I'm working on getting rid of the three requirements for emulated TLS, by changing the way it's initialized on Android.
 +
 
 +
* Integrate the linux shared library support in druntime's <tt>rt.sections_elf_shared</tt>, so that multiple D shared libraries can be used.
 +
 
 +
* Now that we can write D code for Android, it'll make building easier if ldc cross-compilation is integrated with [https://github.com/dlang/dub the D package manager and build tool, dub].
 +
 
 +
* Fix [https://github.com/ldc-developers/ldc/issues/2153 the remaining stdlib incompatibilities on 64-bit ARM].
  
 
[[Category: Android]]
 
[[Category: Android]]

Revision as of 10:41, 10 November 2018

These instructions show you how to build D command-line executables and OpenGL ES GUI apps for Android, either by using the desktop D compilers for Windows, Mac, or linux available here or a native Android compiler. There are separate steps for cross-compilation, ie building apps on a Windows/linux PC or Mac and running the app on Android, versus native compilation, both building and running on your Android device itself.

Since you cannot install the Android SDK on Android, I end by showing how to package a GUI Android app, a zip file called an .apk, from scratch, by using the tools available in the Termux app for Android, a terminal emulator app and open-source package manager/repository for Android devices.

Prerequisites

Cross-compilation

  • A command shell on your host PC/Mac, where you'll run the ldc D compiler
    • Either a DOS command prompt or Powershell should work on Windows.
    • Any shell should work on Mac and linux, typical commands for the bash shell are shown.
  • Android native toolchain, the NDK and optionally the SDK
    • The SDK is necessary to package a GUI app; the NDK is enough if you just want to build a command-line binary.
    • A recent version of the NDK, 15c or later, is required. Older versions like r13b will not work.
  • The ldc D compiler, version 1.12 or later
    • It's best to use the official release from github, as it's built against a slightly tweaked LLVM that supports emulated TLS on Android. If using ldc from your distro or elsewhere, make sure it was built against our tweaked LLVM, otherwise it will not compile properly for Android.
    • Note that all the samples below pass the -mcpu=cortex-a8 flag to ldc when compiling for 32-bit Android/ARM. That is needed because ldc will otherwise choose LLVM's generic ARM CPU, which can sometimes break code-generation. You can pick a more recent 32-bit ARM CPU than cortex-a8 as the baseline, but make sure both the runtime libraries and your code are built with the same baseline CPU.
    • The final ldc 1.12 release has a bug in the way emulated TLS is accessed by the runtime libraries on 32-bit ARM. Either use the ldc 1.13 beta instead or patch one file and rebuild the runtime libraries for 32-bit Android/ARM, ie do this after running the commands in the Setup section below.
cd droid32/ldc-src/
curl -L -O https://raw.githubusercontent.com/termux/termux-packages/master/packages/ldc/ldc-druntime-tls.patch

patch -p1 < ldc-druntime-tls.patch
cd ../..

# add the --reset flag to the command for your OS
ldc-build-runtime --targetPreset=Android-arm --dFlags="-w;-mcpu=cortex-a8" --buildDir=droid32 --reset
  • Common build tools
    • CMake and either Make or Ninja are required to build the D runtime libraries for Android. There are instructions below on setting these tools up for Windows, Mac, and linux.
  • Android, whether a device or emulator, to run your D code
    • The SDK comes with an emulator. I use actual hardware, so that's what I'll discuss.
    • If using a device, you need some way to transfer the app over. There are several ways to do this, here are a few I've tried:
  1. Install an ssh server app on your Android device and scp the app over. Alternately, set up an ssh server on your host PC/Mac, and use an ssh/scp client on Android to get the app. This is what I do, by using the OpenSSH package in Termux.
  2. Host the app in a web server and get it by using your Android browser or a downloader app.
  3. Setup the Android Debug Bridge (adb) on your device and use the SDK tools to push your files over.

Native compilation

Setup

Once you're at a command prompt or have the Termux app installed, get the ldc compiler for your OS and the NDK for cross-compilation, set some needed environment variables, and generate the runtime libraries for Android.

Cross-compilation

Windows

Download CMake and the zip files for one of the Android NDKs for Windows, the latest ldc, and either Make or Ninja (the following instructions assume Ninja). You will need 7-Zip to unpack recent ldc releases. Make sure unzip is available to unpack the rest of the build tools, then add them to your path, set the path of the NDK and its C cross-compiler, and run ldc-build-runtime. I show the commands for 64-bit Windows, should be similar for 32-bit, except the Ninja zip only comes with a 64-bit version.

cd droid   # assuming all the zip files have been placed in a folder called droid

unzip cmake-3.11.4-win64-x64.zip
7z x ldc2-1.11.0-windows-x64.7z
unzip android-ndk-r17b-windows-x86_64.zip
unzip ninja-win.zip

set PATH=%PATH%;C:\Users\you\droid\cmake-3.11.4-win64-x64\bin;C:\Users\you\droid\ldc2-1.11.0-windows-x64\bin;C:\Users\you\droid

ldmd2 --version   # run this to check that ldc is in your path

set CC=C:\Users\you\droid\android-ndk-r17b\toolchains\llvm\prebuilt\windows-x86_64\bin\clang

ldc-build-runtime --ninja --targetPreset=Android-arm --dFlags="-w;-mcpu=cortex-a8" --buildDir=droid32

ldc-build-runtime --ninja --targetPreset=Android-aarch64 --buildDir=droid64

set NDK=C:\Users\you\droid\android-ndk-r17b

Mac

Download CMake, the zip file for the Android NDK, the latest ldc, and either Make or Ninja (the following instructions assume Ninja). CMake and Ninja can be installed from a package manager like Homebrew, but I'll show the manual install here. Make sure unzip is available to unpack the NDK and tar for everything else. After unpacking, add these tools to your path, including setting the path of the NDK and its C cross-compiler, and run ldc-build-runtime.

cd droid   # assuming all the zip and tar files have been placed in a folder called droid

tar xf cmake-3.11.4-Darwin-x86_64.tar.gz
tar xf ldc2-1.11.0-osx-x86_64.tar.xz
unzip android-ndk-r17b-darwin-x86_64.zip
unzip ninja-mac.zip

export PATH=$PATH:/Users/you/droid/cmake-3.11.4-Darwin-x86_64/CMake.app/Contents/bin:/Users/you/droid/ldc2-1.11.0-osx-x86_64/bin:/Users/you/droid

ldmd2 --version   # run this to check that ldc is in your path

export CC=/Users/you/droid/android-ndk-r17b/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang

ldc-build-runtime --ninja --targetPreset=Android-arm --dFlags="-w;-mcpu=cortex-a8" --buildDir=droid32

ldc-build-runtime --ninja --targetPreset=Android-aarch64 --buildDir=droid64

export NDK=/Users/you/droid/android-ndk-r17b
export HOST=darwin-x86_64

linux

Install needed packages, including optionally Ninja, as shown here for Ubuntu. You will need tar to unpack ldc and unzip for the NDK. Add ldc to your path and export the path of the NDK and its C cross-compiler, as shown here for bash, and run ldc-build-runtime.

sudo apt-get install cmake curl ninja-build unzip

curl -L -O https://dl.google.com/android/repository/android-ndk-r17b-linux-x86_64.zip

unzip android-ndk-r17b-linux-x86_64.zip

curl -L -O https://github.com/ldc-developers/ldc/releases/download/v1.11.0/ldc2-1.11.0-linux-x86_64.tar.xz

tar xf ldc2-1.11.0-linux-x86_64.tar.xz
export PATH=$PATH:/path/to/your/ldc2-1.11.0-linux-x86_64/bin

ldmd2 --version   # check that ldc is in your path

export CC=/path/to/your/android-ndk-r17b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang

ldc-build-runtime --targetPreset=Android-arm --dFlags="-w;-mcpu=cortex-a8" --buildDir=droid32

ldc-build-runtime --targetPreset=Android-aarch64 --buildDir=droid64

export NDK=/path/to/your/android-ndk-r17b
export HOST=linux-x86_64

Set environment variables

The environment variables vary based on whether you want to target 32-bit or 64-bit ARM.

32-bit ARM

On linux or macOS:

export TRIPLE=armv7-none-linux-androideabi
export DFLAGS="-mtriple=$TRIPLE -mcpu=cortex-a8"
export LIBDIR=droid32

export NDK_ARCH=arch-arm
export NDK_LINKER=arm-linux-androideabi-4.9
export APK_DIR=armeabi-v7a

On Windows:

set TRIPLE=armv7-none-linux-androideabi
set DFLAGS=-mtriple=%TRIPLE% -mcpu=cortex-a8
set LIBDIR=droid32

set NDK_ARCH=arch-arm
set NDK_LINKER=arm-linux-androideabi-4.9
set APK_DIR=armeabi-v7a
64-bit ARM

On linux/macOS:

export TRIPLE=aarch64-none-linux-android
export DFLAGS="-mtriple=$TRIPLE"
export LIBDIR=droid64

export NDK_ARCH=arch-arm64
export NDK_LINKER=aarch64-linux-android-4.9
export APK_DIR=arm64-v8a

On Windows:

set TRIPLE=aarch64-none-linux-android
set DFLAGS=-mtriple=%TRIPLE%
set LIBDIR=droid64

set NDK_ARCH=arch-arm64
set NDK_LINKER=aarch64-linux-android-4.9
set APK_DIR=arm64-v8a
Set path to runtime

Finally, set the path to the runtime libraries you just built:

# On linux
export RTDIR=/path/to/your/$LIBDIR

# On Mac
export RTDIR=/Users/you/droid/$LIBDIR

# On Windows
set RTDIR=C:\Users\you\droid\%LIBDIR%

Native compilation

Just install ldc from the Termux app, which will automatically pull in the clang compiler and a linker, as ldc tries to use the local C compiler for linking.

apt install ldc

These instructions show you how to compile a GUI app for your device, but you'll need to know whether you're running 32-bit or 64-bit ARM. Run

uname -m

in Termux and if it says aarch64, you're running 64-bit ARM. armv7l means you're running 32-bit ARM.

Note that you should pass the -mcpu=cortex-a8 flag to ldc when compiling for 32-bit Android/ARM, even though the few samples below don't require it. See the explanation above in the Cross-compilation section for more details.

Set the APK_DIR environment variable to the right platform for your device:

32-bit ARM

export APK_DIR=armeabi-v7a

64-bit ARM

export APK_DIR=arm64-v8a

Build a command-line executable

Now that we have a D compiler and runtime libraries for Android, let's try building a small program, the classic Sieve of Eratosthenes single-core benchmark, which finds all prime numbers up to a number you choose. Install the curl package in Termux if you're natively compiling, apt install curl.

# Load this link in your browser and download the file otherwise 
curl -L -O
https://raw.githubusercontent.com/dlang/dmd/master/samples/sieve.d

# On linux/macOS
ldmd2 -L-L$RTDIR/lib -Xcc=--sysroot=$NDK/platforms/android-21/$NDK_ARCH
-Xcc=-fuse-ld=bfd -Xcc=-gcc-toolchain
-Xcc=$NDK/toolchains/$NDK_LINKER/prebuilt/$HOST
-Xcc=-target -Xcc=$TRIPLE -Xcc=-fpie -Xcc=-pie sieve.d

# On 64-bit Windows
ldmd2 -L-L%RTDIR%\lib -Xcc=--sysroot=%NDK%\platforms\android-21\%NDK_ARCH%
-Xcc=-fuse-ld=bfd.exe -Xcc=-gcc-toolchain
-Xcc=%NDK%\toolchains\%NDK_LINKER%\prebuilt\windows-x86_64
-Xcc=-target -Xcc=%TRIPLE% -Xcc=-fpie -Xcc=-pie sieve.d

# Natively compiling in the Termux app for Android
ldmd2 sieve.d

Cross-compilation

Copy this sieve program onto an Android device or emulator and set its permissions with the chmod command. Here's how I do it in Termux, with an ssh server running on the host PC/Mac with IP address 192.168.1.37:

apt install openssh
cd
scp jo@192.168.1.37:sieve .
chmod 700 sieve

Run the sieve program

The sieve program will tell you how many prime numbers there are in the first n integers, a limit you can specify. Run this command to find how many primes there are in the first million integers:

./sieve 1000000

If you built sieve successfully, it should return

78498 primes

Build a sample OpenGL ES 1.0 GUI app ported to D

Clone my android repository or download its source in a zip file, which contains several headers and sample OpenGL apps from the NDK translated to D, and build the Native Activity app, which is written completely in D. As you'll see below, D code for an apk must be compiled to a shared library, which the Android runtime will call.

On linux or the Termux app, you can just clone my git repo (the same can be done on Mac and Windows if you install git first):

sudo apt-get install git # In Termux, apt install git

git clone https://github.com/joakim-noah/android.git

cd android/

Otherwise, simply get and unpack the zip file:

curl -L -O https://github.com/joakim-noah/android/archive/build.zip

unzip build.zip
cd android-build/

After getting the source, go to the sample app, compile the D source, then link the objects into a shared library and place it in the right directory for your platform.

cd samples/native-activity/

ldmd2 -I../../ -c jni/main.d

ldmd2 -I../../ -c ../../android/sensor.d

ldmd2 -I../../ -c ../../android_native_app_glue.d

mkdir -p libs/$APK_DIR/   # On Windows, mkdir libs\%APK_DIR%

# On linux/macOS
$CC -Wl,-soname,libnative-activity.so -shared --sysroot=$NDK/platforms/android-21/$NDK_ARCH
main.o sensor.o android_native_app_glue.o $RTDIR/lib/libphobos2-ldc.a
$RTDIR/lib/libdruntime-ldc.a -gcc-toolchain
$NDK/toolchains/$NDK_LINKER/prebuilt/$HOST -fuse-ld=bfd -target $TRIPLE -llog -landroid -lEGL -lGLESv1_CM
-o libs/$APK_DIR/libnative-activity.so

# On 64-bit Windows
%CC% -Wl,-soname,libnative-activity.so -shared --sysroot=%NDK%\platforms\android-21\%NDK_ARCH%
main.o sensor.o android_native_app_glue.o %RTDIR%\lib\libphobos2-ldc.a
%RTDIR%\lib\libdruntime-ldc.a -gcc-toolchain
%NDK%\toolchains\%NDK_LINKER%\prebuilt\windows-x86_64 -fuse-ld=bfd.exe -target
%TRIPLE% -llog -landroid -lEGL -lGLESv1_CM
-o libs\%APK_DIR%\libnative-activity.so

# In Termux
mkdir -p lib/$APK_DIR/

$PREFIX/bin/clang -Wl,-soname,libnative-activity.so -shared main.o sensor.o
android_native_app_glue.o $PREFIX/lib/libphobos2-ldc.a $PREFIX/lib/libdruntime-ldc.a
-llog -landroid -lEGL -lGLESv1_CM -o lib/$APK_DIR/libnative-activity.so

Cross-compilation

Finally, package the app as the SDK directs: at this point, it's just like building a regular Android app. I document the older Ant approach, which is deprecated, replace it with the Gradle command from a newer SDK. With Ant on Mac or linux, set the path to your SDK, then run these commands:

export SDK=/path/to/your/android-sdk
$SDK/tools/android update project -p . -s --target 1
ant debug

Transfer the resulting bin/NativeActivity-debug.apk to your Android device, again shown here by using scp from the Termux app.

scp jo@192.168.1.37:android/samples/native-activity/bin/NativeActivity-debug.apk /sdcard/Download/

Native compilation

Follow the instructions below to package this native shared library into an Android apk.

Install and run the sample GUI app

Go to Settings->Security on your Android device and allow installation of apps from unknown sources, ie from outside the Play Store, then go to /sdcard/Download in your file manager and choose the NativeActivity-debug apk to install it. Open the app after installing or go to your app folder and run the app named NativeActivity: it'll show a black screen initially, then flash a bunch of colors when the screen is touched.

Build a sample OpenGL ES 2.0 GUI app mostly written in D, with some Java

This D app has not been ported to 64-bit Android/ARM yet, only 32-bit ARM compilation will work for now.

The app comes with a simple build script, which will build the D shared library for you, as long as the environment variables are set.

cd samples/Teapot/

# On linux/macOS
./build-apk

# On 64-bit Windows
call build-apk.bat

Here are the contents of that script, so you can see what it's doing. The Windows version, build-apk.bat, and the linux/macOS version, build-apk, only differ on the final link command, which I've pasted below.

ldmd2 -I../../ -c ../../ndk_helper/GLContext.d
ldmd2 -I../../ -c ../../ndk_helper/JNIHelper.d
ldmd2 -I../../ -c ../../ndk_helper/gestureDetector.d
ldmd2 -I../../ -c ../../ndk_helper/perfMonitor.d
ldmd2 -I../../ -c ../../ndk_helper/shader.d
ldmd2 -I../../ -c ../../ndk_helper/tapCamera.d

ldmd2 -I../../ -Ijni/ -Jjni/ -c jni/TeapotNativeActivity.d
ldmd2 -I../../ -Jjni/ -c jni/TeapotRenderer.d
ldmd2 -I../../ -c ../../android/sensor.d

ldmd2 -I../../ -c ../../android_native_app_glue.d

mkdir -p libs/$APK_DIR/   # On Windows, mkdir libs\%APK_DIR%

# Link command on linux/macOS
$CC -Wl,-soname,libTeapotNativeActivity.so -shared
--sysroot=$NDK/platforms/android-21/$NDK_ARCH TeapotNativeActivity.o sensor.o
TeapotRenderer.o android_native_app_glue.o GLContext.o JNIHelper.o
gestureDetector.o perfMonitor.o shader.o tapCamera.o
$RTDIR/lib/libphobos2-ldc.a $RTDIR/lib/libdruntime-ldc.a -gcc-toolchain
$NDK/toolchains/$NDK_LINKER/prebuilt/$HOST -fuse-ld=bfd
-target $TRIPLE -llog -landroid -lEGL -lGLESv2
-o libs/$APK_DIR/libTeapotNativeActivity.so

# Link command on 64-bit Windows
%CC% -Wl,-soname,libTeapotNativeActivity.so -shared
--sysroot=%NDK%\platforms\android-21\%NDK_ARCH% TeapotNativeActivity.o sensor.o
TeapotRenderer.o android_native_app_glue.o GLContext.o JNIHelper.o
gestureDetector.o perfMonitor.o shader.o tapCamera.o
%RTDIR%\lib\libphobos2-ldc.a %RTDIR%\lib\libdruntime-ldc.a -gcc-toolchain
%NDK%\toolchains\%NDK_LINKER%\prebuilt\windows-x86_64 -fuse-ld=bfd.exe
-target %TRIPLE% -llog -landroid -lEGL -lGLESv2
-o libs/%APK_DIR%/libTeapotNativeActivity.so

mkdir -p lib/$APK_DIR/

# Link command in Termux
clang -Wl,-soname,libTeapotNativeActivity.so -shared
TeapotNativeActivity.o sensor.o TeapotRenderer.o
android_native_app_glue.o GLContext.o JNIHelper.o
gestureDetector.o perfMonitor.o shader.o
tapCamera.o $PREFIX/lib/libphobos2-ldc.a
$PREFIX/lib/libdruntime-ldc.a -llog -landroid
-lEGL -lGLESv2 -o lib/$APK_DIR/libTeapotNativeActivity.so

Cross-compilation

Package this shared library into an apk by using the SDK, as you would normally, and try installing and running it on your device.

Native compilation

Install the right Eclipse Java compiler package for your device (the ecj4.6 package if you're running Android 5 or 6), the Android dex tool, and other packages needed to build an Android apk. Generate any Java files needed, compile and dex them, then package everything up into an apk and sign it.

apt install ecj dx aapt apksigner

aapt package  -M ./AndroidManifest.xml -I $PREFIX/share/java/android-21.jar -J src/ -S res -m

ecj-21 -d ./obj -sourcepath src $(find src -type f -name "*.java")

dx --dex --output=./classes.dex ./obj/

aapt package  -M ./AndroidManifest.xml -S res -A assets -F teapot.apk

aapt add teapot.apk classes.dex lib/$APK_DIR/libTeapotNativeActivity.so

apksigner debug.ks teapot.apk teapot-signed.apk

Finally, move teapot-signed.apk into a public directory, from which you can install and run it.

Changes for Android

Now that you've seen some examples, here's a description of changes to D that have been made for Android.

The Android environment doesn't support native Thread-Local Storage (TLS), which is integral to D, since all static and global variables not explicitly marked shared/__gshared/immutable are thread-local by default in D. The Android D runtime supports emulated TLS instead, but this requires some changes to the build process:

  1. You must use the ld.bfd linker- see the use of -fuse-ld=bfd above- ld.gold won't do.
  2. You must have a D main function, even for a shared library. An empty D main can be put next to android_main, if you're using the default Android wrapper from my D android repo.
  3. The ELF object with the D main function must be passed to the linker first.

All the examples above follow these rules, which are in place to make sure emulated TLS data is properly passed to the D garbage-collector.

If building a shared library and not a D command-line executable, you must also initialize and exit the D runtime by calling rt_init() and rt_term() before and after all D code is run, as has been done in the default Android wrapper (rt_init/rt_term are automatically inserted and run for a D executable). Running multiple D shared libraries is currently unsupported on Android, only a single D shared library that statically links against the D runtime will work.

Package an Android app from scratch on your Android device

Install aapt, the Android Asset Packaging Tool, and apksigner, a tool to create a hashed manifest and sign your apps.

apt install aapt apksigner

I'll demonstrate with the NativeActivity app built above.

cd samples/native-activity/
aapt package -M AndroidManifest.xml -S res -F NativeActivity-debug-unsigned.apk
aapt add NativeActivity-debug-unsigned.apk lib/$APK_DIR/libnative-activity.so

This simple app only requires three files, AndroidManifest.xml, resources.arsc, and lib/$APK_DIR/libnative-activity.so, which you can check with the following aapt command.

aapt list NativeActivity-debug-unsigned.apk

Now let's generate a hashed manifest, just like a Java jar file, and sign the app. If you have your own Java Keystore already, just supply it to apksigner. If not, apksigner will generate a self-signed Keystore file, which we name debug.ks below, which is good enough to sign and install debug apps on your own Android device.

apksigner debug.ks NativeActivity-debug-unsigned.apk NativeActivity-debug.apk

You should see three additional files in the apk, if you list its contents using the command above. At this point, you can install and run the signed app on your own device. If you modify the app, you'll need to build the manifest and sign it again: make sure you use the debug.ks you created before or Android won't allow you to reinstall the same app with a newly generated key, unless you first uninstall the app.

Sign your app using a certificate and OpenSSL

Unfortunately, apksigner only supports Java Keystore files for signing right now and I don't know how to build one from scratch, so if you don't have a keystore and want to release your app to an app store, you'll have to use OpenSSL to sign the app.

For a valid certificate for the final release, there's plenty of information online on how to generate one. I'll just show how to create a self-signed certificate for debugging purposes.

First, install the OpenSSL package in Termux. Then, this OpenSSL command will generate a self-signed debug certificate, apk.cert, and a 2048-bit RSA private key, key.pem, which isn't encrypted with a password. It will ask you for some signing info, for which I've shown what's used by the debug certificate in the Android SDK, but it doesn't matter what you enter, as it's ignored:

apt install openssl-tool

openssl req -x509 -nodes -newkey rsa:2048 -keyout key.pem -out apk.cert

....................................+++
writing new private key to 'key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Android
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:Android Debug
Email Address []:

Now that we have a certificate- self-signed in this case, use your actual release certificate if you want to release the app- and private key, we use them to sign the app. Since the apk is just a zip file, unzip it into a directory and use OpenSSL to generate a new signature file, CERT.RSA, then update the apk with the new signature, and copy the apk to a public user directory from which you can install it:

mkdir unpack
cd unpack/
unzip ../NativeActivity-debug.apk

cd META-INF/
openssl smime -sign -md sha1 -binary -noattr -in CERT.SF -out CERT.RSA -outform der -inkey ../../key.pem -signer ../../apk.cert

cd ..
aapt remove ../NativeActivity-debug.apk META-INF/CERT.RSA
aapt add ../NativeActivity-debug.apk META-INF/CERT.RSA

cd ..
cp NativeActivity-debug.apk /sdcard/Download/

The OpenSSL commands to generate a certificate and sign the apk were taken from this 2012 blog post, you can follow it further to see what the signature consists of and verify it for yourself. This 2013 blog post was critical for me to understand how apk signing works, I used to run all those commands by hand until the apksigner package was added to the Termux package repo.

Directions for future work

  • I'm working on getting rid of the three requirements for emulated TLS, by changing the way it's initialized on Android.
  • Integrate the linux shared library support in druntime's rt.sections_elf_shared, so that multiple D shared libraries can be used.