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 27This 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.cThis 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
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)
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...
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 /.
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...
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"
> 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"
Hi mashingan,
I tried cross-compile the same hello.nim from linux and got the same errors exactly like in windows.
what I did:
- Cloned nim-lang branch master from github and compled it.
- Downloaded android ndk
- Defined all needed paths in PATH
- Compile hello.nim: nim c --cpu:arm --os:android --compileOnly hello.nim
- Compile with arm-linux-androideabi-gcc.exe
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
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)