Note: I'm currently no longer active in cross-compiling. I can't guarantee that this howto will work for you and I can't give you any support for it and I'm most likely not going to update this howto anymore. If you are currently fiddling with cross-compiling you already have more know-how than I have now. If you are new to cross-compiling you definetly want to take a look at Dan Kegel's .
Building cross-compiling toolchain
Required sources
I suppose you have no access to any precompiled ARM software so I'll explain how to build a cross compiling toolchain from the ground up, including glibc.
You need the following source packages to go on:
Package |
Used version |
Download |
Linux Kernel |
2.4.17 |
|
ARM Kernel patch |
2.4.17-rmk4 |
|
binutils |
2.11.2 |
|
gcc |
2.95.3 |
|
glibc |
2.2.4 |
|
glibc linuxthreads add-on |
2.2.4 |
|
binutils
Unpack the binutils tarball into a temporary directory, change to the unpacked binutils directory and run the following commands:
# ./configure --target=arm-linux
# make
# make install
You have now some arm-linux-*
binaries in /usr/local/bin. These are the binutils used by the cross-compiling toolchain. And you'll find the new directory /usr/local/arm-linux/
. This is where the cross-compiling toolchain will be installed.
You can check if the binutils are compiled correctly by calling arm-linux-ar
. This tool outputs the supported targets in its command line help. You should find targets like elf32-littlearm there.
Linux Kernel header files
To compile gcc we need some header files from the linux kernel source. Unpack the kernel source code in a temporary directory and change to the unpacked source directory. You'll need to patch the kernel with the ARM kernel patch. You do this by running this command:
# zcat path-to-arm-patch/patch-2.4.17-rmk4.gz | patch -p1
Now you need to configure the kernel by calling this command:
# make menuconfig ARCH=arm
Notice that you need to specify ARCH=arm
otherwise you are going to configure the kernel for your host architecture which maybe a x86 machine.
You don't need to do a complete configuration unless you want to compile the kernel now. Up to now you don't have a cross compiler so you can't compile it anyway. All you need to do is to select the correct processer type. In my case I have selected SA1100-based in ARM system type and Compaq iPAQ H3600/H3700 in SA11x0 Implementations. Now save the configuration and call the following command to finish the kernel configuration:
# make dep
Now copy the include files from the kernel source to the toolchain directory:
# mkdir /usr/local/arm-linux/include
# cp -dR include/asm-arm /usr/local/arm-linux/include/asm
# cp -dR include/linux /usr/local/arm-linux/include/linux
Finally change to the toolchain directory and create a symbolic link from include to sys-include:
# cd /usr/local/arm-linux/
# ln -s include sys-linux
gcc, which we will compile now, is searching for the include files in sys-linux by default. You can use the --with-headers
configure-option to specify an other directory but this results in copying the specifed directory to sys-linux. So I think it's better to create a symbolic link to avoid redundant files.
gcc
Unpack the gcc source code and change to the unpacked source directory. We currently don't have a running glibc so we can't compile the whole compiler suite. But for now it is enough to compile only the C compiler. Later we can compile the glibc with this cross compiler and after that we can compile the whole compiler suite.
It may be necessary to modify the gcc source a little bit. I have done this because otherwise I was not able to compile, I got these error messages:
./libgcc2.c:41: stdlib.h: No such file or directory
./libgcc2.c:42: unistd.h: No such file or directory
.make[3]: *** [libgcc2.a] Error 1
There are rumors that it is not always needed. If you think (or know, or learn) that you need it, edit the file gcc/config/arm/t-linux
, search this line:
TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC
And change it to this:
TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC -Dinhibit_libc -D__gthr_posix_h
Now configure the source code, compile and install:
# ./configure --target=arm-linux --disable-threads --enable-languages=c
# make
# make install
You have now a running cross compiler (/usr/local/bin/arm-linux-gcc
) but without glibc it is not really useful. So let's cross-compile that beast.
glibc
Unpack the glibc tarball in a temporary directory as usual. Then switch to the unpacked source directory and unpack the linuxthreads add-on into it:
# tar xvfz glibc-2.2.4.tar.gz
# cd glibc-2.2.4
# tar xvfz ../glibc-linuxthreads-2.2.4.tar.gz
Now set the environment variable CC to arm-linux-gcc because we want the glibc to be cross-compiled for the ARM platform. Then configure, compile and install the beast:
# export CC=arm-linux-gcc
# ./configure arm-linux --target=arm-linux --prefix=/usr/local/arm-linux --enable-add-ons
# make
# make install
Be sure you use the --prefix
parameter correctly, otherwise you mess up your hosts glibc installation.
You'll now find a lot of new files and directories in /usr/local/arm-linux
. These are the glibc headers, libraries and utitilies.
Notice that you can't use this compiled glibc on the target machine because of the specified prefix. If you want to compile a glibc which you can copy to your target machine, use an empty prefix (--prefix=
) instead and use the install_root
parameter to specify the installation directory:
# make install install_root=/path/to/target/root
Finally, make sure you unset the CC environment variable (with unset CC
), because in the next step we are going to recompile the cross compiler and we don't want to cross-compile the cross-compiler.
gcc (Second try)
Now we have a cross compiled glibc so we can now go on and compile the whole gcc compiler suite.
You can use the already unpacked source code of gcc but you have to remove the changes you have made and you should call make distclean
to clean up the source. To be sure to do it right I suggest you delete the old source directory and unpack the gcc sources again. Whatever, after you have a clean gcc source directory, change into it, configure the source, compile and install it:
# ./configure --target=arm-linux
# make
# make install
If compilation fails because PATH_MAX is undeclared in basicio.c
then add the following line to the file libchill/basicio.c
somewhere between all the other includes at the top of the file:
#include
Call make
again and it should compile fine now.
That's it. You should now have a working cross-compile toolchain for the ARM platform. If you want to cross-compile a program just set the CC environment-variable to arm-linux-gcc and compile the program as usual.
Cross-compiling various libraries
Cross-compiling Berkeley DB
Used version:
After you have unpacked the sources change to the directory build_unix
:
# cd db-4.0.14/build-unix
Now the source code needs to be configured. The Berkeley DB uses autoconf and uses compiled programs to test various things. This won't work during cross compile so these checks has to be overridden. That's what all the environment variables in the following command are doing:
# db_cv_sprintf_count=yes \
db_cv_fcntl_f_setfd=yes \
db_cv_mutex="no" \
db_cv_alignp_t="unsigned long" \
CC=arm-linux-gcc \
../dist/configure --host=arm-linux --prefix=/usr
This configures the sources to cross-compile for the ARM platform and to use /usr
as install prefix. Note: If you are going to use this library in your cross-compiling toolchain and not on the target machine you have to specify the prefix /usr/local/arm-linux
or wherever your toolchain is installed.
To compile the sources, just type:
# make
Now install the binaries:
# make install prefix= strip=arm-linux-strip
If you are going to use this library in your cross-compiling toolchain you don't need to specify prefix because the configured one is already the right one.
Cross-compiling ncurses
Used version: ncurses-5.2.tar.gz
After you have unpacked the sources change to the source directory:
# cd ncurses-5.2
Now configure the source:
# CC=arm-linux-gcc \
./configure arm-linux --target=arm-linux --with-shared --prefix=/usr
Note: If you are going to use this library in your cross-compiling toolchain and not on the target machine you have to specify the prefix /usr/local/arm-linux
or wherever your toolchain is installed.
To compile the sources type this:
# make HOSTCC=gcc CXX=arm-linux-c++
HOSTCC is needed because some tools needs to be compiled for the host system. The documentation says this variable has the name BUILD_CC but this is wrong. Never trust documenations
Now install the files:
# make install DESTDIR=
If you are going to use this library in your cross-compiling toolchain you don't need to specify prefix because the configured one is already the right one.
Cross-compiling Linux-PAM
Used version:
After you have unpacked the sources change to the source directory:
# cd Linux-PAM-0.75
The configure script of Linux-PAM seems to be realy ugly. Some commands are hardcoded and it seems not to be possible to override them. So you have to modify the configure script a little bit. Here is the mapping from which you can see what you need to search and with what you have to replace it:
Search for |
Replace with |
GCC=gcc |
GCC=arm-linux-gcc |
LD=ld |
LD=arm-linux-ld |
LD_D="gcc -shared -Xlinker -x" |
LD_D="$CC -shared -Xlinker -x" |
Now you can configure the source for cross-compiling:
# ./configure arm-linux --target=arm-linux --prefix=/usr
Note: If you are going to use this library in your cross-compiling toolchain and not on the target machine you have to specify the prefix /usr/local/arm-linux
or wherever your toolchain is installed. Additionaly you need to specify the following parameter, otherwise some include files are installed in the wrong place:
--enable-includedir=/usr/local/arm-linux/include
To compile the sources, just type:
# make
Now install the files:
# make install FAKEROOT=
If you are going to use this library in your cross-compiling toolchain you have to use this command to install the files:
# make install \
DOCDIR=/usr/local/arm-linux/share/doc/Linux-PAM \
MANDIR=/usr/local/arm-linux/share/man
Note that the binaries are not stripped automatically so you have to do this manually if needed.
Cross-compiling zlib
Used version:
After you have unpacked the sources change to the source directory:
# cd zlib-1.1.4
Now the source code needs to be configured. If you want to compile a static version of this library use this configure command:
# CC=arm-linux-gcc \
./configure --prefix=/usr
Building a shared version is a little bit more complicated:
# CC=arm-linux-gcc \
LDSHARED="arm-linux-gcc -shared -Wl,-soname,libz.so.1" \
./configure --shared --prefix=/usr
Note: If you are going to use this library in your cross-compiling toolchain and not on the target machine you have to specify the prefix /usr/local/arm-linux
or wherever your toolchain is installed.
To compile the sources, just type:
# make
Now install the binaries:
# make install prefix=
If you are going to use this library in your cross-compiling toolchain you don't need to specify prefix because the configured one is already the right one.
Note that the binaries are not stripped automatically so you have to do this manually if needed.
Cross-compiling various programs
Cross-compiling bash
Used version:
After you have unpacked the sources change to the source directory:
# cd bash-2.05a
There is a small bug in the Makefile template that prevents cross-compiling. To fix it edit the file Makefile.in
and search for this part:
bashversion$(EXEEXT): patchlevel.h conftypes.h version.h version.o $(SUPPORT_SRC)bashversion.c
$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) $(CPPFLAGS) -o $@ $(SUPPORT_SRC)bashversion.c version.o
Now replace the two occurences of version.o
with version.c
so it looks like this:
bashversion$(EXEEXT): patchlevel.h conftypes.h version.h version.c $(SUPPORT_SRC)bashversion.c
$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) $(CPPFLAGS) -o $@ $(SUPPORT_SRC)bashversion.c version.c
The reason behind this is: The binary bashversion
needs to be compiled for the build platform. But version.o is been compiled for the target platform so it can't be linked. So we simply replace the object file with the source file. In this case the source file is compiled again but this time for the correct platform.
Now the source code needs to be configured. Bash uses autoconf and uses compiled programs to test various things. This won't work during cross compile so these checks has to be overridden. That's what all the environment variables in the following command are doing:
# ac_cv_sys_restartable_syscalls=yes \
ac_cv_func_setvbuf_reversed=yes \
./configure --build=i386-linux --host=arm-linux --enable-readline --prefix=/
This configures the sources to cross-compile for the ARM platform and to use /
as install prefix. You'll see some warnings, that's because some checks fail and default values are used. I think these default values are ok so I don't override them like the other two ac-options above.
To compile the sources, just type:
# make
Now install the files:
# make install prefix=
Note that the root-directory must be an absolute path. Relative paths will not work.
If you get the error message unknown option --dir-file
your texinfo installation is pretty old. This may happen if you are running Debian GNU/Linux. If you can't (or don't want to) update your texinfo installation you can do this: Edit the file doc/Makefile.in
and search for this part:
install-info --dir-file=$(DESTDIR)$(infodir)/dir $(DESTDIR)$(infodir)/bash.info; \
And modify it so it looks like this:
install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/bash.info; \
Now you need to add a dummy dir-file file if it's not already present:
# echo 1 > /info/dir
Now run the above configure
command again so the Makefile is regenerated. Now the call to make install
should work like a charm.
Note that the installed binaries are not stripped automatically so you have to do it manually by using arm-linux-strip
.
Cross-compiling BusyBox
Used version:
After you have unpacked the sources change to the source directory:
# cd busybox-0.60.2
To compile the sources type this:
# make CROSS=arm-linux-
Now install the files:
# make install PREFIX=
Cross-compiling flex
Used version:
After you have unpacked the sources change to the source directory:
# cd flex-2.5.4
Now configure the source:
# CC=arm-linux-gcc \
RANLIB=arm-linux-ranlib \
./configure arm-linux --target=arm-linux --prefix=/usr
Note: If you are going to use this program (or better: the included libfl) in your cross-compiling toolchain and not on the target machine you have to specify the prefix /usr/local/arm-linux
or wherever your toolchain is installed.
To compile the sources type this:
# make AR=arm-linux-ar
Now install the files:
# make install prefix=/usr
Note that you need to add /usr
to the root-directory.
If you are going to use this program in your cross-compiling toolchain you don't need to specify prefix because the configured one is already the right one.
Cross-compiling Python
Used version:
Cross compiling Python is tricky because:
- The compiled python binary is used to compile and install the modules.
- The parser generator which is linked to some Python libraries is executed during compilation.
- The compiled modules are checked if they can be imported. But they can't be imported because they are not running on the host system. These modules are automatically removed which is bad.
I found no way to cross compile Python without modifiying the source code. I created a patch which can be downloaded . This patch needs to be applied directly after you have unpacked the sources:
# cat python-cross-compiling.diff | patch -p0
Now change to the patched source code directory:
# cd Python-2.2.1
Two programs (python and Parser/pgen) are executed during the cross compilation so we need them to be compiled for the host system. To do this type this:
# ./configure
# make python Parser/pgen
Now rename these two binaries, otherwise they are deleted in the next step:
# mv python hostpython
# mv Parser/pgen Parser/hostpgen
Because we are now going to cross-compile python, clean up the source code first:
# make distclean
To configure the source code for cross-compilation type this:
# CXX=arm-linux-g++ \
CC=arm-linux-gcc \
AR=arm-linux-ar \
RANLIB=arm-linux-ranlib \
./configure arm-linux --target=arm-linux --prefix=/usr
Now comes the tricky part which needs the patch you have applied before. The patch introduces the environment variables HOSTPYTHON and HOSTPGEN so the host-compiled versions of python and Parser/pgen can be executed.
# make HOSTPYTHON=./hostpython \
HOSTPGEN=./Parser/hostpgen \
BLDSHARED="arm-linux-gcc -shared"
This compilation can take some time. Watch out for errors. Maybe some modules are not compiled because your cross-compiling toolchain is missing some libraries like OpenSSL or expat.
The installation of Python also requires to execute the python binary. And during the installation of the python modules a python script checks if the modules can be imported. If not, they are removed. That's bad because all modules can't be imported because they are compiled for the target system. The patch fixes this behaviour by introducing the variable CROSS_COMPILE. If set to yes the modules are not removed if they can't be imported.
To install python type this:
# make install prefix=<Root-directory>/usr \
HOSTPYTHON=./hostpython \
BLDSHARED="arm-linux-gcc -shared" \
CROSS_COMPILE=yes
Notice that you have to specify /usr behind the path to the targets root-directory.
You are done. You should now have a complete working cross-compiled Python suite. Copy it to your target machine and be happy.