In this post I will explain how to compile, install and debug an Android native "C" application.
If you are reading this post just because you have googled the magic keywords ("android" + "native code") then you should know that there is an easier way to build native applications using android makefiles ("Android.mk" and "Application.mk").
The method I'm describing here is only useful if you want to understand how things work in order to create more complex standard GNU makefiles. This is also useful if you would like to create your own GNU autotools wrappers to compile projects using GNU configure.
I'm using Windows Vista as host machine but any other supported platforms (e.g. linux-x86 or darwin-x86) should work.
If you are reading this post just because you have googled the magic keywords ("android" + "native code") then you should know that there is an easier way to build native applications using android makefiles ("Android.mk" and "Application.mk").
The method I'm describing here is only useful if you want to understand how things work in order to create more complex standard GNU makefiles. This is also useful if you would like to create your own GNU autotools wrappers to compile projects using GNU configure.
I'm using Windows Vista as host machine but any other supported platforms (e.g. linux-x86 or darwin-x86) should work.
I have tested both the NDK (1.6) and SDK (2.1) on:
- Windows XP (32-bit) and Vista (64-bit)
- Mac OS X Snow Leopard
- Ubuntu Intrepid
To download the latest Android SDK, visit this address http://developer.android.com/sdk/index.html.
If you need information on how to install the SDK, visit this address http://developer.android.com/sdk/installing.html.
If the "SDK setup" fail to update the installed packages you can change the remote site URL from https://dl-ssl.google.com/android/repository/repository.xml to http://dl-ssl.google.com/android/repository/repository.xml (change the URL scheme from HTTPS to HTTP) or try to disable your anti-virus or firewall.
I have installed the SDK version 2.1 under c:/android-sdk (a.r.a /cygdrive/c/android-sdk).
Add an environment variable named ANDROID_SDK_ROOT pointing to the SDK root directory.
If you need information on how to install the SDK, visit this address http://developer.android.com/sdk/installing.html.
If the "SDK setup" fail to update the installed packages you can change the remote site URL from https://dl-ssl.google.com/android/repository/repository.xml to http://dl-ssl.google.com/android/repository/repository.xml (change the URL scheme from HTTPS to HTTP) or try to disable your anti-virus or firewall.
I have installed the SDK version 2.1 under c:/android-sdk (a.r.a /cygdrive/c/android-sdk).
Add an environment variable named ANDROID_SDK_ROOT pointing to the SDK root directory.
Important: You should add "$ANDROID_SDK_ROOT/tools" directory to the $PATH environment variable.
Under *nix:
export PATH=$ANDROID_SDK_ROOT/tools:$PATH
set PATH=%ANDROID_SDK_TOOLS%;%PATH%
If you are using Windows XP or Vista as host machine then you MUST install Cygwin Devel package with GNU Make (3.81 or later) before installing the NDK.
It should also work with MinGW.
Installing the Android NDK
To download the latest Android NDK, visit this address http://developer.android.com/sdk/ndk/1.6_r1/index.html.
I have uncompressed the NDK version 1.6 under c:/android-ndk (a.r.a /cygdrive/c/android-ndk).
Add an environment variable named ANDROID_NDK_ROOT pointing to the NDK root directory.
To install the NDK:
I have uncompressed the NDK version 1.6 under c:/android-ndk (a.r.a /cygdrive/c/android-ndk).
Add an environment variable named ANDROID_NDK_ROOT pointing to the NDK root directory.
To install the NDK:
cd $ANDROID_NDK_ROOT
build/host-setup.sh
To test that the toolchain has been correctly installed you can try to build the hello-jni sample which comes with the NDK by doing this:
cd $ANDROID_NDK_ROOT
make -APP=hello-jni
If all is OK then the console will print:
Android NDK: Building for application 'hello-jni'
Compile thumb : hello-jni <= sources/samples/hello-jni/hello-jni.c SharedLibrary : libhello-jni.so Install : libhello-jni.so => apps/hello-jni/project/libs/armeabi
Creating an AVD
AVD stands for Android Virtual Device and can be seen as a device profile (keyboard, dialing pad, skin, screen dimensions, appearance ...) to load into your emulator. You can create as many AVDs as you need.
To create an AVD named "avdtest" targeting platform 2.1 (targetID=android-7):
android create avd -n avdtest -t android-7
Created AVD 'avdtest' based on Android 2.1, with the following hardware config: hw.lcd.density=160
Here I will create a basic test.c file under C:\tmp with the following content:
#include
int main(int argc, char **argv)
{
int i = 1;
i+=2;
printf("Hello, world (i=%d)!\n", i);
return 0;
}
Just create an empty file named makefile (without any extension) under C:\tmp (which is the same directory as test.c).
Now We will fill the makefile step by step.
Add application name, $ROOT directory, install directory and the NDK platform version:
APP := test
ROOT:=/cygdrive/c
NDK_PLATFORM_VER := 1.5
INSTALL_DIR := /data/tmp
ANDROID_NDK_ROOT:=$(ROOT)/android-ndk
ANDROID_NDK_HOST:=windows
ANDROID_SDK_ROOT:=$(ROOT)/android-sdk
PREBUILD:=$(ANDROID_NDK_ROOT)/build/prebuilt/$(ANDROID_NDK_HOST)/arm-eabi-4.2.1
BIN := $(PREBUILD)/bin
Add GCC options:
CPP := $(BIN)/arm-eabi-g++
CC := $(BIN)/arm-eabi-gcc
CFLAGS :=
LDFLAGS := -Wl
- 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)
- clean:
- @rm -f $(APP).o $(APP)
To build the application, switch to the directory where you have created both files and then:
make
To resolve this issue, add the Bionic header files to $CFLAGS variable like this:
CFLAGS := -I$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/include
crt0.o: No such file: No such file or directory
LDFLAGS := -Wl -nostdlib
test.c:(.text+0x34): undefined reference to `printf'
test.c:(.text+0x3c): undefined reference to `exit'
LDFLAGS := -Wl -L$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/lib
LDFLAGS += -nostdlib -lc
/cygdrive/c/android-ndk/build/platforms/android-1.5/arch-arm/usr/lib/libc.so: undefined reference to `dl_unwind_find_exidx'
LDFLAGS := -Wl,-rpath-link=$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/lib -L$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/lib
/cygdrive/c/android-ndk/build/prebuilt/windows/arm-eabi-4.2.1/bin/../lib/gcc/arm
-eabi/4.2.1/../../../../arm-eabi/bin/ld: warning: cannot find entry symbol _start; defaulting to 000082c8
LDFLAGS := -Wl,--entry=main,-rpath-link=$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/lib -L$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/lib
LDFLAGS += -nostdlib -lc
Testing your application
Before testing your application you MUST run the emulator like this:
emulator -avd avdtest
To install the application on the emulator, open a new console and go to to directory where you have created test.c and makefile. Install your application on the emulator like this:
make install
/cygdrive/c/android-sdk/tools/adb push test /data/tmp/test
304 KB/s (2493 bytes in 0.008s)
/cygdrive/c/android-sdk/tools/adb shell chmod 777 /data/tmp/test
make run
/cygdrive/c/android-sdk/tools/adb shell /data/tmp/test
/data/tmp/test: not found
I spent hours searching and I found that this error happens because the loader fails to load the application because it cannot found a proper linker.
To specify a search directory for the dynamic linker (at run time) you MUST change the link options like this:
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
The console will print the expected result ("hello, world (i=3)!") but just after we have an segmentation fault error ("[1] Segmentation fault /data/tmp/test").
To resolve this issue you can exit the program (exit(0);) just before the main function returns (return 0;). You should also include
If you retry the build&&run process (make clean && make && make install && make run) then you should have:
/cygdrive/c/android-sdk/tools/adb shell /data/tmp/test
Hello, world (i=3)!
Debugging your application
Before doing anything you MUST copy the gdbserver file to the emultor.
This file is under $BIN ($ANDROID_NDK_ROOT/build/prebuilt/$ANDROID_NDK_HOST/arm-eabi-4.2.1/bin).
Copy gdbserver to the emulator like this:
adb push gdbserver $INSTALL_DIR/gdbserver
adb shell chmod 777 $INSTALL_DIR/gdbserver
Before running the server on port 1234 you MUST redirect all tcp connection to this port like this:
Now it's time to run the server:
If all is OK the the server will print something like this:
To generate debug symbols you MUST change the makefile like this (should not be hard coded like this):
Connect to the server (from the same console) like this:
The final makefile and test.c files are shown below:
adb forward tcp:1234: tcp:1234
Now it's time to run the server:
adb shell $INSTALL_DIR/gdbserver :1234 $INSTALL_DIR/$APP
If all is OK the the server will print something like this:
Process /data/tmp/test created; pid = 246
Listening on port 1234
- debug:
- $(GDB_CLIENT) $(APP)
GDB_CLIENT := $(BIN)/arm-eabi-gdb
To generate debug symbols you MUST change the makefile like this (should not be hard coded like this):
DEBUG = -g
CFLAGS := $(DEBUG) -I$(ANDROID_NDK_ROOT)/build/platforms/android-$(NDK_PLATFORM_VER)/arch-arm/usr/include
Connect to the server (from the same console) like this:
target remote :1234
b main
c
n
p i
#$1 = 1
n
#9 printf("Hello, world (i=%d)!\n", i);
p i
#$2 = 3
c
#Program exited normally.
The final makefile and test.c files are shown below:
- makefile
- 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)
- debug:
- $(GDB_CLIENT) $(APP)
- clean:
- @rm -f $(APP).o $(APP)
APP := test
ROOT:=/cygdrive/c
INSTALL_DIR := /data/tmp
NDK_PLATFORM_VER := 1.5
ANDROID_NDK_ROOT:=$(ROOT)/android-ndk
ANDROID_NDK_HOST:=windows
ANDROID_SDK_ROOT:=$(ROOT)/android-sdk
PREBUILD:=$(ANDROID_NDK_ROOT)/build/prebuilt/$(ANDROID_NDK_HOST)/arm-eabi-4.2.1
BIN := $(PREBUILD)/bin
GDB_CLIENT := $(BIN)/arm-eabi-gdb
DEBUG = -g
CPP := $(BIN)/arm-eabi-g++
CC := $(BIN)/arm-eabi-gcc
CFLAGS := $(DEBUG) -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
all: $(APP)
- test.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int i = 1;
i+=2;
printf("Hello, world (i=%d)!\n", i);
exit(0);
return 0;
}
27 commentaires:
Hi,
I want some help, I am following the steps given hear when I try to run the image I am getting following linker error
$ make
/cygdrive/c/android-ndk/build/prebuilt/windows/arm-eabi-4.2.1/bin/arm-eabi-g++ -Wl,--entry=main,-rpath-link=/cygdrive/c/android-ndk/build/platforms/android-1.5/arch-arm/usr/lib,-dynamic-link
er=/system/bin/linker -L/cygdrive/c/android-ndk/build/platforms/android-1.5/arch-arm/usr/lib -nostdlib -o test test.o
test.o: In function `main':
test.c:(.text+0x34): undefined reference to `printf'
test.o:(.ARM.exidx+0x0): undefined reference to `__aeabi_unwind_cpp_pr1'
collect2: ld returned 1 exit status
make: *** [test] Error 1
kreddy@SQAVISTA5 /cygdrive/c/temp
PLease let me know how to fix the probelm.
Thanks in advance.
-Kalyan.
Kaylan, the author mentions it in the tutorial...
to link against the c library add this to the LDFLAGS, e.g. i have:
"LDFLAGS += -lc -L$(NDK_ROOT)/build/platforms/android-4/arch-arm/usr/lib"
generally the tutorial is very very decent, to get to know how things work under the bonet but new users should try to learn how to use "make APP=myapp" first
Hi,
Very nice tutorial. Based on this, I was able to create a cmake platform file. Now the whole thing just compiles in the cmake way:
$ cmake .
$ make
Everything is nice!
Thank YOUUUUUUUUUUU!
Worked!!!!!!!!!!!!!!
Thank you very much for the wonderful tutorial. it helped me a lot. Could you please suggest if it's possible to use command line arguments in this application. If yes, could you suggest how?
Thanks a lot ones again.
Alright, let me try again... I will let you know soon, I hope it works, it will make my axim useful again :) Hope there was a way to use wireless and all those stuff, I am pretty knowledgable about the linux and stuff, but I don't know why this happens. Let's see.
Very good article. However the Segmention fault would need a fix. I've also put up a how-to-do-it article, and a script for using ARM-eabi-gcc directly:
http://www.pocketmagic.net/?p=1462
A great article. Thank you for showing not only the final solution but also the common pitfalls. Cheers,
Lukasz
All,
to fix the Segmentation Fault happening after returning from the main, the library crtend_android.o needs to be linked with the executable.
This library is located under $(ANDROID_NDK)/platforms/android-9/arch-arm/usr/lib
Enman SARL
Well, it still causes Segmentation faults...
Is there any workaround for this?
If using MinGW make sure to change /system/bin/linker to
//system/bin/linker
Thanks for the great tutorial
Hi,
As this has been asked by many and I also spent some time to get something compiled under Windows, here's how I got the example run using NDK r7 and no Cygwin - all this could be constructed from this blog post but this is a "complete" example:
Code as above:
#include
int main()
{
printf("Hello Google Android world!\n");
return 0;
}
NDK extracted under C:\ndk.
Compile command (a single line command of course, split here for better readability):
c:\ndk\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin\arm-linux-androideabi-g++.exe
-o test test.cc
-I c:\ndk\platforms\android-8\arch-arm\usr\include
-L c:\ndk\platforms\android-8\arch-arm\usr\lib
-nostdlib
c:\ndk\platforms\android-8\arch-arm\usr\lib\crtbegin_dynamic.o
c:\ndk\platforms\android-8\arch-arm\usr\lib\crtend_android.o
-lc
Send to device:
adb -d push test /data/local
Execute:
adb -d shell
cd /data/local
chmod 700 test
./test
And voila. No segementation fault and exits nicely. Thanks for a good getting started article.
Hi, thanks for the tutorial, this is what i was looking for ;). Do you know what changes are necessary to build a shared library?
This is one of the memorable post.I like your blog achievement.This is one of the effective post.
It seems like a great idea and really informative post it was, I got some thing new here.Website Hosting
Instant Approval Directory and
Free Dofollow Directory list
Approval in a 48 hrs...Gaurented..100% Human Edited and approved quickly..
Wow. I already loving your blog.
Wow, I landed on the right page at the right time. I was looking for programming information that will help me to write the literature review of my research project and this website has provided the exact information that I needed. I am very grateful to have visited this site and access this information since I will only submit my papers to an online writer so that they can help to Removing Plagiarism from a Case Study.
Amazing post thank you for sharing this superb knowledge.
SSL Certificate Price
Amezing post thank you for sharing this superb knowledge.
SSL Certificate Price
The dedicated server that is completely reserved for the individual customer. Buy dedicated server from Buydedicatedserver company and get 20% off
buy dedicated server
The Windows Cloud VPS server ensures the resources to be very competitive at each and every cost of level to support all the services of delivering and for their better performance and lower costs; hence to maintain the particular decorum for the window based cloud VPS server to enact their compliance's.
LINUX Cloud VPS India
hey you have shared nice stuff..
Best Advertising Agency
Good information and great post. I will bookmark your weblog and check again here every once in a while.!!
Zenyataa shoes
شركة تنظيف منازل بالجبيل
شركات تنظيف منازل بالجبيل
ارقام شركات تنظيف منازل بالجبيل
اسعار شركات تنظيف منازل بالجبيل
شركة تركيب طارد الحمام بالجبيل
شركة تنظيف مجالس بالجبيل
شركة تنظيف سجاد بالجبيل
شركةغسيل سجاد بالجبيل
شركة تنظيف فلل بالجبيل
شركة تنظيف بالجبيل
شركة تنظيف خزانات بالجبيل
شركة مكافحة صراصير بالجبيل
شركات تنظيف بالجبيل
ارخص شركة تنظيف بالجبيل
رقم شركة تنظيف بالجبيل
شركة نظافة بالجبيل
تنظيف بالجبيل
ارقام شركات تنظيف بالجبيل
تنظيف بالجبيل رخيص
https://almthaly-dammam.com
Jaipur to Kota taxi
Enregistrer un commentaire