Recently I got an opportunity to cross compile code for different platforms like arm, x86 and x86_64. As previously I do not have any experience in cross compilation, I learned it and found it very interesting.In this blog, I will be mentioning about the concepts, which I learned, so that anybody else who needs to do cross compilation can quickly ramp up with the fundamental concepts and instructions.
It is intended to beginners who needs to learn about cross compilation.
Usually when you write a program in in order to execute it, it needs compilation. Compilation is a process when a text based program is transformed into machine understandable format(native code).
Here machine means PC/Mobile/Tablets.Now these machines are made of processor, which actually does the computation work or executes the instruction mentioned in program. Majority of the CPU available in market comes from Intel; however there are many other vendors like AMD, Nvidia etc who manufactures CPU. These processor can be categorized on the basis of their architecture.
Basically they are 32 and 64 bit architecture.The most popular processors are
- i686/x86, that is 32 bit Intel provided processor.
- x86_64 that is both 32/64 bit Intel provided processor.
- ARM 32 bit and 64 bit processors.
In nutshell, what we need is to make our program run on these different architectures and for that, we need to compile it with a compiler who produces executable targeted to these architectures. These compilers usually comes through a toolchain.
A toolchain is a set of programming tools that are used to perform a complex software development task or to create a software product, which is typically another computer program or a set of related programs.
In layman terms, it is a set of files/libraries which helps you to compile, link, debug and do many more operations to program. The most interesting tool in toolchain for us is compiler.
As I said earlier, compiler is used to compile a program to native code. But the question is what is this native code?
Native code is a particular format which the processor running your program understands.
So here, compiler takes that responsibility to convert your program to machine (processor) understandable instructions called native code. For eg, in a typical case, if your computer is Linux is x86_64 machine, so when you compile a program in your Linux machine and execute it, you used GCC compiler which understands x86_64 processor format and produced a executable to execute on x86_64 processor. GCC is the most popular compiler used in Linux environment.
Now there comes a requirement, when you need to compile your code against different architecture. For eg:
- The machine on which you are doing coding is x86_64 platform.
- But the machine where you want your program to execute have ARM processor. And for this need we need to do cross compilation.
A cross compiler is a compiler capable of creating executable code for a platform other than the one on which the compiler is running. For example, a compiler that runs on a Windows 7 PC (x86_64) but generates code that runs on Android smartphone (ARM) is a cross compiler.
Cross Compilation Concepts
There are two types of files/source codes that are cross-compiled-
- Toolchain (aka compilers, binutils, gdb) is needed when you have source code of GCC compiler but you don’t have its executable to run on a particular type of device, say ARM device.
- Programs, existing open source libraries.
Example for cross compiling a toolchain is complex task and is beyond the scope of this article. Therefore, our example will be focused on programs/libraries.
Now two machines must be distinguished when discussing about cross compilation of libraries/programs.
- The build machine, where the compilation is happening
- The host machine, where the executable will run.
And three machines must be distinguished when discussing about cross compilation of tool chains.
- The build machine, where the toolchain is built.
- The host machine, where the toolchain will be executed.
- The target machine, where the binaries created by the toolchain are executed.
For clarity, I have separated machines types for libraries and toolchains. However they are actually same, if you think toolchain as normal program, then in case of toolchain cross compilation, our toolchain (GCC) is executed to creates a new executable.
–target is only required in case of cross compiling toolchain.
For normal libaries do not use –target.
For cross compiling a library you need to understand host and build options.
- –build=The system on which the package is built.
- –host=The system where built programs and libraries will run
Mentioning –host flag to ./configure makes it think that we are cross compiling. Do not pass it when you are doing native build for libraries.
Cross Compiler are named according to convention, which are called as TRIPLETS. Target Triplets describe a platform on which code runs and are a core concept in the GNU build system.
They contain three fields:
- the name of the CPU family/model,
- the vendor,
- and the operating system name.
Examples are :
- arm-none-linux-gnueabi (vendor name doesn’t matter)
- arm-unknown-linux-gnueabi (vendor name doesn’t matter)
- i686-QNAP-linux-gnu (QNAP vendor)
- x86_64-QNAP-linux-gnu (QNAP vendor)
- arm-marvell-linux-gnueabi (marvell vendor)
Cross compilation example
Mostly libraries comes with configure, make , make install approach for compilation. It is a very different concept. If interested you can read more about it in this fantastic article.
In this example, we will cross compile Linux-PAM-1.3.0 library.
1. Download Linux-PAM-1.3.0 from below link and extract it in some location
neeraj@lxpc:~$ ls Linux-PAM-1.3.0-docs.tar.bz2 neeraj@lxpc:~$ tar -xf Linux-PAM-1.3.0-docs.tar.bz2 neeraj@lxpc:~$ cd Linux-PAM-1.3.0
2. Download/install/identify toolchain in your machine and set the following variables as below and set the CC, CPP, CXX, LD, AR option that will be used by configure and make system.
I am already having an arm toolchain extracted in my home directory.
neeraj@lxpc:Linux-PAM-1.3.0$ export CC=~/crosstool/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-gcc neeraj@lxpc:Linux-PAM-1.3.0$ export CPP=~/crosstool/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-cpp neeraj@lxpc:Linux-PAM-1.3.0$export CXX=~/crosstool/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-g++ neeraj@lxpc:Linux-PAM-1.3.0$export LD=~/crosstool/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-ld neeraj@lxpc:Linux-PAM-1.3.0$ export AR=~/crosstool/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-ar
3. Run configure script and provide prefix, so that once make install knows where to keep the compiled files.
–host value determines the platform on which binaries are suppose to be executed.
–build value no need to provide as ./configure will guess it automatically, and which is your development machine architecture
neeraj@lxpc:Linux-PAM-1.3.0$ ./configure --prefix=~/lib-pam --host=arm-unknown-linux-gnueabi neeraj@lxpc:Linux-PAM-1.3.0$ make neeraj@lxpc:Linux-PAM-1.3.0$ make install
4. To verify the architecture of compiled files, you can use file command like below.
neeraj@lxpc:Linux-PAM-1.3.0$ file ~/lib-pam/lib/libpamc.so.0.82.1 lib-pam/lib/libpamc.so.0.82.1: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, not stripped You can notice ELF 32-bit LSB shared object, ARM.
Here it shows an example of how to cross compile a library from x86_64 machine, so that its executable will run in ARM machine.
Thats all about cross compilation.
Thank you for reading up to this. Hope this article gives you good understanding on cross compilation concepts.