This small howto will explain how to build a cross compiling toolchain for the ARM platform and how to cross compile various programs and libraries. I've written this howto during my endeavours creating my own linux distribution for the Compaq iPAQ H3600 which is powered by a StrongARM 1100 processor. My host platform is x86 compatible (An Intel Pentium III to be accurate) but maybe this howto is also valid for other host platforms.
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 a cross-compiling toolchain You need the following source packages to go on:
Package Used version Download
binutils
# ./configure --target=arm-linux 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 # 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 Finally change to the toolchain directory and create a symbolic link from include to sys-include:
# cd /usr/local/arm-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 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 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 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
# tar xvfz glibc-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 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) 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 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 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 \ 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 After you have unpacked the sources change to the source directory: # cd ncurses-5.2 Now configure the source:
# CC=arm-linux-gcc \ 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 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 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 \ Note that the binaries are not stripped automatically so you have to do this manually if needed.
Cross-compiling zlib After you have unpacked the sources change to the source directory: # cd zlib-1.1.4
# CC=arm-linux-gcc \ Building a shared version is a little bit more complicated:
# CC=arm-linux-gcc \
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 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 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 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 \ 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 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 After you have unpacked the sources change to the source directory: # cd flex-2.5.4 Now configure the source:
# CC=arm-linux-gcc \ 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 Cross compiling Python is tricky because:
The compiled python binary is used to compile and install the modules. # 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 Now rename these two binaries, otherwise they are deleted in the next step:
# mv python hostpython 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++ \ 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 \ 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=/usr \ 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. |
|