Gentoo Logo

Gentoo Cross Development Guide

Content:

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:

  1. Building a cross toolchain
  2. Cross-compiling binary packages
  3. 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

#!/bin/bash
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

#!/bin/bash
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



Print

Page updated August 22, 2006

Summary: This guide demonstrates the use of Gentoo tools to develop for non-native platforms.

Alex Tarkovsky
Author

Mike Frysinger
Reviewer

Donate to support our development efforts.

Copyright 2001-2014 Gentoo Foundation, Inc. Questions, Comments? Contact us.