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.hAlso
Makefile.am –> input to automake –> generates –> Makefile.in –> input to –> configure script –> generates MakefileThe 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” #endifSimply 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.
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
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 directoryLIBS=”-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 directorycollect2: 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 statusOnce 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.
Great and useful article
Thanks
Thank you so much for this artitcle which describled what i want to study.
Hi Kishore
Thanks for your post, You explained well about Android makefile in detail.
I trying cross compile a library with android toolchain right now, but facing same problem, Can you kindly advise me on this ??
Here is my configure options.
export ANDROID_ROOT=/home/arun/mydroid
export PATH=$PATH:$ANDROID_ROOT/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/
If i run the following command, i getting one common error, but not able resolve my slef, can you please assist on this
./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 “
configure: error: unrecognized option: -L/home/arun/mydroid/build/platforms/android-3/arch-arm/usr/lib/”
Try `./configure –help’ for more information.
I guess there is an extra quote ” character in the linker flags, which is what is causing you this issue. See if that helps.
Hi kishore Thanks for ur document,
I am also facing the same problem while compiling gstreamer components in froyo.while compiling i am getting the following error.
target SharedLib: libgstcoreelements (out/target/product/generic/obj/PLUGIN_LIBRARIES/libgstcoreelements_intermediates/LINKED/libgstcoreelements.so)
/home/venu/Gstreamer/froyo/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/bin/ld: cannot find -lgstbase-0.10
collect2: ld returned 1 exit status
make: *** [out/target/product/generic/obj/PLUGIN_LIBRARIES/libgstcoreelements_intermediates/LINKED/libgstcoreelements.so] Error 1
make: Leaving directory `/home/venu/Gstreamer/froyo’
Can u please give me some suggestions to solve this error
I think it is pretty simple, you ought to add the location of the library in your build. Let me know if it helps.
Hi kishore,
Here is my cross build environment setup.
export PATH=$PATH:/home/arun/mydroid/prebuilt/linux-x86/toolchain/arm-
eabi-4.2.1/bin
LD=arm-eabi-ld
AR=arm-eabi-ar
STRIP=arm-eabi-strip
RANLIB=arm-eabi-ranlib
CC=arm-eabi-gcc
CXX=arm-eabi-g++
CPPFLAGS=”-I/home/arun/mydroid/bionic/libstdc++/include -I/home/arun/
mydroid/bionic/libc/include -I/home/arun/mydroid/bionic/libc/arch-arm/
include/ -I/home/arun/mydroid/external/jpeg -I/home/arun/mydroid/
bionic/libc/kernel/common -I/home/arun/mydroid/bionic/libc/kernel/arch-
arm -I/home/arun/mydroid/bionic/libm/include -I/home/arun/mydroid/
bionic/libm/include/arch/arm -I/home/arun/mydroid/bionic/libm/arm -I/
home/arun/mydroid/bionic/libm”
CFLAGS=”-nostdlib”
LDFLAGS=-Wl,–entry=main,–no-undefined,-rpath-link=”-L/home/arun/
mydroid/out/target/product/imx51_BBG/obj/STATIC_LIBRARIES/
libjpeg_intermediates/ -L/home/arun/mydroid/development/ndk/build/
platforms/android-3/arch-arm/usr/lib/ -L/home/arun/mydroid/out/target/
product/imx51_BBG/system/lib”
LIBS=”-lc -lgcc -lm -ldl -lstdc++ -L/home/arun/mydroid/out/target/
product/imx51_BBG/obj/STATIC_LIBRARIES/libjpeg_intermediates -ljpeg”
————————————————————————————————————————————-
Then i execute “./configure”. It went well.
But while doing “make” c and c++ souces are compiled properly.
At the linking stage i got this error
/home/arun/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
I tried using different options.I have googled and tried some
solution. But not proper ending.
Kindly help/guide me on this.
Thanks
Thangamani Arun
Just looking at the error it seems the linker flags are either not being passed properly or the paths are not correct. Compilers do not complain about the non existent directories, thus make sure that directories you pass to linker do exist. It appears that somehow the libc of the host system is getting linked with your sources which is not compatible with the Android libc. I see that you are using the compiler present in the android sources itself rather then using the one shipped with the Android NDK. Unless you explain the complete / relevant scenario, no one can really help. Overall I would ask the following questions to be able to help.
1. What are you trying to do? It is possible that there is a shorter and cleaner way to compile your sources.
2. What is the final build command issued when doing make?
3. Why are you using cross compiler present in the Android sources? Are you building Android image itself or your goal is only to build some library for Android?
4. What is your target platform? Android or some other platform?
Hi Kishore,
I am trying to build a executable from normal Linux source package. I followed the these steps to cross compile my linux source
step1:
export PATH=$PATH:/home/arun/mydroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin
step2:
./configure LD=arm-eabi-ld AR=arm-eabi-ar STRIP=arm-eabi-strip RANLIB=arm-eabi-ranlib CC=arm-eabi-gcc CXX=arm-eabi-g++ CPPFLAGS=”-I/home/arun/mydroid/bionic/libstdc++/include -I/home/arun/mydroid/bionic/libc/include -I/home/arun/mydroid/bionic/libc/arch-arm/include/ -I/home/arun/mydroid/external/jpeg -I/home/arun/mydroid/bionic/libc/kernel/common -I/home/arun/mydroid/bionic/libc/kernel/arch-arm -I/home/arun/mydroid/bionic/libm/include -I/home/arun/mydroid/bionic/libm/include/arch/arm -I/home/arun/mydroid/bionic/libm/arm -I/home/arun/mydroid/bionic/libm” CFLAGS=”-nostdlib” LDFLAGS=-Wl,–entry=main,-rpath-link=”-L/home/arun/mydroid/out/target/product/imx51_BBG/obj/STATIC_LIBRARIES/libjpeg_intermediates/ -L/home/arun/mydroid/development/ndk/build/platforms/android-3/arch-arm/usr/lib/ -L/home/arun/mydroid/out/target/product/imx51_BBG/system/lib” LIBS=”-lc -lgcc -lm -ldl -lstdc++ -L/home/arun/mydroid/out/target/product/imx51_BBG/obj/STATIC_LIBRARIES/libjpeg_intermediates -ljpeg”
step3:
make
/home/arun/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
At the end of the source compilation, while linking getting the above error.
step4:
To solve the above error, i did
cp /home/arun/mydroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/lib/gcc/arm-eabi/4.2.1/crtn.o /home/arun/mydroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/lib/gcc/arm-eabi/4.2.1/crt0.o
Step5:
make
/home/arun/mydroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/../../../../arm-eabi/bin/ld: cannot find -lg
collect2: ld returned 1 exit status
I do not know what is wrong with my compiler/linker flags. Kindly correct me if anything wrong.
Regards
Arun
You have still not specified what is your target system and why are you using android’s toolchain for building it. Anyways try removing -lgcc and -lstdc++.
Also please do not manually copy the object files that you are doing in your comment as that might screw up your compiler setup.
Hope that helps, Divkis
I just tried for understanding. I will remove those -lgcc & -lstdc++. Then i will see if it goes well.
Kindly note that the Linux source package used for cross compilation has both .C .CPP file. While linking these objects and libs throwing those errors. Let me know if you any concern on this statement
I used “–target=arm-eabi”, but i forget to mention, Sorry for that
Hello
Really nice and informative article.
I’m trying to port libsigc++ library to Android.
First of all I don’t know exactly what more flags and paths to include to ./configure
In my experience with porting libcurl library, you could just ‘make libcurl showcommands’ from mydroid folder and it would reveal the necessary flags.
This time when I try make I get make: *** No rule to make target `libsigcpp’. Stop.
Now I try to pass the following to ./configure by running this sh file:
#!/bin/sh
A=`realpath ../..` && \
PATH=”$A/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/:$PATH” \
./configure –host=arm-eabi CC=arm-eabi-gcc CXX=arm-eabi-g++ \
CPPFLAGS=”-I $A/system/core/include \
-include $A/system/core/include/arch/linux-arm/AndroidConfig.h” \
CFLAGS=”-nostdlib” \
LDFLAGS=”-Wl,-rpath-link=$A/out/target/product/passion/obj/lib \
-L$A/out/target/product/passion/obj/lib” \
LIBS=”-lc”
When I run it I get exactly the error you were talking about:
/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/bin/ld: crt0.o: No such file: No such file or directory
collect2: ld returned 1 exit status
What stuff do I miss to pass along to ./configure?
How do I reveal all the necessary libraries, flags and paths to make libsigc++?
Thanks in advance and best regards,
Alexej
It appears you are trying to build the library using the non prescribed way i.e. you are not using NDK to build the library but you are using the android sources itself to build the library. Since I have not tried using that I can’t say much but probably you are better off using the NDK build system instead of using the android sources for rootfs, libs, headers etc. as not all of them are exposed to Native developers on Android. Hope that helps.
Your suggestion is very useful to me, thanks a lot.
Here is the command line that works for dpkg:
./configure –host=arm-eabi CC=arm-eabi-gcc CPPFLAGS=”-I/usr/local/android-ndk-r4b/build/platforms/android-3/arch-arm/usr/include/” CFLAGS=”-fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -DANDROID -Wa,–noexecstack” LDFLAGS=”-nostdlib -Bdynamic -Wl,-dynamic-linker,/system/bin/linker -Wl,–gc-sections -Wl,-z,nocopyreloc /usr/local/android-ndk-r4b/build/platforms/android-3/arch-arm/usr/lib/crtbegin_dynamic.o” LIBS=”/usr/local/android-ndk-r4b/build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/libgcc.a /usr/local/android-ndk-r4b/build/platforms/android-3/arch-arm/usr/lib/libc.so /usr/local/android-ndk-r4b/build/platforms/android-3/arch-arm/usr/lib/libstdc++.so /usr/local/android-ndk-r4b/build/platforms/android-3/arch-arm/usr/lib/libm.so -Wl,–no-undefined -Wl,-z,noexecstack -Wl,-rpath-link=/usr/local/android-ndk-r4b/build/platforms/android-3/arch-arm/usr/lib /usr/local/android-ndk-r4b/build/platforms/android-3/arch-arm/usr/lib/crtend_android.o” –without-dselect –without-start-stop-daemon –disable-nls –disable-rpath –disable-largefile
make will fail for various reasons, the fixes for which are probably outside the scope of my comment here (the default NDK tree doesn’t have all the include headers one might hope for).
Dear sir,
I’m trying to build sysfsutils-2.1.0. The thing actually goes pretty well, it makes fine. I have added the –prefix=/system to your ./configure line, and when I run make install on the build machine, it successfully copy everything to /system/bin and /system/lib (on the LInux build machine, /system is simply a directory I made to see if make install was working
).
If I check the file type (on the build machine):
dlist_test: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
get_device: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
get_driver: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
get_module: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
systool: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
so it seems the files correctly build as ARM binaries.
I push all the bin/libs to my actual device (to /system/bin and /system/lib respectively).
When I try to run systool, I get:
# /system/bin/systool
/system/bin/systool: not found
The file is actually there:
# ls -l /system/bin/systool
-rwxr-xr-x system system 63622 2010-11-11 09:15 systool
I believe the not found error is actually meaning here something else (maybe a missing lib?), but I don’t know where to look at… Any idea what is wrong here? (no ldd on Android afaik).
Thanks in advance for your help (you can contact me by email would you need some more details).
The trouble is that you don’t have shared libraries which systool is dependent upon in the LD_LIBRARY_PATH. Try copying the required libraries in the same folder where you have systools installed or try setting the LD_LIBRARY_PATH. ldd is just a script which actually invoked ld. To get equivalent functionality you can do
/lib/ld.lnux.so.2 –list /lib/systools
Just match it to where your ld and systools are installed. Let me if it works.
If I understand correctly, you mean I have to copy the libs that compiled with systool to somewhere that is in the LD_LIBRARY_PATH?
Actually that I have already done.
On the device: LD_LIBRARY_PATH=/system/lib
/system/lib is where I have copied the 2 lib files created during the compilation.
There is no /lib/ld-linux.so.2 on my Android device :-/, what would be the equivalent on Android? (No “*ld*” in /system/lib/).
The equivalent of ld-linux.so on android is actually /system/bin/linker but somehow it behaves quite differently on android so I am afraid that it might not be able to list the dependencies. Sorry for the confusion. To list dependencies you can do
/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/arm-eabi-readelf -d systools
where systools is the binaries that you build. The outout of this would be something similar to as shown below. Note that at the top the second column shows the ‘NEEDED’ and third column lists the libraries that are needed. This one is the output from running readelf on libGLESv1_CM.so.
Dynamic section at offset 0×5000 contains 19 entries:
Tag Type Name/Value
0×00000001 (NEEDED) Shared library: [liblog.so]
0×00000001 (NEEDED) Shared library: [libcutils.so]
0×00000001 (NEEDED) Shared library: [libEGL.so]
0×00000001 (NEEDED) Shared library: [libdl.so]
0×00000001 (NEEDED) Shared library: [libc.so]
0×00000001 (NEEDED) Shared library: [libstdc++.so]
0×00000001 (NEEDED) Shared library: [libm.so]
0x0000000e (SONAME) Library soname: [libGLESv1_CM.so]
0×00000010 (SYMBOLIC) 0×0
0×00000004 (HASH) 0xb4
0×00000005 (STRTAB) 0x17a8
0×00000006 (SYMTAB) 0x7c8
0x0000000a (STRSZ) 3995 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0×00000003 (PLTGOT) 0x50c0
0×00000002 (PLTRELSZ) 8 (bytes)
0×00000014 (PLTREL) REL
0×00000017 (JMPREL) 0×2744
0×00000000 (NULL) 0×0
Hope that helps
Pingback: cji->setMode(GEEK); » Starting work on G3D…
Nice tutorial..
It explained all the parameters for configure command
This really helped me.
Thanx
Pingback: Compiling open source libraries for Android: Part 1 | ampersand
Thanks for the info! This pretty much sums up what I’ve gone through and a bit more that I had yet to discover..
THANK YOU
Hi! I could have sworn I’ve been to this website before but after browsing through some of the post I realized it’s new to me.
Anyways, I’m definitely happy I found it and I’ll be book-marking and checking
back often!
Sue
Thank you, good & usefull article
It’s going to be end of mine day, but before ending I am reading this impressive post to increase my knowledge.