A lot has changed since my previous article, on Android C native development, back in 2009.
The Android NDK has been released and the JNI development is not only possible, but also easy. Have a look on this article on the Android NDK.
The new challenge is to use the NDK to compile Native ARM-EABI executables that would run on an Android phone. I don't want to setup the complete Google Android source code as I did in my first article.
This is possible, and I will provide the steps to do it:
Step 1. Install the NDK
Step 2. Install Cygwin
(as presented in the Android NDK Article)
While this guide is for Windows, you can easily adapt the following for a Linux box or a Mac.
Create a simple C code file, test.c
#include <stdio.h> int main() { printf("Hello Google Android world!/nwww.pocketmagic.net/n"); return 1; exit(0); }
Find the following locations:
NDK_ROOT (eg. D:/work_code/android/android-ndk-r4b/ )
NDK_ROOT/build/platforms/
NDK_ROOT/build/prebuilt/windows/arm-eabi-4.2.1/
You will need them.
When starting Cygwin using the Cygwin.bat BATCH File, make sure you define the PATH to the Android NDK:
set PATH=D:/work_code/android/android-sdk-windows/tools;D:/work_code/android/android-ndk-r4b;D:/work_code/android/android-ndk-r4b/build/prebuilt/windows/arm-eabi-4.2.1/bin/;$PATH;D:/work_code/android/android-ndk-r4b/build/platforms/android-5/arch-arm/usr/lib/;
Step 3. If you read my Android NDK article, you already know the NDK folder contains the ndk-build script, that is used to compile the JNI code.
We will build a similar script, to compile our test.c code file.
Let's call this file ndk-comp and place it where ndk-build is.
#!/bin/sh OS='windows' ANDROIDSDK='android-3' PROGDIR=`dirname $0` PROGDIR=`cd $PROGDIR && pwd` ARMEABIGCC=$PROGDIR/build/prebuilt/$OS/arm-eabi-4.2.1/bin/arm-eabi-gcc ARMEABILIB=$PROGDIR/build/platforms/$ANDROIDSDK/arch-arm/usr/lib ARMEABIINC=$PROGDIR/build/platforms/$ANDROIDSDK/arch-arm/usr/include ARMEABICRT=$PROGDIR/build/platforms/$ANDROIDSDK/arch-arm/usr/lib/crtbegin_dynamic.o LINKER=/system/bin/linker echo "GCC:"$ARMEABIGCC "LIB:"$ARMEABILIB "LINKER":$LINKER "PARAMS:"$@ $ARMEABIGCC $@ -Wl,-rpath-link=$ARMEABILIB,-dynamic-linker=$LINKER -L$ARMEABILIB $ARMEABICRT -I$ARMEABIINC -nostdlib -lc
If you did everything correctly, you should be able to call this script from within Cygwin's shell. Using cd command, navigate in Cygwin shell to the test.c folder. Compile it using ndk-comp -o test test.c :
As you can see, running it on the device using ADB works. Here is another picture showing the executable started using the Terminal app, directly on the Android smartphone:
It works well.
There is another even better way of compiling native C apps for Android using the NDK, as presented by Mamadou on his blog.
You can create a Makefile in the same folder with test.c then navigate there with the Cygwin shell and run make.
The Makefile is as follows:
APP := test ROOT:=/cygdrive/d/work_code/android NDK_PLATFORM_VER := 3 INSTALL_DIR := /data/tmp ANDROID_NDK_ROOT:=$(ROOT)/android-ndk-r4b ANDROID_NDK_HOST:=windows ANDROID_SDK_ROOT:=$(ROOT)/android-sdk-windows PREBUILD:=$(ANDROID_NDK_ROOT)/build/prebuilt/$(ANDROID_NDK_HOST)/arm-eabi-4.4.0 BIN := $(PREBUILD)/bin CPP := $(BIN)/arm-eabi-g++ CC := $(BIN)/arm-eabi-gcc CFLAGS := -I$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/include LDFLAGS := -Wl,--entry=main,-rpath-link=$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/lib,-dynamic-linker=/system/bin/linker -L$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/lib LDFLAGS += -nostdlib -lc -disable-multilib all: $(APP) OBJS += $(APP).o $(APP): $(OBJS) $(CPP) $(LDFLAGS) -o $@ $^ %.o: %.c $(CC) -c $(INCLUDE) $(CFLAGS) $< -o $@ install: $(APP) $(ANDROID_SDK_ROOT)/tools/adb push $(APP) $(INSTALL_DIR)/$(APP) $(ANDROID_SDK_ROOT)/tools/adb shell chmod 777 $(INSTALL_DIR)/$(APP) shell: $(ANDROID_SDK_ROOT)/tools/adb shell run: $(ANDROID_SDK_ROOT)/tools/adb shell $(INSTALL_DIR)/$(APP) r: $(APP) $(ANDROID_SDK_ROOT)/tools/adb push $(APP) $(INSTALL_DIR)/$(APP) $(ANDROID_SDK_ROOT)/tools/adb shell chmod 777 $(INSTALL_DIR)/$(APP) $(ANDROID_SDK_ROOT)/tools/adb shell $(INSTALL_DIR)/$(APP) clean: @rm -f $(APP).o $(APP)
Makefile
If you copy paste this, make sure you replace the spaces before "$(CPP) $(LDFLAGS.." and the other paragraphs with one TAB. Not doing so will result in an error:
$ make Makefile:24: *** missing separator. Stop. ITX@itxserv /cygdrive/d/work_code/android/TBTS/Native
If everything is in place, you can use the following defined commands:
make clean - will delete all object files and prepare for a new build
make - will compile your code
make r - copies the compiled binary to your Android device, it sets executable permissions and launches it.
For some reason this binary produces a segmentation fault, just before it terminates. I didn;t have the time to look into this, but Mamadou also had the error. For the moment I'd suggest you stick to my first script.