Crosscompiler

From Segfault
Jump to navigation Jump to search

Crosstool-NG

Prerequisites

Linux

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

Fedora:

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

OpenSUSE:

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

MacOS X

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:

wget http://ftp.gnu.org/gnu/binutils/binutils-2.25.tar.bz2{,.sig}
gpg --keyserver hkp://keys.gnupg.net --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
/dev/disk4

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

Installation

Download Crosstool-NG:

wget http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.20.0.tar.xz{,.sig}
gpg --keyserver hkp://keys.gnupg.net --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 https://github.com/crosstool-ng/crosstool-ng.git 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/crosstool-NG.sh[7] on BSD like systems that we need to address first:

diff --git a/scripts/crosstool-NG.sh.in b/scripts/crosstool-NG.sh.in
index cd65d5b..53ac552 100644
--- a/scripts/crosstool-NG.sh.in
+++ b/scripts/crosstool-NG.sh.in
@@ -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_EndStep

 CT_DoLog DEBUG "Unsetting and unexporting MAKEFLAGS"

Now we can install Crosstool-NG:

export PREF=/opt/ctng
./bootstrap
./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:

make
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/ctng.sh

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

$ grep -E 'CT_((WORK|PREFIX|LOCAL_TARBALLS)_DIR|SAVE_TARBALLS|ARCH|PARALLEL_JOBS|LIBC)=' .config
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]

MacOS

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

# General toolchain options
CT_WANTS_STATIC_LINK=n
CT_STATIC_TOOLCHAIN=n

Examples

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
CT_ARCH_ARCH="armv7-a"
CT_ARCH_FPU="neon-vfpv4"
CT_ARCH_FLOAT_HW=y
CT_ARCH_FLOAT="hard"

For aarch64, only set:

CT_ARCH_64=y                                  # Tuple: aarch64-unknown-linux-gnueabi
CT_ARCH_ARCH="armv8-a"

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]

Usage

Hello World

Standard hello.c:

#include<stdio.h>
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

  KERNEL=/usr/local/src/linux-2.6-git
  RESULT=${HOME}/results
  TOOLS=/opt/ctng/tools
  
  # Find out which archs we can build for
  ARCHS="$(find "${TOOLS}" -maxdepth 1 -type l | sed 's/.*\///' | xargs echo)"

  cd ${KERNEL_SOURCE}
  for arch in ${ARCHS}; do
        
        # powerpc-750-linux-gnu vs. powerpc-unknown-linux-gnu
        CROSS_COMPILE="$(ls -d "${CROSS}"/gcc*/"${arch}"* | sed 's/.*\///')-"
        PATH="${TOOLS}/${arch}/bin:/bin:/usr/bin"

        echo "ARCH=${arch}" PATH="${PATH}" CROSS_COMPILE="${CROSS_COMPILE}"
        ${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 ""
done

Crosstool

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

Installation

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

wget http://www.kegel.com/crosstool/crosstool-0.43.tar.gz -O - | tar -xzf -       # Last Update: 2006-12-07
wget http://crosstool.googlecode.com/svn/trunk/src/patches/glibc-2.3.6/glibc-2.3.6-csu-Makefile.patch
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 https://crosstool.googlecode.com/svn/trunk/src/ crosstool-svn              # Last update: 2008-10-15
cd crosstool-svn

Adjust TARBALLS_DIR and RESULT_TOP:

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}"
    grep -Ev '^\#|^$' "demo-${a}.sh"
    echo
done

Find out what will happen :)

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

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

cd `awk -F= '/^RESULT_TOP/ {print $2}' demo-s390.sh`
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

Sources

Tool URL Last update
binutils https://ftp.gnu.org/gnu/binutils/
gcc https://ftp.gnu.org/gnu/gcc/
glibc https://ftp.gnu.org/gnu/glibc/
gdb https://ftp.gnu.org/gnu/gdb/
linux https://www.kernel.org/pub/linux/kernel/v3.x/
linux-libc-headers http://ep09.pld-linux.org/~mmazur/linux-libc-headers/ resp. https://github.com/pld-linux/linux-libc-headers 2005-07-06
glibc-linuxthreads https://ftp.gnu.org/gnu/glibc/ 2006-10-02

TODO

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

Links

References