Gentoo Cross Development Guide
1.
Deprecated
This guide is outdated by the Embedded Handbook.
Please use that from now on.
2.
Overview
Introduction
Cross development has traditionally been a black art, requiring a lot of
research, trial and error, and perseverance. Intrepid developers face a
shortage of documentation and the lack of mature, comprehensive open source
toolkits for multi-platform cross development. Ongoing work by the
Embedded
Gentoo project, the Gentoo Toolchain
herd, and other contributors is yielding a Gentoo-based development
platform that greatly simplifies cross development.
In this guide we demonstrate how to use these Gentoo development tools for
three common cross development tasks:
- Building a cross toolchain
- Cross-compiling binary packages
- Cross-compiling a kernel
The content of this guide is being merged into a forthcoming Gentoo Embedded
Handbook which will also cover cross development with
Hardened Gentoo,
the creation of embedded filesystem images, testing with
QEMU, deployment, and
more.
Terminology
- host system
- The system used for cross development
- sysroot
-
Any directory on the host system where a toolchain is installed; can be
used as a secondary root filesystem hierarchy to provide a minimal
non-native environment for creating cross-compiled binaries
- target system
-
The system the cross-compiled binaries will be deployed on
- toolchain
-
A set of packages required to build binaries for modern Unix-like operating
systems
The Gentoo toolchain
The Gentoo toolchain consists of the following packages:
-
binutils – Essential utilities for handling binaries
-
gcc – The GNU Compiler Collection
-
glibc – The GNU C Library
-
uclibc – A lean drop-in replacement for glibc optimized for embedded
systems
-
linux-headers – Kernel headers needed by system libc
-
gdb – Optional, for debugging binaries
All proper Gentoo systems have a toolchain installed as part of the base
system. This toolchain is configured to build binaries native to its host
platform.
In order to build binaries on the host system for a non-native platform
you'll need a special toolchain—a so-called cross toolchain—which can
target that particular platform. Gentoo provides a simple but powerful tool
called crossdev for this purpose. Crossdev can build and install
arbitrary GCC-supported cross toolchains on the host system, and because
Gentoo installs toolchain files into target-specific directories the toolchains
built by crossdev won't interfere with the host's native toolchain.
Environment variables
Certain environment variables used by the Gentoo toolchain and Portage can
thoroughly confuse developers inexperienced with cross development. The
following table explains some tricky variables and provides sample values based
on the cross development examples presented in this guide.
| Variable |
Meaning When Building Cross Toolchain |
Meaning When Building Cross Binaries |
| CBUILD |
Platform used to build the cross toolchain.
Example: CBUILD="i686-pc-linux-gnu"
|
Platform used to build the cross binary.
Example: CBUILD="i686-pc-linux-gnu"
|
| CHOST |
Platform running the cross toolchain.
Example: CHOST="i686-pc-linux-gnu"
|
Platform hosting the cross binary.
Example: CHOST="powerpc-softfloat-linux-uclibc"
|
| CTARGET |
Platform the cross toolchain produces binaries for.
Example: CTARGET="powerpc-softfloat-linux-uclibc"
|
Platform running the cross binary.
Example: CTARGET="powerpc-softfloat-linux-uclibc"
|
| ROOT |
Directory containing the filesystem where emerge should install
packages. Default value is "/".
Example: ROOT="/usr/powerpc-softfloat-linux-uclibc"
|
| PORTAGE_CONFIGROOT |
Directory containing the filesystem from which emerge should read
Portage configuration files. Often you will want to point this to the same
directory as ROOT. Default value is "/". Example:
PORTAGE_CONFIGROOT="/usr/powerpc-softfloat-linux-uclibc"
|
Note:
The PORTAGE_CONFIGROOT feature was introduced in
portage-2.1_pre10-r1.
|
Canonicalized machine names
Values for CBUILD, CHOST, and CTARGET, such as
i686-pc-linux-gnu and powerpc-softfloat-linux-uclibc, may seem
arbitrary but they're actually machine names in canonicalized form.
Canonicalized machine names consist of up to four dash-separated fields which
must occur in the following order:
- arch-vendor-OS-libc
arch specifies the CPU architecture, vendor specifies the
hardware platform or vendor, OS is the operating system, and libc
is the C library to use. Only arch is strictly required in all
cases—if you omit one or more of the remaining fields crossdev attempts to fill
in the missing values with its best guess. Nevertheless—for Linux machines at
least—it's good practice to specify all four fields. The libc field is
not supported for
Gentoo/FreeBSD, so for these machines it must always be omitted.
The following table lists field values known to work with crossdev, including
some special machine names which don't follow the naming convention just
described.
| CPU Architecture |
Hardware Platform or Vendor |
Operating System |
C Library |
alpha
arm / armeb
bfin
cris
hppa / hppa1.1 / hppa2.0 / hppa64
i386 / i486 / i586 / i686
ia64
m68k
mips / mipsel / mips64 / mips64el
nios2
powerpc / powerpc64
s390 / s390x
sh / sheb / sh4 / sh4eb / sh64
sparc / sparc64
vax
x86_64
|
gentoo
pc
softfloat
unknown
|
elf
freebsd6.0
freebsd6.1
linux
uclinux
|
eabi
gnu *
gnueabi
uclibc
|
| Special Machine Names |
avr
ee / iop / dvp
msp430
|
* Specifies glibc
Examples used in this guide
The example host system we'll use is an Athlon XP running Gentoo Linux with
glibc. This means that when building the cross toolchain, the value of
CHOST should be i686-pc-linux-gnu, and—whether building the cross
toolchain or cross binaries—CBUILD should always be set to
i686-pc-linux-gnu.
The example target system will be an embedded PowerPC 405 based Linux system
using uClibc. Since the PowerPC 405
processor has no floating point unit we should include the
SoftFloat
library when building our cross GCC. This gives us a CTARGET value of
powerpc-softfloat-linux-uclibc. When building cross binaries, the value
of CHOST should also be powerpc-softfloat-linux-uclibc.
Useful utilities for general cross development
-
binutils-config – Manages slotted versions of binutils
-
gcc-config – Manges slotted versions of gcc
-
crossdev – Builds and installs slotted toolchains for arbitrary
GCC-supported platforms
-
qpkg – Creates binary packages from cross-compiled ebuilds on the
sysroot
We'll be using all of these, so now is a good time to install those which
aren't already installed by default:
Code Listing 2.1: Installing tools for cross development |
# emerge --sync
# emerge -av portage-utils crossdev
|
3.
Building a Cross Toolchain
The first thing you should know about building a toolchain is that some
versions of toolchain components refuse to work together. Exactly which
combinations are problematic is a matter that's constantly in flux as the
Portage tree evolves. The only reliable way to determine what works is to run
crossdev, adjusting individual component versions as necessary, until crossdev
completes the toolchain build successfully. Even then, the cross toolchain may
build binaries which break on the target system. Only through trial and error
and patience will you arrive at a favorable combination of all factors.
Using crossdev
For our powerpc-softfloat-linux-uclibc example we'll be using a highly
specific combination of toolchain components that is known to work at the time
of this writing.
Open a terminal and do:
Code Listing 3.1: Building a toolchain with crossdev |
# USE="-*" crossdev -p -v \
--binutils 2.16.92 \
--gcc 3.4.6-r1 \
--kernel 2.6.11-r4 \
--libc 0.9.28 \
--ex-gdb \
--target powerpc-softfloat-linux-uclibc
|
If the output of the practice run looks correct, remove the -p option
and run the command again to actually build the toolchain. Crossdev will build
it in the following order:
- binutils
-
gcc – bootstrap stage, with SoftFloat; no g++ support
- linux-headers
- uclibc
-
gcc – second stage, adding g++ support
-
gdb – latest version
The completed toolchain will be installed to /usr/$CTARGET, which
in this case is /usr/powerpc-softfloat-linux-uclibc. This
directory is referred to as a sysroot.
Using gcc-config to set the crosscompiler spec on a hardened host system
If the host system was using a
hardened
Portage profile when the cross toolchain was built, you'll need to manually
adjust the active crosscompiler spec to use a non-hardened toolchain because by
default crossdev will set a hardened spec for the crosscompiler. If however you
do want to use the hardened toolchain for cross-compiling, you may skip to the
next section.
Code Listing 3.2: Selecting a non-hardened crosscompiler spec on a hardened host system |
# gcc-config powerpc-softfloat-linux-uclibc-3.4.6-vanilla
# source /etc/profile
|
This won't affect the host system's native compiler settings. To confirm:
Code Listing 3.3: Listing installed and active compilers |
# gcc-config -l
|
The host system's native compiler will be marked with a green asterisk
(*) and the crosscompiler will be marked with a light blue asterisk.
Using binutils-config
We won't need to for the examples in this guide, but for reference, you can
manually set the active binutils for the cross toolchain using
binutils-config. Usage is similar to gcc-config; see
binutils-config --help. In most cases the binutils selected
automatically during a cross emerge is the one you want.
Removing the cross toolchain
If at any time you wish to completely remove the cross toolchain built by
crossdev, do:
Code Listing 3.4: Removing the powerpc-softfloat-linux-uclibc cross toolchain |
# crossdev -C powerpc-softfloat-linux-uclibc
|
Note:
When prompted to confirm directory removals it's safe to answer y for
all.
|
4.
Preparing the Host Environment
Setting up sysroot for cross development
When cross developing, you'll usually want to avoid polluting the host system's
environment with the products of cross development activity, and to also
provide Portage with an alternate configuration and environment for cross
emerge operations. The simplest solution for this is to use sysroot.
For convenience let's set the environment variable SYSROOT on our host
system to point to the directory of the cross toolchain we'll be working with.
Code Listing 4.1: Setting the value of SYSROOT |
# export SYSROOT="/usr/powerpc-softfloat-linux-uclibc"
|
This variable should remain set while performing the tasks outlined in this
guide. Add it to your .bashrc to make it persistent across terminal
sessions.
Code Listing 4.2: Adding SYSROOT to ~/.bashrc |
# echo 'export SYSROOT="/usr/powerpc-softfloat-linux-uclibc"' >> ~/.bashrc
|
Create a $SYSROOT/etc/make.conf file, and assign any path-related
values in it as if SYSROOT were simply /. emerge
should automatically adjust these values whenever ROOT and
PORTAGE_CONFIGROOT are set to something other than /.
Here's the make.conf we'll use:
Code Listing 4.3: $SYSROOT/etc/make.conf |
ACCEPT_KEYWORDS="ppc"
ARCH="ppc"
CFLAGS="-Os -pipe"
CHOST="powerpc-softfloat-linux-uclibc"
CXXFLAGS="${CFLAGS}"
GENTOO_MIRRORS="http://open-systems.ufl.edu/mirrors/gentoo \
http://prometheus.cs.wmich.edu/gentoo \
http://mirror.datapipe.net/gentoo \
http://ftp.ucsb.edu/pub/mirrors/linux/gentoo/"
INPUT_DEVICES="keyboard"
MAKEOPTS="-j2"
USE="ppc symlink"
|
Copy the host system's /etc/make.globals to the sysroot and create
the directory for local profile configuration files:
Code Listing 4.4: Creating $SYSROOT/etc/make.globals |
# cp /etc/make.globals "${SYSROOT}/etc"
# mkdir -p "${SYSROOT}/etc/portage/profile"
|
We need to create a symlink for the sysroot Portage profile. Our example target
system calls for uClibc, so we'll choose a pre-existing Portage profile for a
minimal PPC uClibc base system:
Code Listing 4.5: Setting the sysroot Portage profile |
# ln -sn /usr/portage/profiles/uclibc/ppc "${SYSROOT}/etc/make.profile"
|
xmerge: A simple cross emerge wrapper
Creating cross-compiled binaries usually entails using emerge in
conjunction with a few modified environment variables. This can become tedious,
so we can make things easier by handling everything in a script that wraps
emerge. Here's an example of such a wrapper we'll call xmerge:
Code Listing 4.6: xmerge |
CBUILD=$(portageq envvar CHOST)
PORTAGE_CONFIGROOT="$SYSROOT"
if [[ "$1" == "--root" ]] ; then
ROOT="$2"
shift 2
else
ROOT="$SYSROOT"
fi
export CBUILD PORTAGE_CONFIGROOT ROOT
emerge $*
|
Make this script executable and save it somewhere in the host system's
PATH.
By default xmerge will install ebuilds to SYSROOT, using the
Portage configuration located there. You may specify an alternate location by
invoking xmerge with the --root directory option.
xkmake: A cross kernel make wrapper
We'll also want a convenience wrapper for cross kernel make operations:
Code Listing 4.7: xkmake |
make ARCH="ppc" CROSS_COMPILE="powerpc-softfloat-linux-uclibc-" INSTALL_MOD_PATH="$SYSROOT" $*
|
Call this script xkmake, make it executable, and put it somewhere in
the host system's PATH. The value for ARCH should reflect the
target system's CPU architecture (see
Canonicalized machine names) and
CROSS_COMPILE should be the same value as CTARGET but appended
with a dash.
Always use this make wrapper when working with kernel sources in the sysroot.
Usage is identical to how you would normally use make within the kernel
source tree.
5.
Cross-compiling Binary Packages
General cross-compilation using emerge
Before cross emerging, you need to assign the appropriate values to ROOT
and if applicable, PORTAGE_CONFIGROOT. You might also need to modify
CBUILD. Our xmerge script handles all of this,
as does
cmerge, an
emerge wrapper with more sophisticated capabilities.
Note:
cmerge is planned for future inclusion in the crossdev package.
|
For example, if we want to cross emerge ntp to the sysroot, we'd do:
Code Listing 5.1: Cross emerging ntp, the tedious way |
# CBUILD="i686-pc-linux-gnu" ROOT="$SYSROOT" PORTAGE_CONFIGROOT="$SYSROOT" emerge -av ntp
|
Or, using our wrapper, simply:
Code Listing 5.2: Cross emerging ntp, the easy way |
# xmerge -av ntp
|
Warning:
xmerge defaults to ROOT=$SYSROOT. Because SYSROOT is where
the cross toolchain is hosted on the host system, if you need to cross emerge
any toolchain components (i.e. gcc, system libc, binutils, kernel
headers, or gdb) for hosting on the target system, you do not want to use
ROOT=$SYSROOT; use the --root option to specify a different
directory instead. If you ignore this warning, you will end up overwriting your
cross toolchain with the target system's toolchain components and breaking cross
emerging completely, and the only way to fix it will be to delete your
SYSROOT directory and rebuild your cross toolchain.
|
Preparing cross-compiled packages for deployment with qpkg
Packages cross emerged to the sysroot can easily be packaged for deployment
using qpkg.
Code Listing 5.3: Creating a binary package |
# ROOT="$SYSROOT" qpkg -P "${SYSROOT}/var/tmp/binpkgs" ntp
|
The package is tarred, bzipped, and saved to
$SYSROOT/var/tmp/binpkgs with a .tbz2 extension.
Note:
The -P option was introduced into qpkg in
portage-utils-0.1.17.
|
6.
Cross-compiling a Kernel
Install the kernel sources to the sysroot.
Code Listing 6.1: Installing kernel sources for the target system |
# xmerge -av gentoo-sources
|
Configure and cross-compile the kernel and its modules using
xkmake:
Code Listing 6.2: Configuring and cross-compiling a kernel |
# cd "${SYSROOT}/usr/src/linux"
# xkmake menuconfig
# xkmake
|
7.
Acknowledgments
The author thanks Mike Frysinger, Ned Ludd, Peter S. Mazinger, and Diego
Pettenò for sharing their expertise during the preparation of this guide, and
Joakim Tjernlund for bug extermination.
8.
Resources
Pre-compiled Gentoo cross toolchains for x86 host systems
DistCC Cross-compiling Guide
Building a Gentoo/FreeBSD cross toolchain
|