Cross-compiling OSS packages
From Tuxation
Most open-source software packages include a script file called configure. This is especially true for popular packages that are built with portability in mind. Unfortunately, you can't find this luxury in all packages out there and thus cross-compiling (or sometimes referred to as porting) it can potentially be a pain.
The usual steps involved in cross-compiling are the following:
- Download the software package from an FTP or HTTP website or Version Control repository.
- Decompress the file. Most packages are distributed in compressed form especially when downloading from FTP or HTTP sites.
- Run the configure script.
- Run make.
- Run make install.
- Finally, download to the target machine.
Cross-compiling requires that the build machine be equipped with what is referred to as the toolchain. A toolchain contains the utilities, binaries and libraries used to compile programs for a target machine on a different host machine. Say cross-compiling hello.c on an i386-based machine (Desktop PC) and run the resulting hello application on ARM-based machine (Samsung S3C2410 board).
Contents |
The cross-compiler
There are different ways of setting the Desktop PC so that it can cross-compile programs. However you setup your desktop is up to you but basically you'll need:
- gcc cross-compiler for your target architecture (eg. arm-linux-gcc for ARM)
- Cross-compiled libc library files. If you can't get the pre-built ones, you can always cross-compile libc yourself. This is quite a process but libc is relatively cross-compilable.
- Binary utilities commonly called binutils which contains the linker, assembler, and other utilities like for manipulating the resulting binaries like disassembling and such.
Building the toolchain from scratch used to be a craze but now, it's quite easy to find pre-built ones and are quite easy to setup on your Desktop PC as well. Take the Debian-based Linux distribution for example, you can just do the following to cross-compile for ARM:
- Go to http://debian.speedblue.org/
- Download binutils-arm_2.17-1_i386.deb, glibc-cross-arm_2.4-1_i386.deb and gcc-3.3-arm_3.3-3.3.3-2_i386.deb.
- Then install the ".deb" files with dpkg -i.
That's it, you should now have a toolchain installed in /usr/arm/.
compilation environment
Most applications use some environment variables for its build process. Be careful, though, some applications don't and require that you manually edit the Makefiles and/or Config files.
Basically you need to configure the package such that it'll use your toolchain during build.
These are the environment variables you need to set: (WARNING: This is not always true so make sure to double check with the Makefiles and/or Config files what the needed variables are.)
- CC - path to the C cross-compiler
- CPP or CXX - path to the C++ cross-compiler
- LDFLAGS - linker flags
Setting the environment variables varies between shells, so consult your man pages if the following don't work:
$ export CC=/usr/arm/bin/arm-linux-gcc $ export CPP=/usr/arm/bin/arm-linux-cpp $ export CXX=/usr/arm/bin/arm-linux-cpp
Depending on what you intend to build, setup LDFLAGS accordingly. Below shows how to compile stripped binaries.
$ export LDFLAGS="-s -Xlinker -rpath /lib -Xlinker -rpath-link /usr/arm/arm-linux/lib"
-Xlinker -rpath /lib tells the cross-linker that the resulting binaries will look for the dynamic libraries in /lib directory.
-Xlinker -rpath-link /usr/arm/arm-linux/lib tells the cross-linker to link with the libraries pointed to by the path during build.
Remember that each shell session can have different environment variables and settings. So if you want to compile on all your shell sessions and don't want to manually set these on each, you can put these in your .bashrc or .bash_profile files (if you're using bash shell, and they'll automatically be set every time you open a new shell.
The configure script
The configure script of a software package lives on the base directory of the package tree. It's usually just a shell script that can be run usually on a bash shell (and variant).
Each configure script is specific to it's software package although the structure, output, and usage is somewhat similar between packages.
To see how to use the script and what the options are, just type in:
$ ./configure --help
You can then run the script with the options you need. For example, here's how I configure the php package at one time:
./configure --host=i386-linux-gnu --target=arm --prefix=install-arm \\ --disable-short-tags --without-mysql \\ --without-pear --disable-all --disable-short-tags \\ --with-thttpd=../../thttpd/thttpd-2.21b
The script should show you some messages on what it's doing and spit errors when it found some.
When the script finds no errors, it will then create the needed files in order to build the package; usually Configs and Makefiles.
To actually build the package, usually you just run make.
$ make
If you have specified the install directory, using the --prefix option in the configure script, you can then finish the build by installing the resulting binaries to the directory you specified.
$ make install
build vs. target vs. host
Usually, target and host mean the same thing: where the resulting binaries will run on. build specifies the machine you're building on.
In the case of GDB, when we're doing cross-debugging, host and build are set to i386 so that the resulting binary can run on the Desktop but target is set to ARM so that GDB can understand ARM machine code and not i386.
So for most packages, you can just configure them easily by:
$ ./configure --host=i386-linux-gnu --target=arm
Be careful, though, some packages require you to set the operating system name especially when the package supports different operating systems; you'll have to set --target accordingly. For example, to build for Linux on ARM, you say:
$ ./configure --host=i386-linux-gnu --target=arm-linux
You'll know that you have to specify the operating system anyway as the configure script will spit out an error about it.