From Segfault
Jump to navigation Jump to search




Debian, Ubuntu:

sudo apt-get install autoconf automake bison curl cvs flex g++ gawk gcc git gperf help2man libgmp-dev libncurses-dev libstdc++-dev libtool libtool-bin make mercurial patch subversion texinfo wget


sudo yum install autoconf automake bison curl cvs flex gawk gcc gcc-c++ git glibc-static gmp-devel gperf libstdc++-devel libstdc++-static libtool make mercurial ncurses-devel patch subversion texinfo wget


sudo zypper install autoconf automake bison curl cvs flex gawk gcc gcc-c++ git glibc-devel-static gmp-devel gperf libstdc++-devel libtool make mercurial ncurses-devel patch subversion texinfo wget


For MacOS it gets more complicated[1][2], we need the following[3]:

  • gcc (>= 4.3) installed or clang for MacOS X 10.x
  • Some GNU utilities: lzmautils, libtool, binutils, gsed, gawk
  • A case sensitive file system for ct-ng's build and target directories

Install the prerequisites:

sudo port install git gsed coreutils libtool gawk wget autoconf automake

There's no suitable[4] binutils package for MacPorts, so let's build it ourselves:

gpg --keyserver hkp:// --recv-keys 4AE55E93
gpg --verify binutils*.tar.bz2.sig
tar -xjf binutils*.tar.bz2 && cd binutils*
./configure --prefix=/opt/binutils && make && sudo make install

Make the new binutils available in PATH:

export PATH=/opt/binutils/bin:$PATH

While we e should be able to install crosstool-ng anywhere on the system disk, we still need a case sensitive file system to build our tool chain.

$ mkfile -n -v 4g /var/tmp/ct-disk.img                    # -n creates an sparse file
$ hdiutil attach -nomount /var/tmp/ct-disk.img

Note: hdiutil(1) expects the image filename to end in .img, otherwise it may fail with:

hdiutil: attach failed - image not recognized

Now we can create a case sensitive file system[5] on this virtual disk:

 $ diskutil eraseDisk jhfsx ct-disk disk4
 Started erase on disk4
 Unmounting disk
 Creating the partition map
 Waiting for the disks to reappear
 Formatting disk4s1 as Mac OS Extended (Case-sensitive, Journaled) with name ct-disk
 Initialized /dev/rdisk4s1 as a 1024 MB case-sensitive HFS Plus volume with a 8192k journal
 Mounting disk
 Finished erase on disk4

The disk should now be mounted on /Volumes/ct-disk, let's prepare it for the toolchain build later on:

mkdir -p /Volumes/ct-disk/{ctng,tools}
ln -s /Volumes/ct-disk/ctng /var/tmp/ctng


Download Crosstool-NG:

gpg --keyserver hkp:// --recv-keys A156D05D
gpg --verify crosstool-ng*tar.xz.sig
xz -dc crosstool-ng*tar.xz | tar -xf -
cd crosstool-ng-*

Or, via Git:[6]

git clone crosstool-ng-git
cd crosstool-ng-git
git checkout -b local crosstool-ng-1.22.0             # We will use a stable version this time

Note: crosstool-ng v1.20 still has a bug in scripts/[7] on BSD like systems that we need to address first:

diff --git a/scripts/ b/scripts/
index cd65d5b..53ac552 100644
--- a/scripts/
+++ b/scripts/
@@ -125,7 +125,7 @@ CT_DoLog INFO "Build started ${CT_STAR_DATE_HUMAN}"
 # We really need to extract from ,config and not .config.2, as we
 # do want the kconfig's values, not our mangled config with arrays.
 CT_DoStep DEBUG "Dumping user-supplied crosstool-NG configuration"
-CT_DoExecLog DEBUG ${grep} -E '^(# |)CT_' .config
+CT_DoExecLog DEBUG ${grep} -E '^(# )?CT_' .config

 CT_DoLog DEBUG "Unsetting and unexporting MAKEFLAGS"

Now we can install Crosstool-NG:

export PREF=/opt/ctng
./configure --prefix=$PREF

When building on MacOS X, we need our GNU tools in PATH:

PATH=/opt/local/bin:$PATH ./configure --prefix=$PREF --with-libtool=glibtool --with-libtoolize=glibtoolize

Build with:

sudo make install
ln -s /Volumes/ct-disk/tools /opt/ctng/tools                                        # On MacOS X, the toolchain directory needs to be case sensitive

sudo install -v -m0644 -o root -g root ct-ng.comp /etc/bash_completion.d/           # For bash-completion
echo "export PATH=\$PATH:$PREF/bin" | sudo tee /etc/profile.d/

On our NFS-mounted share this failed (root was not allowed to read /home where the build took place) and we did make install like this:

sudo mkdir -p $PREF && sudo chown $USER $PREF
make install
sudo chown -R root:root $PREF

Building a toolchain

$ mkdir -p /var/tmp/ctng/build /usr/local/src/pkg
$ cd /var/tmp/ctng

$ ct-ng help
$ ct-ng menuconfig

CT_LOCAL_TARBALLS_DIR="/usr/local/src/pkg"    # Paths and misc options → Local tarballs directory 
CT_SAVE_TARBALLS=y                            # Paths and misc options → Save new tarballs
CT_WORK_DIR="/var/tmp/ctng/build"             # Paths and misc options → Working directory
CT_PREFIX_DIR="/opt/ctng/tools/${CT_TARGET}"  # Paths and misc options → Prefix directory
CT_PARALLEL_JOBS=4                            # Paths and misc options → Number of parallel jobs
CT_ARCH="powerpc"                             # Target options → Target Architecture
CT_LIBC="glibc"                               # C-library → C library[8]


  • For MacOS X we have to disable static linking[9] manually as menuconfig may be unable to do so[10]:
# gcc other options

# General toolchain options


We selected powerpc here for our target architecture. Since we know the machine running the code will be a PowerBook G4, we can set -mcpu and -mtune for gcc:[11]

CT_ARCH_CPU="G4"                              # Target options → Emit assembly for CPU
CT_ARCH_TUNE="G4"                             # Target options → Tune for CPU

If we know the operating system our target will be running on, we can select it instead of "bare-metal":

CT_KERNEL="linux"                             # Operating System → Target OS

After saving the configuration, we can print the tuple[12] of the configured (but yet to be built) toolchain:

$ ct-ng show-tuple
powerpc-unknown-linux-gnu                     # Note: it will print "powerpc-unknown-elf" if we selected 
                                              # "bare-metal" for CT_KERNEL

For ARMv8[13] (e.g. Raspberry_Pi):

CT_ARCH_32=y                                  # Tuple: arm-unknown-linux-gnueabihf

For aarch64, only set:

CT_ARCH_64=y                                  # Tuple: aarch64-unknown-linux-gnueabi

Be sure to have plenty of diskspace available, building toolchains sometimes uses a lot:

  • CT_LOCAL_TARBALLS_DIR may use ~500 MB
  • CT_WORK_DIR may use ~5 GB per architecture (2 GB for the extraced sources, 3 GB for building them)
  • CT_PREFIX_DIR may use ~100 MB per architecture

Now we're ready to actually build (and install) our toolchain.

sudo mkdir -p /opt/ctng/tools
sudo chown -R $USER /opt/ctng/tools

Build our tool chain:

export PATH=/opt/local/libexec/gnubin:$PATH   # For MacOS X only
ct-ng build

This might take a while: on my Intel Core 2 Duo processor, it takes about 6 hours to build for one architecture; on a 4-core Intel i7-3632QM this took about 30 minutes.

Note: the build might fail if DEB_BUILD_HARDENING=1 enabled and -Werror=format-security is set.[14]

After the build is done, setting the ownership of the toolchain to root is advised:

sudo chown -R root:root /opt/ctng/tools

NOTE: We cannot set CT_WORK_DIR or CT_PREFIX_DIR to reside underneath our crosstool installation (/opt/ctng), otherwise it might fail early on.[15]


Hello World

Standard hello.c:

int main(void) {
       printf("Hello World\n");
       return 0;
$ powerpc-unknown-linux-gnu-gcc hello.c -o hello.exe
$ file hello.exe 
hello.exe: ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.15.4, not stripped

$ scp hello.exe alice:
$ ssh alice "uname -rm; ./hello.exe"
3.19.0-rc5 ppc
Hello World

Linux Kernel

To build a Linux kernel, use:

export PATH=$PATH:/opt/ctng/tools/powerpc-unknown-linux-gnu/bin
export  DIR=/var/tmp/lnx
make -j2 O=$DIR ARCH=powerpc CROSS_COMPILE=powerpc-unknown-linux-gnu- tarxz-pkg

Note the trailing "-" after the toolchain tuple (powerpc-unknown-linux-gnu). It's important, so that the build system can find its compilers in $PATH.

When combined with ccache, it looks like this:

make -j4 O=$DIR ARCH=powerpc CROSS_COMPILE="ccache powerpc-unknown-linux-gnu-" tarxz-pkg

And with distcc:

make -j4 O=$DIR ARCH=powerpc CROSS_COMPILE="ccache powerpc-unknown-linux-gnu-" CCACHE_PREFIX=distcc tarxz-pkg

Building for multipe architectures

  # Find out which archs we can build for
  ARCHS="`find "$TOOLS" -maxdepth 1 -type l | sed 's/.*\///' | xargs echo`"

  for arch in $ARCHS; do
        # powerpc-750-linux-gnu vs. powerpc-unknown-linux-gnu
        CROSS_COMPILE="`ls -d "$CROSS"/gcc*/"$arch"* | sed 's/.*\///'`-"

        $DEBUG mkdir -p $RESULT/"$arch"
        $DEBUG make -ki O=$RESULT/"$arch" mrproper

        # Build kernel, modules
        $DEBUG make -ki O=$RESULT/"$arch" targz-pkg

#       # Fetch, archive results
#       cleanup
#       $DEBUG make -ki O=$RESULT/"$arch" mrproper
        echo ""


Crosstool hasn't been updated for some years now, so the following is more for historic reference.


You may want to tune the scripts to your needs to build as many archs as possible with as less hassle as possible:

wget -O - | tar -xzf -       # Last Update: 2006-12-07
mv glibc-2.3.6-csu-Makefile.patch crosstool-0.43/patches/glibc-2.3.6/
cd crosstool-0.43/

Or, when checking out via Subversion:

svn co crosstool-svn              # Last update: 2008-10-15
cd crosstool-svn


sed -i 's/^TARBALLS_DIR=.*/TARBALLS_DIR=\/var\/tmp\/pkgs/' demo-*sh            # Tarballs into /var/tmp/pkgs
sudo mkdir -p /opt/crosstool /var/tmp/pkgs                                     # Create directories
sudo chown -R $USER /opt/crosstool /var/tmp/pkgs

Some prerequisites to be installed:

sudo apt-get install gettext  gcc g++ binutils bison flex autoconf automake

Available architectures:

$ ls demo-*.sh | sed 's/demo-//;s/\.sh//' | xargs echo
alpha arm9tdmi armeb arm-iwmmxt arm arm-softfloat armv5b-softfloat arm-xscale canadian cluster cygwin \
i686 ia64 m68k mipsel mips powerpc-405 powerpc-603 powerpc-750 powerpc-860 powerpc-970 pr17209 runtest \
s390 sh3 sh4 sparc64 sparc x86_64

Which architectures to build:

archs="alpha arm i686 mips powerpc-750 sparc x86_64"

Find out what would happen

for a in $archs; do
    echo "ARCH: $a"
    egrep -v '^\#|^$' demo-"$a".sh

Find out what will happen :)

for a in $archs; do
    echo "ARCH: $a"
    sh demo-"$a".sh 2>&1 | tee demo-"$a".log

Create symlinks for each arch (wow, I wonder when this will break...):

cd `awk -F= '/^RESULT_TOP/ {print $2}'`
for i in */*/*gnu; do (ln -vs "$i" "`echo $i | sed 's/.*\///;s/-.*//'`"); done
for i in */*gnu;   do (ln -vs "$i" "`echo $i | sed 's/.*\///;s/-.*//'`"); done


Tool URL Last update
linux-libc-headers resp. 2005-07-06
glibc-linuxthreads 2006-10-02


  • make use of ccache, distcc (PARALLELMFLAGS="-j2")
  • (more) sophisticated tracking of build results