[DEV] [GUIDE] [LINUX] Comprehensive Guide to Cross-Compiling

Search This thread

JustArchi

Inactive Recognized Developer
Mar 7, 2013
8,739
38,807
Warsaw
[SIZE="+1"]What is a Cross-Compiler?[/SIZE]
A cross compiler is a compiler capable of creating executable code for a platform other than the one on which the compiler is running. Cross compiler tools are used to generate executables for embedded system or multiple platforms. It is used to compile for a platform upon which it is not feasible to do the compiling, like microcontrollers that don't support an operating system. From wikipedia


[SIZE="+1"]How is that connected with an Android?[/SIZE]
In order to create a native C/C++ binary for an Android, you must firstly compile the source code. Usually you can't do so on an Android itself due to lack of proper tools and environment, or hardware barriers, especially amount of RAM. This is why you should learn how to cross-compile, to create a binary on your PC, that your ARM-based Android will understand.


[SIZE="+1"]Why do I need it?[/SIZE]
You need to learn cross-compiling technique if you want to run native C/C++ programs on an Android. Actually, if you've already built your own custom ROM from AOSP sources (i.e. CyanogenMod), then you used cross-compiling tools and methods even without noticing :).
Building an AOSP ROM is fairly easy, there's one command like brunch, which does the job. However, what if you want to compile a custom, not natively included binary? This is the purpose of this tutorial.


[SIZE="+1"]What I will learn from this guide?[/SIZE]
  • How to properly set C/C++ building environment
  • How to build a native C/C++ application for Android device
  • How to optimize native binaries for my device



[SIZE="+1"]Step 1 - The Beginning[/SIZE]
You should start from installing any Linux-based OS, I highly suggest trying a Debian-based distro (such as Ubuntu), or even Debian itself, as this tutorial is based on it :).

In general, I highly suggest to compile an AOSP ROM (such as CyanogenMod) for your device firstly. This will help you to get familiar with cross-compiling on Android. I also suggest to compile one or two programs from source for your Linux, but if you're brave enough to learn cross-compiling without doing any of these, you can skip those suggestions :).


[SIZE="+1"]Step 2 - Setting up[/SIZE]
Firstly you should make sure that you have all required compile tools already.

root@ArchiDroid:~# apt-get update && apt-get install checkinstall

This should do the trick and install all required components.
I suggest creating a new folder and navigating to it, just to avoid a mess, but you can organize everything as you wish.

Start from downloading NDK from here.
The NDK is a toolset that allows you to implement parts of your app using native-code languages such as C and C++.
root@ArchiDroid:~# wget http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86_64.tar.bz2
root@ArchiDroid:~# tar xvf android-ndk-r9d-linux-x86_64.tar.bz2
root@ArchiDroid:~# mv android-ndk-r9d ndk

Now you should make a standalone toolchain, navigate to root of your ndk (this is important) and then build your toolchain:
root@ArchiDroid:~# cd ndk/
root@ArchiDroid:~/ndk# build/tools/make-standalone-toolchain.sh --toolchain=arm-linux-androideabi-4.8 --platform=android-18 --install-dir=/root/ndkTC
Copying prebuilt binaries...
Copying sysroot headers and libraries...
Copying libstdc++ headers and libraries...
Copying files to: /root/ndkTC
Cleaning up...
Done.

You should edit bolded variables to your preferences. Toolchain is the version of GCC you want to use, 4.8 is currently the newest one, in the future it may be 4.9 and so on. Platform is a target API for your programs, this is important only for android-specific commands, such as logging to logcat. When compiling a native Linux program, this won't matter (but it's a good idea to set it properly, just in case). Install dir specifies destination of your toolchain, make sure that it's other than ndk (as you can see I have ndk in /root/ndk and toolchain in /root/ndkTC).

Now you need to download my exclusive cc.sh script from here and make it executable.

root@ArchiDroid:~# wget https://dl.dropboxusercontent.com/u/23869279/Files/cc.sh
root@ArchiDroid:~# chmod 755 cc.sh

This script is a very handy tool written by me to make your life easier while cross-compiling. Before running it make sure to edit "BASIC" options, especially NDK paths. Apart from that it's a good idea to take a look at DEVICEFLAGS and setting them properly for your device, or clearing for generic build. You don't need to touch other ones unless you want/need them.

Just for a reference, I'll include currently editable options:
#############
### BASIC ###
#############

# Root of NDK, the one which contains $NDK/ndk-build binary
NDK="/root/ndk"

# Root of NDK toolchain, the one used in --install-dir from $NDK/build/tools/make-standalone-toolchain.sh. Make sure it contains $NDKTC/bin directory with $CROSS_COMPILE binaries
NDKTC="/root/ndkTC"

# Optional, may help NDK in some cases, should be equal to GCC version of the toolchain specified above
export NDK_TOOLCHAIN_VERSION=4.8

# This flag turns on ADVANCED section below, you should use "0" if you want easy compiling for generic targets, or "1" if you want to get best optimized results for specific targets
# In general it's strongly suggested to leave it turned on, but if you're using makefiles, which already specify optimization level and everything else, then of course you may want to turn it off
ADVANCED="1"

################
### ADVANCED ###
################

# Device CFLAGS, these should be taken from TARGET_GLOBAL_CFLAGS property of BoardCommonConfig.mk of your device, eventually leave them empty for generic non-device-optimized build
# Please notice that -march flag comes from TARGET_ARCH_VARIANT
DEVICECFLAGS="-march=armv7-a -mtune=cortex-a9 -mfpu=neon -mfloat-abi=softfp"

# This specifies optimization level used during compilation. Usually it's a good idea to keep it on "-O2" for best results, but you may want to experiment with "-Os", "-O3" or "-Ofast"
OLEVEL="-O2"

# This specifies extra optimization flags, which are not selected by any of optimization levels chosen above
# Please notice that they're pretty EXPERIMENTAL, and if you get any compilation errors, the first step is experimenting with them or disabling them completely, you may also want to try different O level
OPTICFLAGS="-s -flto=8 -ffunction-sections -fdata-sections -fvisibility=hidden -funswitch-loops -frename-registers -frerun-cse-after-loop -fomit-frame-pointer -fgcse-after-reload -fgcse-sm -fgcse-las -fweb -ftracer -fstrict-aliasing"

# This specifies extra linker optimizations. Same as above, in case of problems this is second step for finding out the culprit
LDFLAGS="-Wl,-O1 -Wl,--as-needed -Wl,--relax -Wl,--sort-common -Wl,--gc-sections"

# This specifies additional sections to strip, for extra savings on size
STRIPFLAGS="-s -R .note -R .comment -R .gnu.version -R .gnu.version_r"

# Additional definitions, which may help some binaries to work with android
DEFFLAGS="-DNDEBUG -D__ANDROID__"

##############
### EXPERT ###
##############

# This specifies host (target) for makefiles. In some rare scenarios you may also try "--host=arm-linux-androideabi"
# In general you shouldn't change that, as you're compiling binaries for low-level ARM-EABI and not Android itself
CONFIGANDROID="--host=arm-linux-eabi"

# This specifies the CROSS_COMPILE variable, again, in some rare scenarios you may also try "arm-eabi-"
# But beware, NDK doesn't even offer anything apart from arm-linux-androideabi one, however custom toolchains such as Linaro offer arm-eabi as well
CROSS_COMPILE="arm-linux-androideabi-"

# This specifies if we should also override our native toolchain in the PATH in addition to overriding makefile commands such as CC
# You should NOT enable it, unless your makefile calls "gcc" instead of "$CC" and you want to point "gcc" (and similar) to NDKTC
# However, in such case, you should either fix makefile yourself or not use it at all
# You've been warned, this is not a good idea
TCOVERRIDE="0"

# Workaround for some broken compilers with malloc problems (undefined reference to rpl_malloc and similar errors during compiling), don't uncomment unless you need it
#export ac_cv_func_malloc_0_nonnull=yes

As you can notice, my magic script already contains bunch of optimizations, especially device-based optimizations, which are the most important. Now it's the time to run our script, but in current shell and not a new one.

root@ArchiDroid:~# source cc.sh
Done setting your environment

CFLAGS: -O2 -march=armv7-a -mtune=cortex-a9 -mfpu=neon -mfloat-abi=softfp -s -flto=8 -ffunction-sections -fdata-sections -fvisibility=hidden -funswitch-loops -frename-registers -frerun-cse-after-loop -fomit-frame-pointer -fgcse-after-reload -fgcse-sm -fgcse-las -fweb -ftracer -fstrict-aliasing -DNDEBUG -D__ANDROID__
LDFLAGS: -Wl,-O1 -Wl,--as-needed -Wl,--relax -Wl,--sort-common -Wl,--gc-sections
CC points to arm-linux-androideabi-gcc and this points to /root/ndkTC/bin/arm-linux-androideabi-gcc

Use "$CC" command for calling gcc and "$CCC" command for calling our optimized CC
Use "$CXX" command for calling g++ and "$CCXX" for calling our optimized CXX
Use "$STRIP" command for calling strip and "$SSTRIP" command for calling our optimized STRIP

Example: "$CCC myprogram.c -o mybinary && $SSTRIP mybinary "

When using makefiles with configure options, always use "./configure $CONFIGANDROID" instead of using "./configure" itself
Please notice that makefiles may, or may not, borrow our CFLAGS and LFLAGS, so I suggest to double-check them and eventually append them to makefile itself
Pro tip: Makefiles with configure options always borrow CC, CFLAGS and LDFLAGS, so if you're using ./configure, probably you don't need to do anything else

Command "source cc.sh" executes cc.sh and "shares" the environment, which means that any exports will be exported to our current shell, and this is what we want. It acts the same as AOSP's ". build/envsetup.sh", so you can also use . instead of source.
As you can see above, my script should let you know if it properly set everything, especially if $CC points to our ndkTC. It also set a generic "$CCC" and "$CCXX" commands, which are optimized versions of standard $CC. $CC points to our cross-compiler, $CCC points to our cross-compiler and also includes our optimization flags.
root@ArchiDroid:~# echo $CC
arm-linux-androideabi-gcc
root@ArchiDroid:~# echo $CCC
arm-linux-androideabi-gcc -O2 -march=armv7-a -mtune=cortex-a9 -mfpu=neon -mfloat-abi=softfp -s -flto=8 -ffunction-sections -fdata-sections -fvisibility=hidden -funswitch-loops -frename-registers -frerun-cse-after-loop -fomit-frame-pointer -fgcse-after-reload -fgcse-sm -fgcse-las -fweb -ftracer -fstrict-aliasing -DNDEBUG -D__ANDROID__ -Wl,-O1 -Wl,--as-needed -Wl,--relax -Wl,--sort-common -Wl,--gc-sections


[SIZE="+1"]Step 3 - Cross-Compiling[/SIZE]
Now we'll compile our first program for Android!

Create a new file hello.c, and put inside:
Code:
#include <stdio.h>
int main (void)
{
   puts ("Hello World!");
   return 0;
}

Now you compile and strip it:
root@ArchiDroid:~# $CCC hello.c -o hello && $SSTRIP hello

Remember that $CCC and $SSTRIP command will only work if you source'd cc.sh script explained above. $CCC command compiles source code to a binary with already optimized flags (device flags, optimization level, optimization flags, linker flags), while $SSTRIP command strips "bloat" from output binary, such as comments and notices. The purpose is to make a binary smaller and faster.

You can check if your binary has been compiled properly through readelf command.
root@ArchiDroid:~# readelf -A hello
Attribute Section: aeabi
File Attributes
Tag_CPU_name: "ARM v7"
Tag_CPU_arch: v7
Tag_CPU_arch_profile: Application
Tag_ARM_ISA_use: Yes
Tag_THUMB_ISA_use: Thumb-2
Tag_FP_arch: VFPv3
Tag_Advanced_SIMD_arch: NEONv1
Tag_ABI_PCS_wchar_t: 4
Tag_ABI_FP_denormal: Needed
Tag_ABI_FP_exceptions: Needed
Tag_ABI_FP_number_model: IEEE 754
Tag_ABI_align_needed: 8-byte
Tag_ABI_enum_size: int
Tag_ABI_HardFP_use: SP and DP
Tag_ABI_optimization_goals: Aggressive Speed
Tag_CPU_unaligned_access: v6
Tag_DIV_use: Not allowed

As you can see, I've compiled a binary optimized for ARM v7, with THUMB-2 instructions and NEON support. How nice! Is it because of device-specific flags? Let's check what happens if we use $CC instead of $CCC:
root@ArchiDroid:~# readelf -A hello2
Attribute Section: aeabi
File Attributes
Tag_CPU_name: "5TE"
Tag_CPU_arch: v5TE
Tag_ARM_ISA_use: Yes
Tag_THUMB_ISA_use: Thumb-1
Tag_FP_arch: VFPv2
Tag_ABI_PCS_wchar_t: 4
Tag_ABI_FP_denormal: Needed
Tag_ABI_FP_exceptions: Needed
Tag_ABI_FP_number_model: IEEE 754
Tag_ABI_align_needed: 8-byte
Tag_ABI_enum_size: int
Tag_ABI_optimization_goals: Aggressive Speed
Tag_DIV_use: Not allowed

As you can see, if you do not specify flags, you'll lose major portion of optimizations. Of course binary will work properly, hence it has been cross-compiled for ARM, but we can always make it smaller and faster! :)


[SIZE="+1"]Step 4 - Testing[/SIZE]
A favourite part of everything, tests! :)

root@ADB:~/shared# adb shell
root@m0:/ # sysrw
root@m0:/ # exit
root@ADB:~/shared# adb push hello /system/bin/hello
95 KB/s (5124 bytes in 0.052s)
root@ADB:~/shared# adb shell
root@m0:/ # chmod 755 /system/bin/hello
root@m0:/ # chown root:system /system/bin/hello
root@m0:/ # exit

In above example I pushed my binary straight to /system/bin directory, which is in the Android's PATH. If you don't have rooted device that's not a problem, you can use /data/local directory or /storage/sdcard0. You can also upload your binary anywhere you want and download it as any other file, then run from /storage/sdcard0/Download, this way doesn't require even working ADB :). Just don't forget about setting proper permissions afterwards!

Now let's try to run it! :)
crosscompile.png


If your binary is not in the PATH, you should write full path to your binary of course. As I pushed my binary to /system/bin, I don't need to do so.
If everything finished successfully and you got your very first Hello World response as above, congratulations. You've just compiled and ran your first native C/C++ program on Android device.


[SIZE="+1"]What to do next?[/SIZE]

In theory, you can now compile anything you want. Here are some apps that I'm using in my ArchiDroid ROM:

These are only a few examples. You can compile anything you want, or even write your own native applications. Good luck!
 
Last edited:

dicksteele

Inactive Recognized Contributor
Sep 4, 2010
3,807
2,740
California
[SIZE=+1]What is a Cross-Compiler?[/SIZE]



[SIZE=+1]How is that connected with an Android?[/SIZE]
In order to create a native C/C++ binary for an Android, you must firstly compile the source code. Usually you can't do so on an Android itself due to lack of proper tools and environment, or hardware barriers, especially amount of RAM. This is why you should learn how to cross-compile, to create a binary on your PC, that your ARM-based Android will understand.


[SIZE=+1]Why do I need it?[/SIZE]
You need to learn cross-compiling technique if you want to run native C/C++ programs on an Android. Actually, if you've already built your own custom ROM from AOSP sources (i.e. CyanogenMod), then you used cross-compiling tools and methods even without noticing :).
Building an AOSP ROM is fairly easy, there's one command like brunch, which does the job. However, what if you want to compile a custom, not natively included binary? This is the purpose of this tutorial.


[SIZE=+1]What I will learn from this guide?[/SIZE]
  • How to properly set C/C++ building environment
  • How to build a native C/C++ application for Android device
  • How to optimize native binaries for my device



[SIZE=+1]Step 1 - The Beginning[/SIZE]
You should start from installing any Linux-based OS, I highly suggest trying a Debian-based distro (such as Ubuntu), or even Debian itself, as this tutorial is based on it :).

In general, I highly suggest to compile an AOSP ROM (such as CyanogenMod) for your device firstly. This will help you to get familiar with cross-compiling on Android. I also suggest to compile one or two programs from source for your Linux, but if you're brave enough to learn cross-compiling without doing any of these, you can skip those suggestions :).


[SIZE=+1]Step 2 - Setting up[/SIZE]
Firstly you should make sure that you have all required compile tools already.



This should do the trick and install all required components.
I suggest creating a new folder and navigating to it, just to avoid a mess, but you can organize everything as you wish.

Start from downloading NDK from here.



Now you should make a standalone toolchain, navigate to root of your ndk (this is important) and then build your toolchain:


You should edit bolded variables to your preferences. Toolchain is the version of GCC you want to use, 4.8 is currently the newest one, in the future it may be 4.9 and so on. Platform is a target API for your programs, this is important only for android-specific commands, such as logging to logcat. When compiling a native Linux program, this won't matter (but it's a good idea to set it properly, just in case). Install dir specifies destination of your toolchain, make sure that it's other than ndk (as you can see I have ndk in /root/ndk and toolchain in /root/ndkTC).

Now you need to download my exclusive cc.sh script from here and make it executable.



This script is a very handy tool written by me to make your life easier while cross-compiling. Before running it make sure to edit "BASIC" options, especially NDK paths. Apart from that it's a good idea to take a look at DEVICEFLAGS and setting them properly for your device, or clearing for generic build. You don't need to touch other ones unless you want/need them.

Just for a reference, I'll include currently editable options:


As you can notice, my magic script already contains bunch of optimizations, especially device-based optimizations, which are the most important. Now it's the time to run our script, but in current shell and not a new one.



Command "source cc.sh" executes cc.sh and "shares" the environment, which means that any exports will be exported to our current shell, and this is what we want. It acts the same as AOSP's ". build/envsetup.sh", so you can also use . instead of source.
As you can see above, my script should let you know if it properly set everything, especially if $CC points to our ndkTC. It also set a generic "$CCC" and "$CCXX" commands, which are optimized versions of standard $CC. $CC points to our cross-compiler, $CCC points to our cross-compiler and also includes our optimization flags.



[SIZE=+1]Step 3 - Cross-Compiling[/SIZE]
Now we'll compile our first program for Android!

Create a new file hello.c, and put inside:
Code:
#include <stdio.h>
int main (void)
{
   puts ("Hello World!");
   return 0;
}
Now you compile and strip it:


Remember that $CCC and $SSTRIP command will only work if you source'd cc.sh script explained above. $CCC command compiles source code to a binary with already optimized flags (device flags, optimization level, optimization flags, linker flags), while $SSTRIP command strips "bloat" from output binary, such as comments and notices. The purpose is to make a binary smaller and faster.

You can check if your binary has been compiled properly through readelf command.


As you can see, I've compiled a binary optimized for ARM v7, with THUMB-2 instructions and NEON support. How nice! Is it because of device-specific flags? Let's check what happens if we use $CC instead of $CCC:


As you can see, if you do not specify flags, you'll lose major portion of optimizations. Of course binary will work properly, hence it has been cross-compiled for ARM, but we can always make it smaller and faster! :)


[SIZE=+1]Step 4 - Testing[/SIZE]
A favourite part of everything, tests! :)



In above example I pushed my binary straight to /system/bin directory, which is in the Android's PATH. If you don't have rooted device that's not a problem, you can use /data/local directory or /storage/sdcard0. You can also upload your binary anywhere you want and download it as any other file, then run from /storage/sdcard0/Download, this way doesn't require even working ADB :). Just don't forget about setting proper permissions afterwards!

Now let's try to run it! :)
crosscompile.png


If your binary is not in the PATH, you should write full path to your binary of course. As I pushed my binary to /system/bin, I don't need to do so.
If everything finished successfully and you got your very first Hello World response as above, congratulations. You've just compiled and ran your first native C/C++ program on Android device.


[SIZE=+1]What to do next?[/SIZE]

In theory, you can now compile anything you want. Here are some apps that I'm using in my ArchiDroid ROM:

These are only a few examples. You can compile anything you want, or even write your own native applications. Good luck!
[Mod Edit: Please don't quote the whole OP]

Fricking awesome. Worked perfect on my builduntu running in VirtualBox
 
Last edited by a moderator:
  • Like
Reactions: JustArchi

JustArchi

Inactive Recognized Developer
Mar 7, 2013
8,739
38,807
Warsaw
Maybe you happen to know which packages checkinstall depends on? I want to run this on Arch - pun not intended :p - and pacman doesn't exactly talk with debs.

(Przy okazji, świetny tutorial c: )

Checkinstall makes sure that you have all required packages installed. You can achieve nearly the same by installing "build-essential, gcc, g++, make", and that should be enough I guess ;).
 
  • Like
Reactions: Dragoon Aethis

EnerJon

Senior Member
Jan 29, 2014
350
212
maybe a bit irrelevant... but i wanted to learn how to cross compile/port a binary (for example "applypatch") for cygwin... any link to guide will be helpful :)

Thank You :)
 

JustArchi

Inactive Recognized Developer
Mar 7, 2013
8,739
38,807
Warsaw
I would like to see a guide for llvm/ clang.

Sent from my GT-I9000 using xda app-developers app

When making standalone toolchain you should use clang instead of gcc. You should also study my cc.sh script and adapt to your own. After that, steps are nearly the same.

maybe a bit irrelevant... but i wanted to learn how to cross compile/port a binary (for example "applypatch") for cygwin... any link to guide will be helpful :)

Thank You :)

Using Cygwin for such kind of things is... bad. Install VirtualBox and any Linux distro if you want to master cross-compile technique.
 

EnerJon

Senior Member
Jan 29, 2014
350
212
Using Cygwin for such kind of things is... bad. Install VirtualBox and any Linux distro if you want to master cross-compile technique.

Actually i was making a tool for windows to generate/apply OTA for Android ROMs... i wanted to compile/port "IMGDIFF2" and "applypatch" from android sources...
 

JustArchi

Inactive Recognized Developer
Mar 7, 2013
8,739
38,807
Warsaw
Actually i was making a tool for windows to generate/apply OTA for Android ROMs... i wanted to compile/port "IMGDIFF2" and "applypatch" from android sources...

Then you should find your sources for IMGDIFF2 and applypatch and compile from source for Android, just like example hello.c above.
 
  • Like
Reactions: EnerJon

Odysseus1962

Senior Member
Sep 30, 2013
690
562
Ripley, TN
@JustArchi I saw this guide mentioned on the portal and read through it. Very interesting stuff. Great work explaining. I've got several questions, however, perhaps you can elaborate on.

My primary PC OS is Gentoo Linux (I've been using it for 10 years), in patricular ~amd64 which is the equivalent of Debian unstable. In Gentoo, all packages are compiled from the sources. I have a very up to date complete toolchain already installed and functioning properly as part of the native package installation system which uses portage for maintaining and updating.

I've already compiled CM and AOSP for my device, but I can't for the life of me understand why when setting up my build environment using either Google or CM tools several much older versions of GCC and GLIBC are installed into my source repos and used to build the ROM when the prerequisites for building the environment already require a working toolchain on the host build box?

Isn't there a way to just use the native toolchain from the host? Ideally, I'd love to free up the space used by these extra compilers and libraries for sources instead. Additionally, since my toolchain is much newer (gcc-4.8.2, glibc-2.19, etc) and optimized for my hardware than these generic prebuilt binaries, my ROM builds would compile faster and more optimized if I could use it instead.

The big question I ask is would you know what I'd have to do to setup my native environment to build Android? I'd truly love to be able to get rid of these other toolchains and free up the space on my harddrive. Any help would be greatly appreciated. TIA
 
Last edited:

DerRomtester

Senior Member
Aug 20, 2012
2,899
5,824
27
Neumarkt
When making standalone toolchain you should use clang instead of gcc. You should also study my cc.sh script and adapt to your own. After that, steps are nearly the same.



Using Cygwin for such kind of things is... bad. Install VirtualBox and any Linux distro if you want to master cross-compile technique.

I try this. I would like to cross compile a kernel with clang. Hopefully i get it working.
 

JustArchi

Inactive Recognized Developer
Mar 7, 2013
8,739
38,807
Warsaw
@JustArchi I saw this guide mentioned on the portal and read through it. Very interesting stuff. Great work explaining. I've got several questions, however, perhaps you can elaborate on.

My primary PC OS is Gentoo Linux (I've been using it for 10 years), in patricular ~amd64 which is the equivalent of Debian unstable. In Gentoo, all packages are compiled from the sources. I have a very up to date complete toolchain already installed and functioning properly as part of the native package installation system which uses portage for maintaining and updating.

I've already compiled CM and AOSP for my device, but I can't for the life of me understand why when setting up my build environment using either Google or CM tools several much older versions of GCC and GLIBC are installed into my source repos and used to build the ROM when the prerequisites for building the environment already require a working toolchain on the host build box?

Isn't there a way to just use the native toolchain from the host? Ideally, I'd love to free up the space used by these extra compilers and libraries for sources instead. Additionally, since my toolchain is much newer (gcc-4.8.2, glibc-2.19, etc) and optimized for my hardware than these generic prebuilt binaries, my ROM builds would compile faster and more optimized if I could use it instead.

The big question I ask is would you know what I'd have to do to setup my native environment to build Android? I'd truly love to be able to get rid of these other toolchains and free up the space on my harddrive. Any help would be greatly appreciated. TIA

You need special compiler capable of compiling for specific architecture, this is not the same as native GCC toolchain for amd64. When you're using native compiler, output is always designed for amd64 or i386, when using cross-compiler, output is always designed for ARM, or other specific architecture.
 
  • Like
Reactions: Odysseus1962

Odysseus1962

Senior Member
Sep 30, 2013
690
562
Ripley, TN
You need special compiler capable of compiling for specific architecture, this is not the same as native GCC toolchain for amd64. When you're using native compiler, output is always designed for amd64 or i386, when using cross-compiler, output is always designed for ARM, or other specific architecture.

Thanks for the quick response. I'm a bit disappointed, but I'm still wondering that there has to be some way for me to utilize the ARM toolchain I currently have installed to cross-compile from the sources a more updated optimized toolchain for me to build with. Unfortunately (for me), that Gentoo is more of a niche Linux distro so finding help in their forums for working with ARM is difficult. As it is, it took much effort and trial and error to setup my current configuration to build with since nearly everything on the net is geared towards Ubuntu / Debian (both of which I feel are loaded with useless cruft and dependencies for things I have never and will never use).

Anyhow thanks again for this great guide, and for your continued work here helping us all.

Ciao
 

JustArchi

Inactive Recognized Developer
Mar 7, 2013
8,739
38,807
Warsaw
Code:
#!/bin/bash

#      _           _      _             _     _
#     | |_   _ ___| |_   / \   _ __ ___| |__ (_)
#  _  | | | | / __| __| / _ \ | '__/ __| '_ \| |
# | |_| | |_| \__ \ |_ / ___ \| | | (__| | | | |
#  \___/ \__,_|___/\__/_/   \_\_|  \___|_| |_|_|
#
# Copyright 2014 Łukasz "JustArchi" Domeradzki
# Contact: JustArchi@JustArchi.net
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#############
### BASIC ###
#############

# Root of NDK, the one which contains $NDK/ndk-build binary
NDK="/root/ndk"

# Root of NDK toolchain, the one used in --install-dir from $NDK/build/tools/make-standalone-toolchain.sh. Make sure it contains $NDKTC/bin directory with $CROSS_COMPILE binaries
NDKTC="/root/ndkTC"

# Optional, may help NDK in some cases, should be equal to GCC version of the toolchain specified above
export NDK_TOOLCHAIN_VERSION=4.8

# This flag turns on ADVANCED section below, you should use "0" if you want easy compiling for generic targets, or "1" if you want to get best optimized results for specific targets
# In general it's strongly suggested to leave it turned on, but if you're using makefiles, which already specify optimization level and everything else, then of course you may want to turn it off
ADVANCED="1"

################
### ADVANCED ###
################

# Device CFLAGS, these should be taken from TARGET_GLOBAL_CFLAGS property of BoardCommonConfig.mk of your device, eventually leave them empty for generic non-device-optimized build
# Please notice that -march flag comes from TARGET_ARCH_VARIANT
DEVICECFLAGS="-march=armv7-a -mtune=cortex-a9 -mfpu=neon -mfloat-abi=softfp"

# This specifies optimization level used during compilation. Usually it's a good idea to keep it on "-O2" for best results, but you may want to experiment with "-Os", "-O3" or "-Ofast"
OLEVEL="-O2"

# This specifies extra optimization flags, which are not selected by any of optimization levels chosen above
# Please notice that they're pretty EXPERIMENTAL, and if you get any compilation errors, the first step is experimenting with them or disabling them completely, you may also want to try different O level
OPTICFLAGS="-s -flto=8 -ffunction-sections -fdata-sections -fvisibility=hidden -funswitch-loops -frename-registers -frerun-cse-after-loop -fomit-frame-pointer -fgcse-after-reload -fgcse-sm -fgcse-las -fweb -ftracer -fstrict-aliasing"

# This specifies extra linker optimizations. Same as above, in case of problems this is second step for finding out the culprit
LDFLAGS="-Wl,-O1 -Wl,--as-needed -Wl,--relax -Wl,--sort-common -Wl,--gc-sections"

# This specifies additional sections to strip, for extra savings on size
STRIPFLAGS="-s -R .note -R .comment -R .gnu.version -R .gnu.version_r"

# Additional definitions, which may help some binaries to work with android
DEFFLAGS="-DNDEBUG -D__ANDROID__"

##############
### EXPERT ###
##############

# This specifies host (target) for makefiles. In some rare scenarios you may also try "--host=arm-linux-androideabi"
# In general you shouldn't change that, as you're compiling binaries for low-level ARM-EABI and not Android itself
CONFIGANDROID="--host=arm-linux-eabi"

# This specifies the CROSS_COMPILE variable, again, in some rare scenarios you may also try "arm-eabi-"
# But beware, NDK doesn't even offer anything apart from arm-linux-androideabi one, however custom toolchains such as Linaro offer arm-eabi as well
CROSS_COMPILE="arm-linux-androideabi-"

# This specifies if we should also override our native toolchain in the PATH in addition to overriding makefile commands such as CC
# You should NOT enable it, unless your makefile calls "gcc" instead of "$CC" and you want to point "gcc" (and similar) to NDKTC
# However, in such case, you should either fix makefile yourself or not use it at all
# You've been warned, this is not a good idea
TCOVERRIDE="0"

# Workaround for some broken compilers with malloc problems (undefined reference to rpl_malloc and similar errors during compiling), don't uncomment unless you need it
#export ac_cv_func_malloc_0_nonnull=yes

############
### CORE ###
############

# You shouldn't edit anything from now on
if [ "$ADVANCED" -ne 0 ]; then # If advanced is specified, we override flags used by makefiles with our optimized ones, of course if makefile allows that
	export CFLAGS="$OLEVEL $DEVICECFLAGS $OPTICFLAGS $DEFFLAGS"
	export LOCAL_CFLAGS="$CFLAGS"
	export CXXFLAGS="$CFLAGS" # We use same flags for CXX as well
	export LOCAL_CXXFLAGS="$CXXFLAGS"
	export CPPFLAGS="$CPPFLAGS" # Yes, CPP is the same as CXX, because they're both used in different makefiles/compilers, unfortunately
	export LOCAL_CPPFLAGS="$CPPFLAGS"
	export LDFLAGS="$LDFLAGS"
	export LOCAL_LDFLAGS="$LDFLAGS"
fi

if [ ! -z "$NDK" ] && [ "$(echo $PATH | grep -qi $NDK; echo $?)" -ne 0 ]; then # If NDK doesn't exist in the path (yet), prepend it
        export PATH="$NDK:$PATH"
fi

if [ ! -z "$NDKTC" ] && [ "$(echo $PATH | grep -qi $NDKTC; echo $?)" -ne 0 ]; then # If NDKTC doesn't exist in the path (yet), prepend it
        export PATH="$NDKTC/bin:$PATH"
fi

export CROSS_COMPILE="$CROSS_COMPILE" # All makefiles depend on CROSS_COMPILE variable, this is important to set"
export AS=${CROSS_COMPILE}as
export AR=${CROSS_COMPILE}ar
export CC=${CROSS_COMPILE}gcc
export CXX=${CROSS_COMPILE}g++
export CPP=${CROSS_COMPILE}cpp
export LD=${CROSS_COMPILE}ld
export NM=${CROSS_COMPILE}nm
export OBJCOPY=${CROSS_COMPILE}objcopy
export OBJDUMP=${CROSS_COMPILE}objdump
export READELF=${CROSS_COMPILE}readelf
export RANLIB=${CROSS_COMPILE}ranlib
export SIZE=${CROSS_COMPILE}size
export STRINGS=${CROSS_COMPILE}strings
export STRIP=${CROSS_COMPILE}strip

if [ "$TCOVERRIDE" -eq 1 ]; then # This is not a a good idea...
	alias as="$AS"
	alias ar="$AR"
	alias gcc="$CC"
	alias g++="$CXX"
	alias cpp="$CPP"
	alias ld="$LD"
	alias nm="$NM"
	alias objcopy="$OBJCOPY"
	alias objdump="$OBJDUMP"
	alias readelf="$READELF"
	alias ranlib="$RANLIB"
	alias size="$SIZE"
	alias strings="$STRINGS"
	alias strip="$STRIP"
fi

export CONFIGANDROID="$CONFIGANDROID"
export CCC="$CC $CFLAGS $LDFLAGS"
export CXX="$CXX $CXXFLAGS $LDFLAGS"
export SSTRIP="$STRIP $STRIPFLAGS"

echo "Done setting your environment"
echo
echo "CFLAGS: $CFLAGS"
echo "LDFLAGS: $LDFLAGS"
echo "CC points to $CC and this points to $(which "$CC")"
echo
echo "Use \"\$CC\" command for calling gcc and \"\$CCC\" command for calling our optimized CC"
echo "Use \"\$CXX\" command for calling g++ and \"\$CCXX\" for calling our optimized CXX"
echo "Use \"\$STRIP\" command for calling strip and \"\$SSTRIP\" command for calling our optimized STRIP"
echo
echo "Example: \"\$CCC myprogram.c -o mybinary && \$SSTRIP mybinary \""
echo
echo "When using makefiles with configure options, always use \"./configure \$CONFIGANDROID\" instead of using \"./configure\" itself"
echo "Please notice that makefiles may, or may not, borrow our CFLAGS and LFLAGS, so I suggest to double-check them and eventually append them to makefile itself"
echo "Pro tip: Makefiles with configure options always borrow CC, CFLAGS and LDFLAGS, so if you're using ./configure, probably you don't need to do anything else"

Temporary replacement for cc.sh, as dropbox will be up soon.
 

sfortier

Member
Aug 19, 2007
37
6
Hi!
Great info.
To cross compile some packages with autotools (./configure; make; make install) it's needed to export the SYSROOT path ($ndkTC/sysroot) and include the option --sysroot=$SYSROOT on CFLAGS. Some need too --with-sysroot=$SYSROOT as configure option. This way the configure script and linker can find the libraries.
If i'm building a library that must be used as dependence to other program I use to include --static to build a static library and --prefix=$SYSROOT/usr on configure options to install the lib on toolchain sysroot folder...
Thanks.
 
Last edited:
  • Like
Reactions: JustArchi

JustArchi

Inactive Recognized Developer
Mar 7, 2013
8,739
38,807
Warsaw
Hi!
Great info.
To cross compile some packages with autotools (./configure; make; make install) it's needed to export the SYSROOT path ($ndkTC/sysroot) and include the option --sysroot=$SYSROOT on CFLAGS. Some need too --with-sysroot=$SYSROOT as configure option. This way the configure script and linker can find the libraries.
If i'm building a library that must be used as dependence to other program I use to include --static to build a static library and --prefix=$SYSROOT/usr on configure options to install the lib on toolchain sysroot folder...
Thanks.

Hey.

Nice to know, I'll update my script with that. Thanks! :)
 

sfortier

Member
Aug 19, 2007
37
6
;)
My last attempt to cross compile something was qemu (i'm was thinking on run windows on my tablet... :))
I needed to build glib, pixmap, libpng, zlib, libjpeg-turbo, libiconv, libffi, libintl. Now I have my toolchain with all these usefull static (I prefer static libs to simplify binary installation) libs installed!
 

Top Liked Posts

  • There are no posts matching your filters.
  • 33
    [SIZE="+1"]What is a Cross-Compiler?[/SIZE]
    A cross compiler is a compiler capable of creating executable code for a platform other than the one on which the compiler is running. Cross compiler tools are used to generate executables for embedded system or multiple platforms. It is used to compile for a platform upon which it is not feasible to do the compiling, like microcontrollers that don't support an operating system. From wikipedia


    [SIZE="+1"]How is that connected with an Android?[/SIZE]
    In order to create a native C/C++ binary for an Android, you must firstly compile the source code. Usually you can't do so on an Android itself due to lack of proper tools and environment, or hardware barriers, especially amount of RAM. This is why you should learn how to cross-compile, to create a binary on your PC, that your ARM-based Android will understand.


    [SIZE="+1"]Why do I need it?[/SIZE]
    You need to learn cross-compiling technique if you want to run native C/C++ programs on an Android. Actually, if you've already built your own custom ROM from AOSP sources (i.e. CyanogenMod), then you used cross-compiling tools and methods even without noticing :).
    Building an AOSP ROM is fairly easy, there's one command like brunch, which does the job. However, what if you want to compile a custom, not natively included binary? This is the purpose of this tutorial.


    [SIZE="+1"]What I will learn from this guide?[/SIZE]
    • How to properly set C/C++ building environment
    • How to build a native C/C++ application for Android device
    • How to optimize native binaries for my device



    [SIZE="+1"]Step 1 - The Beginning[/SIZE]
    You should start from installing any Linux-based OS, I highly suggest trying a Debian-based distro (such as Ubuntu), or even Debian itself, as this tutorial is based on it :).

    In general, I highly suggest to compile an AOSP ROM (such as CyanogenMod) for your device firstly. This will help you to get familiar with cross-compiling on Android. I also suggest to compile one or two programs from source for your Linux, but if you're brave enough to learn cross-compiling without doing any of these, you can skip those suggestions :).


    [SIZE="+1"]Step 2 - Setting up[/SIZE]
    Firstly you should make sure that you have all required compile tools already.

    root@ArchiDroid:~# apt-get update && apt-get install checkinstall

    This should do the trick and install all required components.
    I suggest creating a new folder and navigating to it, just to avoid a mess, but you can organize everything as you wish.

    Start from downloading NDK from here.
    The NDK is a toolset that allows you to implement parts of your app using native-code languages such as C and C++.
    root@ArchiDroid:~# wget http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86_64.tar.bz2
    root@ArchiDroid:~# tar xvf android-ndk-r9d-linux-x86_64.tar.bz2
    root@ArchiDroid:~# mv android-ndk-r9d ndk

    Now you should make a standalone toolchain, navigate to root of your ndk (this is important) and then build your toolchain:
    root@ArchiDroid:~# cd ndk/
    root@ArchiDroid:~/ndk# build/tools/make-standalone-toolchain.sh --toolchain=arm-linux-androideabi-4.8 --platform=android-18 --install-dir=/root/ndkTC
    Copying prebuilt binaries...
    Copying sysroot headers and libraries...
    Copying libstdc++ headers and libraries...
    Copying files to: /root/ndkTC
    Cleaning up...
    Done.

    You should edit bolded variables to your preferences. Toolchain is the version of GCC you want to use, 4.8 is currently the newest one, in the future it may be 4.9 and so on. Platform is a target API for your programs, this is important only for android-specific commands, such as logging to logcat. When compiling a native Linux program, this won't matter (but it's a good idea to set it properly, just in case). Install dir specifies destination of your toolchain, make sure that it's other than ndk (as you can see I have ndk in /root/ndk and toolchain in /root/ndkTC).

    Now you need to download my exclusive cc.sh script from here and make it executable.

    root@ArchiDroid:~# wget https://dl.dropboxusercontent.com/u/23869279/Files/cc.sh
    root@ArchiDroid:~# chmod 755 cc.sh

    This script is a very handy tool written by me to make your life easier while cross-compiling. Before running it make sure to edit "BASIC" options, especially NDK paths. Apart from that it's a good idea to take a look at DEVICEFLAGS and setting them properly for your device, or clearing for generic build. You don't need to touch other ones unless you want/need them.

    Just for a reference, I'll include currently editable options:
    #############
    ### BASIC ###
    #############

    # Root of NDK, the one which contains $NDK/ndk-build binary
    NDK="/root/ndk"

    # Root of NDK toolchain, the one used in --install-dir from $NDK/build/tools/make-standalone-toolchain.sh. Make sure it contains $NDKTC/bin directory with $CROSS_COMPILE binaries
    NDKTC="/root/ndkTC"

    # Optional, may help NDK in some cases, should be equal to GCC version of the toolchain specified above
    export NDK_TOOLCHAIN_VERSION=4.8

    # This flag turns on ADVANCED section below, you should use "0" if you want easy compiling for generic targets, or "1" if you want to get best optimized results for specific targets
    # In general it's strongly suggested to leave it turned on, but if you're using makefiles, which already specify optimization level and everything else, then of course you may want to turn it off
    ADVANCED="1"

    ################
    ### ADVANCED ###
    ################

    # Device CFLAGS, these should be taken from TARGET_GLOBAL_CFLAGS property of BoardCommonConfig.mk of your device, eventually leave them empty for generic non-device-optimized build
    # Please notice that -march flag comes from TARGET_ARCH_VARIANT
    DEVICECFLAGS="-march=armv7-a -mtune=cortex-a9 -mfpu=neon -mfloat-abi=softfp"

    # This specifies optimization level used during compilation. Usually it's a good idea to keep it on "-O2" for best results, but you may want to experiment with "-Os", "-O3" or "-Ofast"
    OLEVEL="-O2"

    # This specifies extra optimization flags, which are not selected by any of optimization levels chosen above
    # Please notice that they're pretty EXPERIMENTAL, and if you get any compilation errors, the first step is experimenting with them or disabling them completely, you may also want to try different O level
    OPTICFLAGS="-s -flto=8 -ffunction-sections -fdata-sections -fvisibility=hidden -funswitch-loops -frename-registers -frerun-cse-after-loop -fomit-frame-pointer -fgcse-after-reload -fgcse-sm -fgcse-las -fweb -ftracer -fstrict-aliasing"

    # This specifies extra linker optimizations. Same as above, in case of problems this is second step for finding out the culprit
    LDFLAGS="-Wl,-O1 -Wl,--as-needed -Wl,--relax -Wl,--sort-common -Wl,--gc-sections"

    # This specifies additional sections to strip, for extra savings on size
    STRIPFLAGS="-s -R .note -R .comment -R .gnu.version -R .gnu.version_r"

    # Additional definitions, which may help some binaries to work with android
    DEFFLAGS="-DNDEBUG -D__ANDROID__"

    ##############
    ### EXPERT ###
    ##############

    # This specifies host (target) for makefiles. In some rare scenarios you may also try "--host=arm-linux-androideabi"
    # In general you shouldn't change that, as you're compiling binaries for low-level ARM-EABI and not Android itself
    CONFIGANDROID="--host=arm-linux-eabi"

    # This specifies the CROSS_COMPILE variable, again, in some rare scenarios you may also try "arm-eabi-"
    # But beware, NDK doesn't even offer anything apart from arm-linux-androideabi one, however custom toolchains such as Linaro offer arm-eabi as well
    CROSS_COMPILE="arm-linux-androideabi-"

    # This specifies if we should also override our native toolchain in the PATH in addition to overriding makefile commands such as CC
    # You should NOT enable it, unless your makefile calls "gcc" instead of "$CC" and you want to point "gcc" (and similar) to NDKTC
    # However, in such case, you should either fix makefile yourself or not use it at all
    # You've been warned, this is not a good idea
    TCOVERRIDE="0"

    # Workaround for some broken compilers with malloc problems (undefined reference to rpl_malloc and similar errors during compiling), don't uncomment unless you need it
    #export ac_cv_func_malloc_0_nonnull=yes

    As you can notice, my magic script already contains bunch of optimizations, especially device-based optimizations, which are the most important. Now it's the time to run our script, but in current shell and not a new one.

    root@ArchiDroid:~# source cc.sh
    Done setting your environment

    CFLAGS: -O2 -march=armv7-a -mtune=cortex-a9 -mfpu=neon -mfloat-abi=softfp -s -flto=8 -ffunction-sections -fdata-sections -fvisibility=hidden -funswitch-loops -frename-registers -frerun-cse-after-loop -fomit-frame-pointer -fgcse-after-reload -fgcse-sm -fgcse-las -fweb -ftracer -fstrict-aliasing -DNDEBUG -D__ANDROID__
    LDFLAGS: -Wl,-O1 -Wl,--as-needed -Wl,--relax -Wl,--sort-common -Wl,--gc-sections
    CC points to arm-linux-androideabi-gcc and this points to /root/ndkTC/bin/arm-linux-androideabi-gcc

    Use "$CC" command for calling gcc and "$CCC" command for calling our optimized CC
    Use "$CXX" command for calling g++ and "$CCXX" for calling our optimized CXX
    Use "$STRIP" command for calling strip and "$SSTRIP" command for calling our optimized STRIP

    Example: "$CCC myprogram.c -o mybinary && $SSTRIP mybinary "

    When using makefiles with configure options, always use "./configure $CONFIGANDROID" instead of using "./configure" itself
    Please notice that makefiles may, or may not, borrow our CFLAGS and LFLAGS, so I suggest to double-check them and eventually append them to makefile itself
    Pro tip: Makefiles with configure options always borrow CC, CFLAGS and LDFLAGS, so if you're using ./configure, probably you don't need to do anything else

    Command "source cc.sh" executes cc.sh and "shares" the environment, which means that any exports will be exported to our current shell, and this is what we want. It acts the same as AOSP's ". build/envsetup.sh", so you can also use . instead of source.
    As you can see above, my script should let you know if it properly set everything, especially if $CC points to our ndkTC. It also set a generic "$CCC" and "$CCXX" commands, which are optimized versions of standard $CC. $CC points to our cross-compiler, $CCC points to our cross-compiler and also includes our optimization flags.
    root@ArchiDroid:~# echo $CC
    arm-linux-androideabi-gcc
    root@ArchiDroid:~# echo $CCC
    arm-linux-androideabi-gcc -O2 -march=armv7-a -mtune=cortex-a9 -mfpu=neon -mfloat-abi=softfp -s -flto=8 -ffunction-sections -fdata-sections -fvisibility=hidden -funswitch-loops -frename-registers -frerun-cse-after-loop -fomit-frame-pointer -fgcse-after-reload -fgcse-sm -fgcse-las -fweb -ftracer -fstrict-aliasing -DNDEBUG -D__ANDROID__ -Wl,-O1 -Wl,--as-needed -Wl,--relax -Wl,--sort-common -Wl,--gc-sections


    [SIZE="+1"]Step 3 - Cross-Compiling[/SIZE]
    Now we'll compile our first program for Android!

    Create a new file hello.c, and put inside:
    Code:
    #include <stdio.h>
    int main (void)
    {
       puts ("Hello World!");
       return 0;
    }

    Now you compile and strip it:
    root@ArchiDroid:~# $CCC hello.c -o hello && $SSTRIP hello

    Remember that $CCC and $SSTRIP command will only work if you source'd cc.sh script explained above. $CCC command compiles source code to a binary with already optimized flags (device flags, optimization level, optimization flags, linker flags), while $SSTRIP command strips "bloat" from output binary, such as comments and notices. The purpose is to make a binary smaller and faster.

    You can check if your binary has been compiled properly through readelf command.
    root@ArchiDroid:~# readelf -A hello
    Attribute Section: aeabi
    File Attributes
    Tag_CPU_name: "ARM v7"
    Tag_CPU_arch: v7
    Tag_CPU_arch_profile: Application
    Tag_ARM_ISA_use: Yes
    Tag_THUMB_ISA_use: Thumb-2
    Tag_FP_arch: VFPv3
    Tag_Advanced_SIMD_arch: NEONv1
    Tag_ABI_PCS_wchar_t: 4
    Tag_ABI_FP_denormal: Needed
    Tag_ABI_FP_exceptions: Needed
    Tag_ABI_FP_number_model: IEEE 754
    Tag_ABI_align_needed: 8-byte
    Tag_ABI_enum_size: int
    Tag_ABI_HardFP_use: SP and DP
    Tag_ABI_optimization_goals: Aggressive Speed
    Tag_CPU_unaligned_access: v6
    Tag_DIV_use: Not allowed

    As you can see, I've compiled a binary optimized for ARM v7, with THUMB-2 instructions and NEON support. How nice! Is it because of device-specific flags? Let's check what happens if we use $CC instead of $CCC:
    root@ArchiDroid:~# readelf -A hello2
    Attribute Section: aeabi
    File Attributes
    Tag_CPU_name: "5TE"
    Tag_CPU_arch: v5TE
    Tag_ARM_ISA_use: Yes
    Tag_THUMB_ISA_use: Thumb-1
    Tag_FP_arch: VFPv2
    Tag_ABI_PCS_wchar_t: 4
    Tag_ABI_FP_denormal: Needed
    Tag_ABI_FP_exceptions: Needed
    Tag_ABI_FP_number_model: IEEE 754
    Tag_ABI_align_needed: 8-byte
    Tag_ABI_enum_size: int
    Tag_ABI_optimization_goals: Aggressive Speed
    Tag_DIV_use: Not allowed

    As you can see, if you do not specify flags, you'll lose major portion of optimizations. Of course binary will work properly, hence it has been cross-compiled for ARM, but we can always make it smaller and faster! :)


    [SIZE="+1"]Step 4 - Testing[/SIZE]
    A favourite part of everything, tests! :)

    root@ADB:~/shared# adb shell
    root@m0:/ # sysrw
    root@m0:/ # exit
    root@ADB:~/shared# adb push hello /system/bin/hello
    95 KB/s (5124 bytes in 0.052s)
    root@ADB:~/shared# adb shell
    root@m0:/ # chmod 755 /system/bin/hello
    root@m0:/ # chown root:system /system/bin/hello
    root@m0:/ # exit

    In above example I pushed my binary straight to /system/bin directory, which is in the Android's PATH. If you don't have rooted device that's not a problem, you can use /data/local directory or /storage/sdcard0. You can also upload your binary anywhere you want and download it as any other file, then run from /storage/sdcard0/Download, this way doesn't require even working ADB :). Just don't forget about setting proper permissions afterwards!

    Now let's try to run it! :)
    crosscompile.png


    If your binary is not in the PATH, you should write full path to your binary of course. As I pushed my binary to /system/bin, I don't need to do so.
    If everything finished successfully and you got your very first Hello World response as above, congratulations. You've just compiled and ran your first native C/C++ program on Android device.


    [SIZE="+1"]What to do next?[/SIZE]

    In theory, you can now compile anything you want. Here are some apps that I'm using in my ArchiDroid ROM:

    These are only a few examples. You can compile anything you want, or even write your own native applications. Good luck!
    2
    I would like to see a guide for llvm/ clang.

    Sent from my GT-I9000 using xda app-developers app

    When making standalone toolchain you should use clang instead of gcc. You should also study my cc.sh script and adapt to your own. After that, steps are nearly the same.

    maybe a bit irrelevant... but i wanted to learn how to cross compile/port a binary (for example "applypatch") for cygwin... any link to guide will be helpful :)

    Thank You :)

    Using Cygwin for such kind of things is... bad. Install VirtualBox and any Linux distro if you want to master cross-compile technique.
    2
    Code:
    #!/bin/bash
    
    #      _           _      _             _     _
    #     | |_   _ ___| |_   / \   _ __ ___| |__ (_)
    #  _  | | | | / __| __| / _ \ | '__/ __| '_ \| |
    # | |_| | |_| \__ \ |_ / ___ \| | | (__| | | | |
    #  \___/ \__,_|___/\__/_/   \_\_|  \___|_| |_|_|
    #
    # Copyright 2014 Łukasz "JustArchi" Domeradzki
    # Contact: JustArchi@JustArchi.net
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #    http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    #############
    ### BASIC ###
    #############
    
    # Root of NDK, the one which contains $NDK/ndk-build binary
    NDK="/root/ndk"
    
    # Root of NDK toolchain, the one used in --install-dir from $NDK/build/tools/make-standalone-toolchain.sh. Make sure it contains $NDKTC/bin directory with $CROSS_COMPILE binaries
    NDKTC="/root/ndkTC"
    
    # Optional, may help NDK in some cases, should be equal to GCC version of the toolchain specified above
    export NDK_TOOLCHAIN_VERSION=4.8
    
    # This flag turns on ADVANCED section below, you should use "0" if you want easy compiling for generic targets, or "1" if you want to get best optimized results for specific targets
    # In general it's strongly suggested to leave it turned on, but if you're using makefiles, which already specify optimization level and everything else, then of course you may want to turn it off
    ADVANCED="1"
    
    ################
    ### ADVANCED ###
    ################
    
    # Device CFLAGS, these should be taken from TARGET_GLOBAL_CFLAGS property of BoardCommonConfig.mk of your device, eventually leave them empty for generic non-device-optimized build
    # Please notice that -march flag comes from TARGET_ARCH_VARIANT
    DEVICECFLAGS="-march=armv7-a -mtune=cortex-a9 -mfpu=neon -mfloat-abi=softfp"
    
    # This specifies optimization level used during compilation. Usually it's a good idea to keep it on "-O2" for best results, but you may want to experiment with "-Os", "-O3" or "-Ofast"
    OLEVEL="-O2"
    
    # This specifies extra optimization flags, which are not selected by any of optimization levels chosen above
    # Please notice that they're pretty EXPERIMENTAL, and if you get any compilation errors, the first step is experimenting with them or disabling them completely, you may also want to try different O level
    OPTICFLAGS="-s -flto=8 -ffunction-sections -fdata-sections -fvisibility=hidden -funswitch-loops -frename-registers -frerun-cse-after-loop -fomit-frame-pointer -fgcse-after-reload -fgcse-sm -fgcse-las -fweb -ftracer -fstrict-aliasing"
    
    # This specifies extra linker optimizations. Same as above, in case of problems this is second step for finding out the culprit
    LDFLAGS="-Wl,-O1 -Wl,--as-needed -Wl,--relax -Wl,--sort-common -Wl,--gc-sections"
    
    # This specifies additional sections to strip, for extra savings on size
    STRIPFLAGS="-s -R .note -R .comment -R .gnu.version -R .gnu.version_r"
    
    # Additional definitions, which may help some binaries to work with android
    DEFFLAGS="-DNDEBUG -D__ANDROID__"
    
    ##############
    ### EXPERT ###
    ##############
    
    # This specifies host (target) for makefiles. In some rare scenarios you may also try "--host=arm-linux-androideabi"
    # In general you shouldn't change that, as you're compiling binaries for low-level ARM-EABI and not Android itself
    CONFIGANDROID="--host=arm-linux-eabi"
    
    # This specifies the CROSS_COMPILE variable, again, in some rare scenarios you may also try "arm-eabi-"
    # But beware, NDK doesn't even offer anything apart from arm-linux-androideabi one, however custom toolchains such as Linaro offer arm-eabi as well
    CROSS_COMPILE="arm-linux-androideabi-"
    
    # This specifies if we should also override our native toolchain in the PATH in addition to overriding makefile commands such as CC
    # You should NOT enable it, unless your makefile calls "gcc" instead of "$CC" and you want to point "gcc" (and similar) to NDKTC
    # However, in such case, you should either fix makefile yourself or not use it at all
    # You've been warned, this is not a good idea
    TCOVERRIDE="0"
    
    # Workaround for some broken compilers with malloc problems (undefined reference to rpl_malloc and similar errors during compiling), don't uncomment unless you need it
    #export ac_cv_func_malloc_0_nonnull=yes
    
    ############
    ### CORE ###
    ############
    
    # You shouldn't edit anything from now on
    if [ "$ADVANCED" -ne 0 ]; then # If advanced is specified, we override flags used by makefiles with our optimized ones, of course if makefile allows that
    	export CFLAGS="$OLEVEL $DEVICECFLAGS $OPTICFLAGS $DEFFLAGS"
    	export LOCAL_CFLAGS="$CFLAGS"
    	export CXXFLAGS="$CFLAGS" # We use same flags for CXX as well
    	export LOCAL_CXXFLAGS="$CXXFLAGS"
    	export CPPFLAGS="$CPPFLAGS" # Yes, CPP is the same as CXX, because they're both used in different makefiles/compilers, unfortunately
    	export LOCAL_CPPFLAGS="$CPPFLAGS"
    	export LDFLAGS="$LDFLAGS"
    	export LOCAL_LDFLAGS="$LDFLAGS"
    fi
    
    if [ ! -z "$NDK" ] && [ "$(echo $PATH | grep -qi $NDK; echo $?)" -ne 0 ]; then # If NDK doesn't exist in the path (yet), prepend it
            export PATH="$NDK:$PATH"
    fi
    
    if [ ! -z "$NDKTC" ] && [ "$(echo $PATH | grep -qi $NDKTC; echo $?)" -ne 0 ]; then # If NDKTC doesn't exist in the path (yet), prepend it
            export PATH="$NDKTC/bin:$PATH"
    fi
    
    export CROSS_COMPILE="$CROSS_COMPILE" # All makefiles depend on CROSS_COMPILE variable, this is important to set"
    export AS=${CROSS_COMPILE}as
    export AR=${CROSS_COMPILE}ar
    export CC=${CROSS_COMPILE}gcc
    export CXX=${CROSS_COMPILE}g++
    export CPP=${CROSS_COMPILE}cpp
    export LD=${CROSS_COMPILE}ld
    export NM=${CROSS_COMPILE}nm
    export OBJCOPY=${CROSS_COMPILE}objcopy
    export OBJDUMP=${CROSS_COMPILE}objdump
    export READELF=${CROSS_COMPILE}readelf
    export RANLIB=${CROSS_COMPILE}ranlib
    export SIZE=${CROSS_COMPILE}size
    export STRINGS=${CROSS_COMPILE}strings
    export STRIP=${CROSS_COMPILE}strip
    
    if [ "$TCOVERRIDE" -eq 1 ]; then # This is not a a good idea...
    	alias as="$AS"
    	alias ar="$AR"
    	alias gcc="$CC"
    	alias g++="$CXX"
    	alias cpp="$CPP"
    	alias ld="$LD"
    	alias nm="$NM"
    	alias objcopy="$OBJCOPY"
    	alias objdump="$OBJDUMP"
    	alias readelf="$READELF"
    	alias ranlib="$RANLIB"
    	alias size="$SIZE"
    	alias strings="$STRINGS"
    	alias strip="$STRIP"
    fi
    
    export CONFIGANDROID="$CONFIGANDROID"
    export CCC="$CC $CFLAGS $LDFLAGS"
    export CXX="$CXX $CXXFLAGS $LDFLAGS"
    export SSTRIP="$STRIP $STRIPFLAGS"
    
    echo "Done setting your environment"
    echo
    echo "CFLAGS: $CFLAGS"
    echo "LDFLAGS: $LDFLAGS"
    echo "CC points to $CC and this points to $(which "$CC")"
    echo
    echo "Use \"\$CC\" command for calling gcc and \"\$CCC\" command for calling our optimized CC"
    echo "Use \"\$CXX\" command for calling g++ and \"\$CCXX\" for calling our optimized CXX"
    echo "Use \"\$STRIP\" command for calling strip and \"\$SSTRIP\" command for calling our optimized STRIP"
    echo
    echo "Example: \"\$CCC myprogram.c -o mybinary && \$SSTRIP mybinary \""
    echo
    echo "When using makefiles with configure options, always use \"./configure \$CONFIGANDROID\" instead of using \"./configure\" itself"
    echo "Please notice that makefiles may, or may not, borrow our CFLAGS and LFLAGS, so I suggest to double-check them and eventually append them to makefile itself"
    echo "Pro tip: Makefiles with configure options always borrow CC, CFLAGS and LDFLAGS, so if you're using ./configure, probably you don't need to do anything else"

    Temporary replacement for cc.sh, as dropbox will be up soon.
    1
    [SIZE=+1]What is a Cross-Compiler?[/SIZE]



    [SIZE=+1]How is that connected with an Android?[/SIZE]
    In order to create a native C/C++ binary for an Android, you must firstly compile the source code. Usually you can't do so on an Android itself due to lack of proper tools and environment, or hardware barriers, especially amount of RAM. This is why you should learn how to cross-compile, to create a binary on your PC, that your ARM-based Android will understand.


    [SIZE=+1]Why do I need it?[/SIZE]
    You need to learn cross-compiling technique if you want to run native C/C++ programs on an Android. Actually, if you've already built your own custom ROM from AOSP sources (i.e. CyanogenMod), then you used cross-compiling tools and methods even without noticing :).
    Building an AOSP ROM is fairly easy, there's one command like brunch, which does the job. However, what if you want to compile a custom, not natively included binary? This is the purpose of this tutorial.


    [SIZE=+1]What I will learn from this guide?[/SIZE]
    • How to properly set C/C++ building environment
    • How to build a native C/C++ application for Android device
    • How to optimize native binaries for my device



    [SIZE=+1]Step 1 - The Beginning[/SIZE]
    You should start from installing any Linux-based OS, I highly suggest trying a Debian-based distro (such as Ubuntu), or even Debian itself, as this tutorial is based on it :).

    In general, I highly suggest to compile an AOSP ROM (such as CyanogenMod) for your device firstly. This will help you to get familiar with cross-compiling on Android. I also suggest to compile one or two programs from source for your Linux, but if you're brave enough to learn cross-compiling without doing any of these, you can skip those suggestions :).


    [SIZE=+1]Step 2 - Setting up[/SIZE]
    Firstly you should make sure that you have all required compile tools already.



    This should do the trick and install all required components.
    I suggest creating a new folder and navigating to it, just to avoid a mess, but you can organize everything as you wish.

    Start from downloading NDK from here.



    Now you should make a standalone toolchain, navigate to root of your ndk (this is important) and then build your toolchain:


    You should edit bolded variables to your preferences. Toolchain is the version of GCC you want to use, 4.8 is currently the newest one, in the future it may be 4.9 and so on. Platform is a target API for your programs, this is important only for android-specific commands, such as logging to logcat. When compiling a native Linux program, this won't matter (but it's a good idea to set it properly, just in case). Install dir specifies destination of your toolchain, make sure that it's other than ndk (as you can see I have ndk in /root/ndk and toolchain in /root/ndkTC).

    Now you need to download my exclusive cc.sh script from here and make it executable.



    This script is a very handy tool written by me to make your life easier while cross-compiling. Before running it make sure to edit "BASIC" options, especially NDK paths. Apart from that it's a good idea to take a look at DEVICEFLAGS and setting them properly for your device, or clearing for generic build. You don't need to touch other ones unless you want/need them.

    Just for a reference, I'll include currently editable options:


    As you can notice, my magic script already contains bunch of optimizations, especially device-based optimizations, which are the most important. Now it's the time to run our script, but in current shell and not a new one.



    Command "source cc.sh" executes cc.sh and "shares" the environment, which means that any exports will be exported to our current shell, and this is what we want. It acts the same as AOSP's ". build/envsetup.sh", so you can also use . instead of source.
    As you can see above, my script should let you know if it properly set everything, especially if $CC points to our ndkTC. It also set a generic "$CCC" and "$CCXX" commands, which are optimized versions of standard $CC. $CC points to our cross-compiler, $CCC points to our cross-compiler and also includes our optimization flags.



    [SIZE=+1]Step 3 - Cross-Compiling[/SIZE]
    Now we'll compile our first program for Android!

    Create a new file hello.c, and put inside:
    Code:
    #include <stdio.h>
    int main (void)
    {
       puts ("Hello World!");
       return 0;
    }
    Now you compile and strip it:


    Remember that $CCC and $SSTRIP command will only work if you source'd cc.sh script explained above. $CCC command compiles source code to a binary with already optimized flags (device flags, optimization level, optimization flags, linker flags), while $SSTRIP command strips "bloat" from output binary, such as comments and notices. The purpose is to make a binary smaller and faster.

    You can check if your binary has been compiled properly through readelf command.


    As you can see, I've compiled a binary optimized for ARM v7, with THUMB-2 instructions and NEON support. How nice! Is it because of device-specific flags? Let's check what happens if we use $CC instead of $CCC:


    As you can see, if you do not specify flags, you'll lose major portion of optimizations. Of course binary will work properly, hence it has been cross-compiled for ARM, but we can always make it smaller and faster! :)


    [SIZE=+1]Step 4 - Testing[/SIZE]
    A favourite part of everything, tests! :)



    In above example I pushed my binary straight to /system/bin directory, which is in the Android's PATH. If you don't have rooted device that's not a problem, you can use /data/local directory or /storage/sdcard0. You can also upload your binary anywhere you want and download it as any other file, then run from /storage/sdcard0/Download, this way doesn't require even working ADB :). Just don't forget about setting proper permissions afterwards!

    Now let's try to run it! :)
    crosscompile.png


    If your binary is not in the PATH, you should write full path to your binary of course. As I pushed my binary to /system/bin, I don't need to do so.
    If everything finished successfully and you got your very first Hello World response as above, congratulations. You've just compiled and ran your first native C/C++ program on Android device.


    [SIZE=+1]What to do next?[/SIZE]

    In theory, you can now compile anything you want. Here are some apps that I'm using in my ArchiDroid ROM:

    These are only a few examples. You can compile anything you want, or even write your own native applications. Good luck!
    [Mod Edit: Please don't quote the whole OP]

    Fricking awesome. Worked perfect on my builduntu running in VirtualBox
    1
    Hi!
    Great info.
    To cross compile some packages with autotools (./configure; make; make install) it's needed to export the SYSROOT path ($ndkTC/sysroot) and include the option --sysroot=$SYSROOT on CFLAGS. Some need too --with-sysroot=$SYSROOT as configure option. This way the configure script and linker can find the libraries.
    If i'm building a library that must be used as dependence to other program I use to include --static to build a static library and --prefix=$SYSROOT/usr on configure options to install the lib on toolchain sysroot folder...
    Thanks.