Introduction
I maintain the lsvpd package. The target platform for lsvpd is PPC and recently my PPC build machine stopped rebooting. I decided to get serious about building all the binary packages on my laptop instead of relying on having machines around with a suitably old version of glibc. An old glibc is needed because I build one PPC RPM package that needs to run on various SLES and RHEL releases and one Debian PPC package that should also run on as many versions as possible. I also want to build packages for i386 and x86_64.
Crosstool
Most of the work is done by crosstool, which is excellent. The biggest problem is figuring out how to build a configuration that works. I downloaded crosstool and copied and hacked configuration files until it worked. So what worked?
I copied gcc-4.0.1-glibc-2.2.2-hdrs-2.6.11.2.dat
to gcc-martins.dat and edited it to look like this:
BINUTILS_DIR=binutils-2.16.1
GCC_CORE_DIR=gcc-2.95.3
GCC_DIR=gcc-4.0.2
GLIBC_DIR=glibc-2.2.5
LINUX_SANITIZED_HEADER_DIR=linux-libc-headers-2.6.12.0
GLIBCTHREADS_FILENAME=glibc-linuxthreads-2.2.5
This meant I would be using the latest tools, with a suitably
old C library and some recent kernel headers. I then copied
demo-ppc604.sh to demo-martins.sh and
edited to make it look like this:
#!/bin/sh
set -ex
TARBALLS_DIR=$HOME/downloads
RESULT_TOP=/opt/crosstool
export TARBALLS_DIR RESULT_TOP
GCC_LANGUAGES="c,c++"
export GCC_LANGUAGES
# Really, you should do the mkdir before running this,
# and chown /opt/crosstool to yourself so you don't need to run as root.
mkdir -p $RESULT_TOP
# Build the toolchain. Takes a couple hours and a couple gigabytes.
eval `cat powerpc-604.dat gcc-martins.dat` sh all.sh --notest
echo Done.
This uses a 32-bit PPC configuration, builds the C and C++
compilers, and installs the results somewhere under
/opt/crosstool.
The big step was to run ./demo-martins.sh. This
caused crosstool to download all the various bits -
if I already had them I could have put them into
/home/martins/downloads and crosstool
would have found them - and compiled and installed everything.
Nice!
Problems
-
I originally tried setting
LINUX_DIRto2.6.14.3rather than settingLINUX_SANITIZED_HEADER_DIR. This didn't work, due to PPC-related restructuring in the kernel tree, which started appearing in2.6.14.3. I then triedlinux-2.6.13, which worked nicely... although I had to hack some of the include files by hand when trying to compile things later. This led me to useLINUX_SANITIZED_HEADER_DIRinstead. -
I use
ccontrol
but it couldn't cope with some of the make
trickery involved with getting glibc installed
and it tried to install into
/usr/lib. That could've been nasty, but happily I was running as me and notroot. Temporarily removing mymaketoccontrollink made things work. - A quick test at the end of the compilation process seemed to fail to compile a static version of "hello world", but I ignored that and pressed on!
Installing Support Libraries
To build lsvpd I was going to need PPC versions of
libsysfs.a (from
sysfsutils
- version 1.30) and
and libsgutils.a (from
sg3_utils).
The right thing to do would probably have been to build Debian
packages with weird names and weird file locations. However, I
decided to just build the bits I needed and install them into
the cross-compiler tree by hand.
libsysfs.a
This one was easy to build. The following commands built the library:
CC=/opt/crosstool/gcc-4.0.2-glibc-2.2.5/powerpc-604-linux-gnu/bin/powerpc-604-linux-gnu-gcc \
./configure --host=powerpc-unknown-linux
make
This left these files, which needed to be installed:
include/dlist.h
include/libsysfs.h
lib/.libs/libsysfs.a
I decided to initially install them outside the cross-compiler tree, so I could more easily rebuild the cross-compiler if needed:
/opt/cross-extras/powerpc-gcc-4.0.2-glibc-2.2.5/
|-- include
| `-- sysfs
| |-- dlist.h
| `-- libsysfs.h
`-- lib
`-- libsysfs.a
After some experimentation to find the right
include and lib subdirectories, I
settled upon these symbolic links:
/opt/crosstool/gcc-4.0.2-glibc-2.2.5/powerpc-604-linux-gnu/powerpc-604-linux-gnu/
|-- include
| `-- sysfs -> /opt/cross-extras/powerpc-gcc-4.0.2-glibc-2.2.5/include/sysfs
`-- lib
`-- libsysfs.a -> /opt/cross-extras/powerpc-gcc-4.0.2-glibc-2.2.5/lib/libsysfs.a
libsgutils
Due to a lack of a suitable libtool and a lack of
interest on my part to try and build one, I had to hack things a
little. There's a special make file that builds the commands in
the package without building a separate library, so I used it to
build 2 object files and then built the library by hand:
make \
CC=/opt/crosstool/gcc-4.0.2-glibc-2.2.5/powerpc-604-linux-gnu/bin/powerpc-604-linux-gnu-gcc \
-f lib_no_lib/Makefile.no_lib \
sg_cmds.o sg_lib.o
ar crv libsgutils.a sg_cmds.o sg_lib.o
Installation details:
libsgutils.a
sg_cmds.h
sg_lib.h
/opt/cross-extras/powerpc-gcc-4.0.2-glibc-2.2.5/
|-- include
| `-- scsi
| | |-- sg_cmds.h
| | `-- sg_lib.h
`-- lib
`-- libsgutils.a
/opt/crosstool/gcc-4.0.2-glibc-2.2.5/powerpc-604-linux-gnu/powerpc-604-linux-gnu/
|-- include
| `-- scsi
| |-- sg_cmds.h -> /opt/cross-extras/powerpc-gcc-4.0.2-glibc-2.2.5/include/scsi/sg_cmds.h
| `-- sg_lib.h -> /opt/cross-extras/powerpc-gcc-4.0.2-glibc-2.2.5/include/scsi/sg_lib.h
`-- lib
`- libsgutils.a -> /opt/cross-extras/powerpc-gcc-4.0.2-glibc-2.2.5/lib/libsgutils.a
Building RPM packages
This was surprisingly simple. I put these lines into
~/.rpmmacros:
%_topdir /home/martins/tmp/rpm
%__cc /opt/cross-extras/rpm-bin/%{_target}-gcc
Then I populated the relevant directories:
/home/martins/tmp/rpm/
|-- BUILD
|-- RPMS
|-- SOURCES
|-- SPECS
`-- SRPMS
/opt/cross-extras/rpm-bin
`-- ppc-linux-gcc -> /opt/crosstool/gcc-4.0.2-glibc-2.2.5/powerpc-604-linux-gnu/bin/powerpc-604-linux-gnu-gcc
I had to update lsvpd.spec to say:
make CC=%__cc
This also works when not cross-building.
Now an RPM package can be built by running:
rpmbuild --target ppc-unknown-linux -tb --clean lsvpd-0.14.1.99.tar.gz
Building Debian packages
This was surprisingly difficult! I installed
dpkg-cross, which came with slightly dodgy
documentation. This package wraps the
dpkg-buildpackage command so you can do fancy
cross-building things. First I had to change a line in
/etc/dpkg-cross/cross-compile to move the world to
a sensible place:
crossbase = /opt/cross-extras/dpkg-cross
Then I populated this directory:
/opt/cross-extras/dpkg-cross/
`-- powerpc-linux-gnu
`-- bin
`-- powerpc-linux-gnu-gcc -> /opt/crosstool/gcc-4.0.2-glibc-2.2.5/powerpc-604-linux-gnu/bin/powerpc-604-linux-gnu-gcc
This changed subtly under version 1.26: having -gnu
in the paths is a new thing.
In theory, the package could now be built with:
dpkg-buildpackage -apowerpc -rfakeroot -us -uc -b
Notice how there's no space between -a and
powerpc? If you have a space you're told:
dpkg-buildpackage: Architecture is not specified.
I've seen more helpful error messages!
Reality was a little more exciting than theory. After hacking
my debian/rules file so that it no longer used the
deprecated debstd command but used all the funky
little debhelper commands instead (a feat not worth
documenting here) I noticed these things.
-
dh_stripisn't cross-build aware. Sorry, no stripped executables! -
dh_shlibdepscan't find the dependencies. If you create a link called/opt/cross-extras/dpkg-cross/powerpc-linux-gnu/libto point to the place that has all the libraries, things get marginally better since the libraries can be found. However, since they're not in Debian packages, and Debian insists on using package dependencies rather than file dependencies (for very good reasons), it is a case of "game over". I ended up hard-coding the C library dependency intodebian/control:Depends: libc6 (>= 2.2.5-1)This isn't a great solution, but if I only ever build with my cross-compiler, then things will be fine.
Other than that, cross-building Debian packages isn't too hard.
Conclusions
crosstool made most of the job easy, with rpm and dpkg-cross providing good support. I also managed to build a cross-compiler for i386 (again with an old libc) - the process was exactly the same as for PPC. I'm yet to succeed in building a x86_64 cross-compiler.