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 crosstool.
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:
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 <linux/limits.h>
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: db-4.0.14.tar.gz
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=<root-directory> 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=<root-directory>
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: Linux-PAM-0.75.tar.gz
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=<root-directory>
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: zlib-1.1.4.tar.gz
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=<root-directory>
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: bash-2.05a.tar.gz
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=<root-directory>
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 > <root-directory>/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: busybox-0.60.2.tar.gz
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=<root-directory>
Cross-compiling flex
Used version: flex-2.5.4a.tar.gz
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=<root-directory>/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: Python-2.2.1.tgz
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
here.
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.
Using a howto from this site I managed to cross-compile python 2.5.1 for my embedded linux board . Although AXIS provides python 2.4 with their SDK and configures it with no threads and stuff, I compiled the the original python 2.5.1 with only this patch
Tracked: Sep 26, 15:57
Tracked: Sep 26, 16:56