After a bit of fiddling, I managed to get a native binary executable file, cross-compiled from Nim source code, which runs on my Android phone running Android 8.0 (Oreo).

Figured someone would find it useful to see how I did it, although there's probably a cleaner way to do it than what I ended up doing. This was rather just thrown together in a way that I found worked, so bear that in mind. x')

Hopefully this can also help the Nim developers make cross-compiling a Nim program for Android easier to do.

I'll also note that I did this from a Windows x64 machine.

Disclaimer: You follow these instructions at your own risk, etc... Not my fault if you brick your device fiddling with it.

  • Download the Android NDK onto your machine. Open a terminal, change into its build/tools subdirectory and run:

make_standalone_toolchain.py --arch=arm64 --install-dir=../../../android-toolchain --api 27
This will have created the android-toolchain directory in the same location where you put the NDK.

Note that the number given for api is the minimum Android API level that your app will target.

  • Compile your Nim code into C source files. A simple 'Hello World' program in my case:

nim c --os:android --cpu=arm64 --compileOnly hello.nim

  • Create the executable using the NDK's clang command. In a terminal, change into the android-toolchain/bin directory and run:

clang -I../sysroot/usr/include -I/path/to/nim/installation/lib -fPIE -pie -o /path/to/output/hello.bin path/to/nimcache/hello.c /path/to/nimcache/stdlib_system.c
This generated 19 warnings for me, but it still ran just fine in the end. Note that I've specified all the C files manually here, but you could do *.c if you ensure that you clean the nimcache every time.

I am compiling manually via C here because Nim calls out to clang.exe or gcc.exe and cannot be told to call the clang.cmd as we need to here, so far as I could tell.

I tried using a config file like 'hello.nim.cfg' to config this but I was not able to get that to work.

At any rate, you should now have an executable binary file that runs on Android ARM64.

Unfortunately, I can only tell you how to run it on real hardware. You can do that like this:

  • Enable 'USB Debugging' on your phone, and install your phone's USB drivers which came with your phone.
  • Upload the binary to your phone.

adb push hello.bin /data/local/tmp/hello.bin

  • Set the executable bit on your executable, and run it.

adb shell
$ chmod +x /data/local/tmp/hello.bin
$ /data/local/tmp/hello.bin
Hello World!
$

If your program segfaults but you know that it's not your Nim code's fault, try removing the '-fPIE -pie' from the clang complication step; particularly if you have a very old version of Android. Position independant code was not originally supported, IIRC.

Hopefully there will be an easier, cleaner, way to do this in the future! xD

2018-02-24 02:50:40

Thank you, I did different approach. I followed from this stackoverflow thread about cross compiling https://stackoverflow.com/questions/16795583/android-error-cannot-open-crtbegin-dynamic-o-no-such-file-or-directory

I was stuck because I added sysroot option to the compiler when compiling C and after I looked your example, I realized I need to add --compileOnly to Nim compiler and do compiling as usual


For completeness, this is what I did

> set PATH=%PATH%;/my-installed-ndk/toolchains/arm-linux-android-eabi-4.9/prebuilt/windows-x86_64/bin
> nim --cpu:arm --os:android --compileOnly hello.nim
> cd nimcache
> arm-linux-androideabi-gcc.exe -I my-installed-nim-folder/lib hello.c stdlib_system.c -o hello --sysroot=my-installed-ndk/platforms/android-19/arch-arm
> adb root     # starting adb server, make sure adb.exe in PATH
> adb push hello /data/local/tmp
> adb shell
$ su
# cd /data/local/tmp
# chmod 755 hello
# ./hello
cross compiled hello

I cross-compiled from Windows 10 64 bit too and targeting android-19 (4.4)

2018-03-09 08:37:29

Hi,

I tried last example. Unfortunately doesn't work for me.

C:\Users\uname\Documents\nimapps\jnijava\nimcache>arm-linux-androideabi-gcc.exe -I C:\Nim\lib hello.c stdlib_system.c -o hello --sysroot=C:\Users\uname\Documents\apps\android-ndk-r16b\platforms\android-19\arch-arm
In file included from c:\users\uname\documents\apps\android-ndk-r16b\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9.x\include-fixed\syslimits.h:7:0,
               from c:\users\uname\documents\apps\android-ndk-r16b\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9.x\include-fixed\limits.h:34,
               from C:\Nim\lib/nimbase.h:255,
               from hello.c:7:
c:\users\uname\documents\apps\android-ndk-r16b\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9.x\include-fixed\limits.h:168:61: error: no include path in which to search for limits.h
 #include_next <limits.h>  /* recurse down to the real one */
                                                           ^
In file included from c:\users\uname\documents\apps\android-ndk-r16b\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9.x\include-fixed\syslimits.h:7:0,
               from c:\users\uname\documents\apps\android-ndk-r16b\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9.x\include-fixed\limits.h:34,
               from C:\Nim\lib/nimbase.h:255,
               from stdlib_system.c:7:
c:\users\uname\documents\apps\android-ndk-r16b\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9.x\include-fixed\limits.h:168:61: error: no include path in which to search for limits.h
 #include_next <limits.h>  /* recurse down to the real one */
                                                           ^
stdlib_system.c:8:20: fatal error: setjmp.h: No such file or directory
 #include <setjmp.h>
                  ^
compilation terminated.

What I do wrong? Could you please help...

2018-03-19 14:58:15

Have you tried / in path string instead of \ as path separator ?

Also you can try adding ".

Very likely because you were using \ so gcc couldn't find the correct path. See my example above all using /.

2018-03-19 15:34:15

Hi mashingan,

thank you for suggestion and I tried all this /," and // possibilities but errors are the same.

any other suggestions? maybe I have not prepared some things...

2018-03-20 09:59:44

Could you give the command-line you typed?

For example, what I did was like this

arm-linux-androideabi-gcc.exe -I "C:/Nim/lib" hello.c stdlib_system.c -o hello --sysroot="C:/Users/uname/Documents/apps/android-ndk-r16b/platforms/android-19/arch-arm"

2018-03-20 11:06:05
> cd C:\Users\uname\Documents\nimapps\jnijava\
> set PATH=%PATH%;C:\Users\uname\Documents\apps\android-ndk-r16b\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin
> nim c --cpu:arm --os:android --compileOnly hello.nim
> cd nimcache
> arm-linux-androideabi-gcc.exe -I "C:/Nim/lib" hello.c stdlib_system.c -o hello --sysroot="C:/Users/uname/Documents/apps/android-ndk-r16b/platforms/android-19/arch-arm"

2018-03-20 12:03:12

Hi mashingan,

I tried cross-compile the same hello.nim from linux and got the same errors exactly like in windows.

what I did:

  1. Cloned nim-lang branch master from github and compled it.
  2. Downloaded android ndk
  3. Defined all needed paths in PATH
  4. Compile hello.nim: nim c --cpu:arm --os:android --compileOnly hello.nim
  5. Compile with arm-linux-androideabi-gcc.exe
2018-03-20 15:27:37

Hmm, I'm not sure, all I can say is the cross compiler cannot find the sysroot

This the exact command line I did and it success

\nimcache>arm-linux-androideabi-gcc -I d:/installer/nim/lib hello_android.c stdlib_system.c -o hello --sysroot=e:/installer/android/ndk/platforms/android-19/arch-arm

Before I did failed like what you had but because I wrote the sysroot wrong, before I wrote it --sysroot=e:/installer/ndk/platforms/android-19/arch-arm , but after recompiled with correct path, it compiled successfully.

My Nim version is still 0.17.2, 64 bit (haven't had a chance to try 0.18.0)

My arm-linux-androideabi-gcc version and its path dependency

arm-linux-androideabi-gcc -v
Using built-in specs.
COLLECT_GCC=arm-linux-androideabi-gcc
COLLECT_LTO_WRAPPER=e:/installer/android/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/bin/../libexec/gcc/arm-linux-androideabi/4.9.x/lto-wrapper.exe
Target: arm-linux-androideabi
Configured with: /usr/local/google/buildbot/src/android/gcc/toolchain/build/../gcc/gcc-4.9/configure --prefix=/tmp/54f254f8bb7b48dd787052921220a87d --target=arm-linux-androideabi --host=x86_64-pc-mingw32msvc --build=x86_64-linux-gnu --with-gnu-as --with-gnu-ld --enable-languages=c,c++ --with-gmp=/buildbot/tmp/build/toolchain/temp-install --with-mpfr=/buildbot/tmp/build/toolchain/temp-install --with-mpc=/buildbot/tmp/build/toolchain/temp-install --with-cloog=/buildbot/tmp/build/toolchain/temp-install --with-isl=/buildbot/tmp/build/toolchain/temp-install --with-ppl=/buildbot/tmp/build/toolchain/temp-install --disable-ppl-version-check --disable-cloog-version-check --disable-isl-version-check --enable-cloog-backend=isl --with-host-libstdcxx='-static-libgcc -static-libstdc++ -lstdc++ -lm -static' --disable-libssp --enable-threads --disable-nls --disable-libmudflap --disable-libgomp --disable-libstdc__-v3 --disable-sjlj-exceptions --disable-shared --disable-tls --disable-libitm --with-float=soft --with-fpu=vfp --with-arch=armv5te --enable-target-optspace --enable-bionic-libs --enable-libatomic-ifuncs=no --enable-initfini-array --disable-nls --prefix=/tmp/54f254f8bb7b48dd787052921220a87d --with-sysroot=/tmp/54f254f8bb7b48dd787052921220a87d/sysroot --with-binutils-version=2.25 --with-mpfr-version=3.1.1 --with-mpc-version=1.0.1 --with-gmp-version=5.0.5 --with-gcc-version=4.9 --with-gdb-version=none --with-gxx-include-dir=/tmp/54f254f8bb7b48dd787052921220a87d/include/c++/4.9.x --with-bugurl=http://source.android.com/source/report-bugs.html --enable-languages=c,c++ --disable-bootstrap --enable-plugins --enable-libgomp --enable-gnu-indirect-function --disable-libsanitizer --enable-gold --enable-eh-frame-hdr-for-static --enable-graphite=yes --with-isl-version=0.11.1 --with-cloog-version=0.18.0 --with-arch=armv5te --program-transform-name='s&^&arm-linux-androideabi-&' --enable-gold=default
Thread model: posix
gcc version 4.9.x 20150123 (prerelease) (GCC)

My system is Windows 10 64 bit

2018-03-20 16:01:38

Hi

finelly is works!

I tried the way suggested Tetralux via make_standalone_toolchain.py and then clang.

Simple echo works, but I tried simple pow from math and clang doesn't compile it:

import math

var a = pow(5.09, 2.33)

clang -I ../sysroot/usr/include -I C:/Nim/lib -fPIE -pie -o C:/Users/uname/Documents/nimapps/jnijava/hello.bin C:/Users/uname/Documents/nimapps/jnijava/nimcache/*.c

...and get error:

\nimcache\hello.c:function NimMainModule: error: undefined reference to 'pow'
clang50.exe: error: linker command failed with exit code 1 (use -v to see invocation)
2018-03-21 10:32:11
<<<••12••>>>