I return to school at noon, but before then, I’d like to share my evening project: agcc.bash, a rewrite of agcc and agcc2.pl that works with revisions 6 and 7 of the Android NDK.
The NDK is a GCC-based cross-compiler that lets you embed object code in a traditional Android app. It also works as a standalone cross-compiler, though it is not advertised as such. It is quite rough when used by itself, and agcc wraps the complexity in a little script. While agcc and agcc2.pl are written in Perl, agcc.bash is a Bash script. It also supports the latest revisions of the NDK, though r7 is slightly buggy.
With agcc.bash, building native Android software feels almost like working with GCC. As a quick example, let’s try the classic hello world:
AGCC_NDK=~/android-ndk-r6 ./agcc.bash hello.c -o hello
That wasn’t too exciting… but what happened there? I have the NDK installed at ~/android-ndk-r6 and I told agcc.bash where to look for it, using the AGCC_NDK environment variable. I then invoked agcc.bash as if it were GCC. Let’s see what agcc.bash did behind the scenes:
AGCC_NDK=~/android-ndk-r6 AGCC_ECHO=yes ./agcc.bash hello.c -o hello
=> ./agcc.bash hello.c -o hello
<= /home/jyio/android-ndk-r6/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc -o hello -I/home/jyio/android-ndk-r6/platforms/android-8/arch-arm/usr/include -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -DANDROID -DSK_RELEASE -DNDEBUG -UDEBUG -march=armv5te -mtune=xscale -msoft-float -mthumb-interwork -fpic -fno-exceptions -ffunction-sections -funwind-tables -fmessage-length=0 -march=armv5te -mtune=xscale -msoft-float -mthumb-interwork -fpic -fno-exceptions -ffunction-sections -funwind-tables -fmessage-length=0 hello.c -Bdynamic -Wl,-T,/home/jyio/android-ndk-r6/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/arm-linux-androideabi/lib/ldscripts/armelf_linux_eabi.x -Wl,-dynamic-linker,/system/bin/linker -Wl,–gc-sections -Wl,-z,nocopyreloc -Wl,–no-undefined -Wl,-rpath-link=/home/jyio/android-ndk-r6/platforms/android-8/arch-arm -L/home/jyio/android-ndk-r6/platforms/android-8/arch-arm/usr/lib -nostdlib /home/jyio/android-ndk-r6/platforms/android-8/arch-arm/usr/lib/crtend_android.o /home/jyio/android-ndk-r6/platforms/android-8/arch-arm/usr/lib/crtbegin_dynamic.o -lc /home/jyio/android-ndk-r6/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/lib/gcc/arm-linux-androideabi/4.4.3/libgcc.a -lm -ldl
See how it transformed our innocent little command into a monster! This might be overkill for a hello world program, but it provides pretty good support for more complex software such as OpenSSL, cURL, and Python. It would be a good idea to add the NDK toolchain and agcc.bash to $PATH before trying to build a big program. In my case, the toolchain resides in ~/android-ndk-r6/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin. If you want to build some software that come with configure scripts, you might start with:
CC=agcc.bash ./configure
Do try this at home! Relevant links:
Hi Jiang Yio, thank you for your script and I have successfully compiled the hello world. I see your script works with C, but is it possible to make it also work with C++? thx
I did some more work on agcc.bash and it’s on GitHub. For now, if you symlink/link/rename it to anything ending in -g++ or -c++ and call it that way, it invokes the C++ compiler with the same arguments. It does not automatically add the C++ headers and libraries, so you need to specify those using -I and -L. While CyanogenMod comes with libstdc++.so and libstlport.so, you cannot assume that these exist on other ROM’s, so link statically or bundle the shared object. You could find some C++ libraries in android-ndk/sources/.
Oh, and there’re also quite a few bug fixes, and I’m now using it with r7.
Thanks! I used today’s GitHub version of agcc.bash to compile hello.c for Samsung Galaxy S2 Epic 4G Touch, NDK 7b. Ok. Great to find your work!
Thank you for putting this script together. I’m able to use it to compile simple programs but how do I use it with a ./configure script?
You might do something like
Of course, you’re going to need all of the dependencies for that program.
Feel free to have a look at the GitHub repo for more examples of what could be done. It contains an updated agcc.bash, as well as a build environment. A lot of common libraries have already been ported, which might help you along.
I guess I need to know how your environment is setup because when I was compiling I was using –host with the ./configure script. I’ll take a look at your build environment in the GitHub repo.
If you use –host, use either arm-linux-androideabi or arm-android-eabi.
I figured out my issue and it was that your script is just too good
Seriously, do you have a paypal account for donations? My script to setup my environment did not need to exist and was causing ./configure scripts to not find arm-linux-androideabi-gcc when I pointed it to agcc.bash. I had no problem using it to compile a simple piece of code like hello.c and now I’m able to compile Nmap. I have a lot to learn going through your botbrew (great name!) and hopefully I can learn enough to be able to contribute but at the very least compile the tools I want to run on my Android phone.
Good to see that you got it working! Sometimes you need the other arm-linux-androideabi-* tools, which you could specify while configuring like STRIP=”arm-linux-androideabi-strip –strip-unneeded” and so on. I set up the BotBrew build system because I got tired of manually satisfying dependencies. It gives me great satisfaction to build programs that are useful to me and others, so I don’t request donations, but it’s nice to see the occasional “it works!”
i was able to compile and run from the bsd-games package (pom, ppt, fish, worm, tetris but it did not clear the screen correctly) manually using a native toolchain
Thanks for the heads-up. I’m looking into just using the NDK’s standalone toolchain option, since it’d simplify some things. It might also help to have a customized toolchain, but that’s a pretty daunting project for me at the moment. Are you running these programs using adb? Terminal app? I find that it sometimes helps to set the TERM environment variable to something sensible.
Im running them using Cyanogenmods built in terminal. The toolchain is not completely built by me it is the c4droid apps gcc plugin.The binutils port I use is compiled by me.
I was hoping to use your m4 btw but it gives a segmentation fault.
I set the TERM variable to linux i forgot to add.
We also don’t have working autotools because we don’t have Perl yet. Do you remember how you generated the segfault?
I just ran m4 in the terminal
m4 processed a trivial input file for me just fine. Do you have a specific example?
I basicly ran m4 with no arguments and it gave me a segmentation fault. I bet that m4 can’t use the libraries I have compiled.
I took a look at perl and it failed on a try.c file which dropped me to the sh shell.
The error is in sys/prctl.h of the system headers specificly
"extern int prctl(int option, unsigned long arg2, unsigned long arg3,unsigned long arg4, unsigned long arg5);"
the error
"expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘extern’"removing extern does not help since it then complains about int
Perl’s a monstrosity
I haven’t gotten it cross-compiled yet, but it needs to be modified before it’d build, and there are hardcoded values that might need to be modified before it’d be Android-friendly. Just like many other packages, of course.
is there an xserver dev pkg with headers? because I would like to be able to port my own window manager, like twm
btw I just reinstalled m4 and it works
I actually have a working cross-build of Perl without any modules. So, it’s next to useless
well its progress.
Thanks, Jiang Yio. You may have saved me from returning my new cell phone instead of keeping it, because prior to finding this page, I hadn’t found enough open source tools to get into it, and then to run on it. But I’m having problems building the entire cookbook. Got around a couple but did’t have time to figure out why dbus wouldn’t build (configure said source directory already configured, but it had been empty prior to that). If you contact me I can provide logs, and also details on the couple of minor things I fixed/changed to get on with the build. Thanks again.
… tried building everything, one by one. The majority worked, but a number didn’t. Haven’t tried running them on the device yet. I took notes, if you contact me.
did you get bison working? because I keep getting a bitsign error apon linking attempts.
Yeah, some of the stuff I used to get a basic X server working is somewhat iffy. But now there’s this, which is awesome.
I also made the mistake of removing *.la *.lo pkgconfig, thinking that they would not work in a cross-compiler environment. They actually work, and so I’m fixing it.
And… I’m starting to migrate to the standalone-toolchain generated by the NDK. It’s not as easy to use as agcc.bash because I cannot do arbitrary things without a wrapper, but it’s actually much cleaner.
I haven’t looked into getting Bison working, yet.
id ssuggest trying lynx for a quick compiile I only had to patch one thing to make it work.
I just found a way to get byacc and flex working
First get btyacc id suggest 2.1 since that’s what I used. Compile it then place the binary where it needs to go.Then rename it from btyacc to byacc.After That procede to compile flex.I have not tried bison yet but I believe it will now be easyer to compile.
The steps are for native compiling I do not know if they work cross compiling.
Incidentally, I just got w3m cross-compiled. It’s somewhat more involved than lynx, it seems, but it works better for me so I think it’s worth the trouble.
Hi!
Nice tool! Some glitch though when building busybox:
https://github.com/jyio/botbrew/issues/1
Can you help?
Thanks Jiang for your hardwork.
I managed to cross-compile on Cygwin using the official NDK (r8) distribution.
Here are the commands I passed:
pastie.org/4394514
It results in an “ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped” binary and runs correctly on the device.
However, using the newer script on Github, it won’t link:
$ AGCC_ECHO=yes agcc -o hello2 hello.c
=> /home/Beta/agccwin.bash -o hello2 hello.c
<= c:/Tools/android-ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi-gcc -o hello2 -march=armv5te -mtune=xscale -msoft-float -mthumb-interwork -fpic -fno-exceptions -ffunction-sections -funwind-tables -fmessage-length=0 hello.c -Ic:/Tools/android-ndk/platforms/android-8/arch-arm/usr/include -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -DANDROID -DSK_RELEASE -DNDEBUG -UDEBUG -Wl,-rpath-link=c:/Tools/android-ndk/platforms/android-8/arch-arm/usr/lib -Lc:/Tools/android-ndk/platforms/android-8/arch-arm/usr/lib -Lc:/Tools/android-ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/lib/gcc/arm-linux-androideabi/4.4.3 -Bdynamic -Wl,-T,c:/Tools/android-ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/arm-linux-androideabi/lib/ldscripts/armelf_linux_eabi.x -Wl,-dynamic-linker,/system/bin/linker -Wl,–gc-sections -Wl,-z,nocopyreloc -Wl,–no-undefined -nostdlib c:/Tools/android-ndk/platforms/android-8/arch-arm/usr/lib/crtend_android.o c:/Tools/android-ndk/platforms/android-8/arch-arm/usr/lib/crtbegin_dynamic.o c:/Tools/android-ndk/sources/cxx-stl/gnu-libstdc++/libs/armeabi/libgnustl_static.a -lc -ldl -lgcc -lm -std=gnu99
arm-linux-androideabi-gcc.exe: c:/Tools/android-ndk/sources/cxx-stl/gnu-libstdc++/libs/armeabi/libgnustl_static.a: No such file or directory
The "libs" directory mentioned above is missing
Does it mean I have to rebuild-all-prebuilt.sh?
I believe you could extract it from a prebuilt NDK by Google. The C++ standard library isn’t included by default.