레이블이 toolchain인 게시물을 표시합니다. 모든 게시물 표시
레이블이 toolchain인 게시물을 표시합니다. 모든 게시물 표시

2011년 12월 21일 수요일

Building Open Source libraries with Android NDK


출처 : http://warpedtimes.wordpress.com/2010/02/03/building-open-source-libraries-with-android-ndk/


Building Open Source libraries with Android NDK

Filed under: Android,Technology — divkis01 @ 12:50 am
Tags: 
Having scrambled through a NDK documentation and a lot of hit and trials and experimentation, finally I could figure out how could one build (even though partially) Open Source libraries with Android NDK.

Some background on how Autotools work:

The way autootool and friends work is this:
You write a configure.ac file, which is read in by Autoreconf and generates a configure script. Configure script test the build system for headers, libraries etc. and generates a config.h which contains definitions like #define HAVE_XXX 1 and also generates Makefiles after reading in the Makefile.in files which in turn is generated using Automake by reading in Makefile.am.
configure.ac —> input to –> autoreconf –> generates -> configure script –> checks host system for headers, libraries etc. -> generates -> config.h
Also
Makefile.am –> input to automake –> generates –> Makefile.in –> input to –> configure script –> generates Makefile
The code uses the generated config.h in the following fashion:
#ifdef HAVE_XXXX
#include <some-header>
#endif
….
….
#ifdef HAVE_XXXX
Call some function which is declared in the header
#else
Provide some other mechanism or report error to user or do whatever you want
#endif

The problem?

Most Open Source libraries use GNU autotools and its friends for building.
The first problem is that the Autools generate some configuration headers based on build time probe of the system. By build time probe I mean checking for things like if a header, library or a tool is present or not. In cross compiling scenario some of these probe should be done on the target system and not on the build system.
Second, the build system for most cross compiler tools have their own quirks which need passing some extra flags.
Third, in case of Android, it provides its own build system which are essentially some Makefile definitions and rules. This is provided so that people can build their code easily without having to deal with usual cross compiling issues. Thus there is a gap that while your autotools would generate the Makefiles while Android build system requires its own styled Makefiles in the form of Android.mk. One cannot simply generate Android.mk files using autotools.
Fourth, even if one gets to write Android specific Makefiles, the build would most probably fail as during the build it would look for a file config.h included in the fashion shown below, while no such file would exist as it is generated by the configure script.
#ifdef HAVE_CONFIG_H
#include “config.h”
#endif
Simply copying a config.h file from a run of configure script on another build system wouldn’t really work as the header files and other libraries present on Android may not match with the header and libraries present on the build system. Thus config.h would probably differ if it is somehow generated for Android with the one generated on a build system.
So how does one build an open source library for Android?

Solution:

The way I have managed to work around this trouble is to run the configure script with right cross compilation variables so that a config.h matching my Android system gets built and then writing Android.mk files which would simply use the Android build system.
The way I figured out the right flags was by building the Android source tree which displayed what flags are being used for building and then taking the cues from there, I passed the right flags to the configure script.
It looks something like this for building Android-3 target API on a linux host:
export ANDROID_ROOT=/home/divkis01/mydroid
The command above is sets the path where the Android sources are checked out from git respository.
NOTE: It is not necessary to check out the ANDROID sources and you can replace the ANDROID_ROOT with NDK_ROOT in all the commands below, along with proper path to the NDK cross compiler.
export PATH=$PATH:$ANDROID_ROOT/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/
The command above is necessary so that configure can find out the path to the cross compiler which is needed to build some test programs during the configure run process. Please note that you can also set the path to the NDK compiler root
./configure –host=arm-eabi CC=arm-eabi-gcc CPPFLAGS=”-I$ANDROID_ROOT/build/platforms/android-3/arch-arm/usr/include/” CFLAGS=”-nostdlib” LDFLAGS=”-Wl,-rpath-link=$ANDROID_ROOT/build/platforms/android-3/arch-arm/usr/lib/ -L$ANDROID_ROOT/build/platforms/android-3/arch-arm/usr/lib/” LIBS=”-lc “
The command above has several points that should be well understood.
–host=arm-eabi –> This tells the configure script if the cross compilation is being done or not. It is also used as a prefix to some of the cross compiler tools like strip, nm etc.
CC=arm-eabi-gcc –> This tells the compiler that should be used for building
CPPFLAGS –> This tells the location where the header files should be searched which were specified in configure.ac with AC_CHECK_HEADER macro
CFLAGS=”-nostdlib” passes the option to build some test programs during configure process run. If you don’t pass this the compiler would link the standard C library of the host system which wouldn’t be compatible with the C library of the target system. You will end up getting error something like this, if you don’t pass this option:
/home/divkis01/mydroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/../../../../arm-eabi/bin/ld: crt0.o: No such file: No such file or directory
LIBS=”-lc” –> This option tells that it should explicitly link to a library called libc.so which is present in the location specified using the -L in the LDFLAGS option. If you are wondering that usually to build a C executable one doesn’t need to provide -lc as libc is automatically linked, then why do we need to specify this here? The answer lies in -nostdlib flag, which instructs not to link with the standard C library on the build system.
You will end up getting error something like this, if you don’t pass this option:
/home/divkis01/mydroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/../../../../arm-eabi/bin/ld: crt0.o: No such file: No such file or directory
collect2: ld returned 1 exit status
LDFLAGS = –> This option is also passed to build some test programs during configure process run.If you don’t pass the -Wl,-rpath-link option, then linker does not know where do the libraries dependent on the library specific using LIBS reside. If you don’t pass the -L option then the linker doesn’t know where do the libraries specified in LIBS reside.
You will end up getting error something like this, if you don’t pass the -Wl,-rpath-link option:
/home/divkis01/mydroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/../../../../arm-eabi/bin/ld: warning: libdl.so, needed by /home/divkis01/mydroid/development/ndk/build/platforms/android-3/arch-arm/usr/lib//libc.so, not found (try using -rpath or -rpath-link)
/home/divkis01/mydroid/prebuilt/linux-x86/toolchain/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 00008184
/home/divkis01/mydroid/development/ndk/build/platforms/android-3/arch-arm/usr/lib//libc.so: undefined reference to `dl_unwind_find_exidx’
You will end up getting error something like this, if you don’t pass the -L option:
/home/divkis01/mydroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/../../../../arm-
eabi/bin/ld: cannot find -lc
collect2: ld returned 1 exit status
Once you run the configure script with these flags and options, it will generate the appropriate config.h which is compatible / in sync with your target system. Now you can go ahead and start writing the Android.mk files to build your sources.

Other troubles:

This solves only part of the problem as Autotools not only help in building but also in installing. Given it doesn’t make sense to install the build for a target system on host except for the headers. This can be done by augmenting the Android.mk files or writing some shell scripts to do this manually.

Conclusion:

Autotool is good only on GNU systems and using it for cross compiling can be really tedious, confusing, error prone or even impossible. The method described here is a hack and should be used at your own risk.
Let me know if this post was helpful for you.

Hello World C program using Android Toolchain

출처 :http://android-tricks.blogspot.com/2009/02/hello-world-c-program-on-using-android.html


Hello World C program using Android Toolchain

I had reported earlier how I had gotten a C Hello World statically-linked program running on my Android phone using CodeSourcery's toolchain (on linux). Today I got a dynamically-linked Hello World program running on the phone, compiled using Android's prebuilt toolchain from the source.

It's well known that Android uses a stripped down version of libc, called bionic. When you compile your program with static linking, you don't use bionic because well, you linked statically. This is non-ideal. You want to use the bionic library on the phone, and besides you want to compile using Android's prebuilt cross-compiler arm-eabi-gcc

If you are anxious to get things working, use agcc, a perl wrapper over arm-eabi-gcc that sets up everything for you so that you can just:
$ agcc hello.c -o hello
and the resulting binary (hello) just works. Of course you should have the directory containing arm-eabi-gcc in your PATH foragcc to work.

Let's explore a bit deeper. But let me first simplify my hello program to contain just a main
$ cat hello.c int main(int argc, char* argv[]) {return 0;}

The minimal set of flags to pass to arm-eabi-gcc to get this working is:
$ arm-eabi-gcc -o hello hello.c -Wl,-rpath-link=/Users/nirnimesh/NIR/android/mydroid/cupcake/out/target/product/generic/obj/lib -L/Users/nirnimesh/NIR/android/mydroid/cupcake/out/target/product/generic/obj/lib -nostdlib/Users/nirnimesh/NIR/android/mydroid/cupcake/out/target/product/generic/obj/lib/crtbegin_dynamic.o -lc

Here /Users/nirnimesh/NIR/android/mydroid/cupcake is the root of my Android source.

$ file hello

hello: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

Note that the executable binary is dynamically linked.

If you leave out -Wl,-rpath-link=/Users/nirnimesh/NIR/android/mydroid/cupcake/out/target/product/generic/obj/lib you get
/Users/nirnimesh/NIR/android/mydroid/cupcake/prebuilt/darwin-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/../../../../arm-eabi/bin/ld: warning: libdl.so, needed by /Users/nirnimesh/NIR/android/mydroid/cupcake/out/target/product/generic/obj/lib/libc.so, not found (try using -rpath or -rpath-link)/Users/nirnimesh/NIR/android/mydroid/cupcake/out/target/product/generic/obj/lib/libc.so: undefined reference to `dl_unwind_find_exidx' collect2: ld returned 1 exit status

If you leave out -L/Users/nirnimesh/NIR/android/mydroid/cupcake/out/target/product/generic/obj/lib you get
/Users/nirnimesh/NIR/android/mydroid/cupcake/prebuilt/darwin-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/../../../../arm-eabi/bin/ld: cannot find -lc collect2: ld returned 1 exit status

If you leave out -nostdlib you get
/Users/nirnimesh/NIR/android/mydroid/cupcake/prebuilt/darwin-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/../../../../arm-eabi/bin/ld: crt0.o: No such file: No such file or directory collect2: ld returned 1 exit status

If you leave out/Users/nirnimesh/NIR/android/mydroid/cupcake/out/target/product/generic/obj/lib/crtbegin_dynamic.oyou get
/Users/nirnimesh/NIR/android/mydroid/cupcake/prebuilt/darwin-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/../../../../arm-eabi/bin/ld: crt0.o: No such file: No such file or directory collect2: ld returned 1 exit status

And finally, f you leave out -lc your compilation fails with:
/Users/nirnimesh/NIR/android/mydroid/cupcake/out/target/product/generic/obj/lib/crtbegin_dynamic.o: In function `_start': bionic/libc/arch-arm/bionic/crtbegin_dynamic.S:(.text+0x10): undefined reference to `__libc_init' collect2: ld returned 1 exit status

So far we've been able to compile C programs using Androids toolchain and run on the phone.
To summarize, it's the most convenient to use agcc as the compiler so you don't have to bother.

Hello World in C on Android

출처 : http://android-tricks.blogspot.com/2009/02/hello-world-in-c-on-android.html


Hello World in C on Android

If you've been following the Android world, you'd know that Android's SDK requires you to write apps in Java. Ever since I got my phone I've been dying to run a Hello World C program, but I've been unable to get the right cross compiler for it.

Today I finally managed to do it using CodeSourcery's cross compiler on linux. A cross compiler is something which allows you to compile on one architecture (the host) and run the executable binary on another (the target). In this case, the host is the linux machine where we'll install the toolchain (linux intel x86) and android phone is the host (arm).
  1. Download CodeSourcery's toolchain installer for GNU/Linux target for IA32 host
  2. Install it: sh arm-2008q3-72-arm-none-linux-gnueabi.bin
  3. The toolchain provides the cross compiler arm-none-linux-gnueabi-gcc. You need to put it's directory in your $PATH. Once you have the toolchain, you can easily compile your hello world program: arm-none-linux-gnueabi-gcc -o hello -static hello.c
  4. Copy the binary to your phone and run it from an adb shell prompt: ./hello
Voila!

Points to note:
  • The above binary is static, that is it does not use the phone's libc libraries. Android ships with its own trimmed down version of libc, called bionic. Next I'll be trying to compile and run using bionic libc, so that I don't have to compile statically
  • The above steps do not use the toolchain in the android source code. I'll try later to cross compile using that.