Friday, February 6, 2015

Cross-Compiling for Embedded Linux based systems

After my recent work with porting multiple things for android. I thought that it would be nice to do a tutorial for cross compiling existing linux projects over to the embedded devices. I will soon get into the details. For cross-compiling linux based binaries/libraries basically you need 3 things

  1. Toolchain
  2. Headers
  3. Libraries

Toolchain

Depending upon the selected target you can always find a toolchain. Toolchains are always architecture specific (Duh!?). For example if your device is ARM based you cannot compile for it with MIPS toolchain. The most common toolchain that you will find for a device is GCC. It is open source toolchain. You might also find different flavours like linaro. Or find a different toolchain itself like clang/LLVM. Whatever the choice you will need these for most of the projects.
  1. C compiler 
  2. Assembler
  3. C++ compiler
  4. Pre-Processor
  5. Linker utilities
  6. Archive utilities
However, Observe that we are talking of a c or c++ based project here. Java, Python, Perl projects inherently depend upon their Interpreter or Virtual Machine to run. And also they are designed to be portable. Hence once compiled they should be able to run on any system provided the availability of the fore said things.

Headers 

These are basically collection of .h/.hh files that contain definitions of the functions/structures ,etc., the way it would be found on the real device. These are mostly created when you compile the kernel, and many more are added by the supporting libraries. Pre-Processor uses these to verify that the function calls that you will be making to the Operating system actually exist and are defined. One might in theory edit these files and add his own stuff or definitions and the project would pass the pre-processing step and compile. However if the system is to be linked these definitions have to be found somewhere. If the OS expects its binaries to be pre-linked then the linking process would fail. If dynamic linking is taken into account then it would fail and throw up a fault at run time. For example you might link your project with a 3.xx kernel based header and newer version of libraries. But if you try to run the project on a older kernel or with older libraries. Then it would not run and throw up a fault.

Libraries

These are basically there so that the linker can verify and statically link the binaries. It is however expected that the same library files exist on the device for it to work. You might in theory simply copy the library to the device and expect it to work. But sometimes, or most of the times the dependencies may not be the same and it would fail.

Now for a practical example take a look at port of LibAV to android. LibAV is an open source implementation of codecs for media play back and encoding. I had to use it to a personal project. I have however uploaded the source to github. It would be interesting to look into the build scripts that I have used to build the libraries. There are basically 3 of them for different architectures, namely ARM, MIPS and X86. This project was configured with autoconf. So it has a configure script that can be easily run. And thanks to popularity of Android, LibAV actually officially claim to support android(previously, wasn't the case). Observe that I configure the build with multiple parameters. But mainly the cross-compiler toolchain

which is configured at cross-prefix. The headers and libraries are located in sysroot, under include and lib directories respectively. Rest of the configurations are mainly project specific. Running this script obviously requires to to edit for your system, the locations would not be same. But in the same project under android directory you will find that multiple ARCH directories are there with executables of the same library compiled. If you are trying to port something linux to android, then do take a look in to the build scripts. You will find a variety of pointers for the job.

Have Fun!
Cheers !!