You are here: Home / Software / embedded linux notes / bootstrapping cross compiler
bootstrapping cross compilerΒΆ
Compiling on an embedded system (sheevaplug, raspberry, etc) is slow. Using a Cross Compiler on your Desktop is a lot faster. You can download ready made cross compiler toolchains. For example plugcomputer.org (Downloads, plug computer basics) or codesourcery.cpm (products, source g++, editions, lit)
Or we can strap our own.
Requires Diskspace and CPU-Time. The steps are
binutils
gcc, static version, no threads
kernelheader
eglibc, header so you can compile
gcc, only C
eglibc
gcc, C and C++
All Details, download URLs can be seen in the following
shell script
.
#!/bin/bash
set -e
set -u
# building my custom cross compiler
# This directory is used as root for all operations
BASE=$(dirname "$0")
BASE=$(cd "$BASE" && pwd)
# target machine tuple. This is suitable for the marvell sheevaplug
TARGET=armv5tel-softfloat-linux-gnueabi
BUILD=$(gcc -dumpmachine) # x86_64-unknown-linux-gnu, i686-linux-gnu, ...
ARCH=arm
SYSROOT="$BASE/sysroot" # files for the target system
TOOLCHAIN="$BASE/toolchain" # the cross compilers
SRCDIR="$BASE/src" # saving tarballs
WORKDIR="$BASE/work" # unpacked tarballs
BUILDDIR="$BASE/build" # running compile
PARALLEL="-j2" # dualcore
# Software Versions to use
BINUTILS=binutils-2.20.1
KERNEL=linux-2.6.34
GCC=gcc-4.5.0
EGLIBC=eglibc-2_11 # abi compatible to glibc, better support for arm
# download functions
get_url() {
# pass a full url as parameter
url=$1
file=${url##*/}
if [ ! -f "$SRCDIR/$file" ]; then
echo "downloading $file from $url"
wget "$url" -O "$BASE/src/$file"
fi
}
unpack() {
# pass a filename as parameter
file=$1
ext=${file##*.}
folder=${file%%.tar.*}
if [ ! -d "$WORKDIR/$folder" ]; then
echo "unpacking $file"
else
return 0
fi
cd $WORKDIR
if [ $ext == "bz2" ]; then
tar jxf "$SRCDIR/$file"
else
tar zxf "$SRCDIR/$file"
fi
}
check_done() {
OBJ=$1
if [ -f $BUILDDIR/$OBJ.done ]; then
echo "already done"
return 0
fi
return 1
}
do_msg() {
OBJ=$1
ACTION=$2
echo "========================================================="
echo "$OBJ - $ACTION"
echo "========================================================="
}
binutils() {
# compile ar, as, ld, objcopy, ...
OBJ=$BINUTILS
do_msg $OBJ "start"
check_done $OBJ && return 0
mkdir -p $BUILDDIR/$OBJ
pushd $BUILDDIR/$OBJ
if [ ! -f Makefile ]; then
# run configure
$WORKDIR/$OBJ/configure \
--target=$TARGET \
--prefix=$TOOLCHAIN \
--with-sysroot=$SYSROOT \
--disable-nls
fi
do_msg $OBJ "compile"
make $PARALLEL
do_msg $OBJ "install"
make install
do_msg $OBJ "done"
touch $BUILDDIR/$OBJ.done
popd
}
gccstatic() {
# static gcc, only C, able to compile the libc
# would be enough if we only compile kernels
OBJ=$GCC-static
do_msg $OBJ "start"
check_done $OBJ && return 0
mkdir -p $BUILDDIR/$OBJ
pushd $BUILDDIR/$OBJ
if [ ! -f Makefile ]; then
$WORKDIR/$GCC/configure \
--target=$TARGET \
--prefix=$TOOLCHAIN \
--without-headers \
--with-newlib \
--disable-shared \
--disable-threads \
--disable-libssp \
--disable-libgomp \
--disable-libmudflap \
--disable-nls \
--enable-languages=c
# --without-headers and --with-newlib make gcc believe that there
# is no c library available (yet)
fi
do_msg $OBJ "compile"
PATH=$TOOLCHAIN/bin:$PATH \
make $PARALLEL
do_msg $OBJ "install"
PATH=$TOOLCHAIN/bin:$PATH \
make install
do_msg $OBJ "done"
touch $BUILDDIR/$OBJ.done
popd
}
gccminimal() {
OBJ=$GCC-min
do_msg $OBJ "start"
check_done $OBJ && return 0
mkdir -p $BUILDDIR/$OBJ
pushd $BUILDDIR/$OBJ
if [ ! -f Makefile ]; then
$WORKDIR/$GCC/configure \
--target=$TARGET \
--prefix=$TOOLCHAIN \
--with-sysroot=$SYSROOT \
--disable-libssp \
--disable-libgomp \
--disable-libmudflap \
--disable-nls \
--enable-languages=c
# now with shared libs and threads
fi
do_msg $OBJ "compile"
PATH=$TOOLCHAIN/bin:$PATH \
make $PARALLEL
do_msg $OBJ "install"
PATH=$TOOLCHAIN/bin:$PATH \
make install
do_msg $OBJ "done"
touch $BUILDDIR/$OBJ.done
popd
}
gccfull() {
OBJ=$GCC
do_msg $OBJ "start"
check_done $OBJ && return 0
mkdir -p $BUILDDIR/$OBJ
pushd $BUILDDIR/$OBJ
if [ ! -f Makefile ]; then
$WORKDIR/$GCC/configure \
--target=$TARGET \
--prefix=$TOOLCHAIN \
--with-sysroot=$SYSROOT \
--enable-__cxy_atexit \
--disable-libssp \
--disable-libgomp \
--disable-libmudflap \
--enable-languages=c,c++ \
--disable-nls
# now with c++
# the cxy_atexit is special for eglibc
fi
do_msg $OBJ "compile"
PATH=$TOOLCHAIN/bin:$PATH \
make $PARALLEL
do_msg $OBJ "install"
PATH=$TOOLCHAIN/bin:$PATH \
make install
do_msg $OBJ "done"
touch $BUILDDIR/$OBJ.done
popd
}
kernelheader() {
# compiling headers that work on the target system
# this is done in-tree
OBJ=$KERNEL
do_msg $OBJ "start"
check_done $OBJ && return 0
pushd $WORKDIR/$OBJ
do_msg $OBJ "cleaning"
make mrproper
do_msg $OBJ "installing"
PATH=$TOOLCHAIN/bin:$PATH \
make \
ARCH=$ARCH \
INSTALL_HDR_PATH=$SYSROOT/usr \
CROSS_COMPILE=$TARGET- \
headers_install
do_msg $OBJ "done"
touch $BUILDDIR/$OBJ.done
popd
}
eglibcheader() {
OBJ=$EGLIBC-header
do_msg $OBJ "start"
check_done $OBJ && return 0
mkdir -p $BUILDDIR/$OBJ
pushd $BUILDDIR/$OBJ
if [ ! -f Makefile ]; then
BUILD_CC=gcc \
CC=$TOOLCHAIN/bin/$TARGET-gcc \
CXX=$TOOLCHAIN/bin/$TARGET-g++ \
AR=$TOOLCHAIN/bin/$TARGET-ar \
LD=$TOOLCHAIN/bin/$TARGET-ld \
RANLIB=$TOOLCHAIN/bin/$TARGET-ranlib \
$WORKDIR/$EGLIBC/configure \
--prefix=/usr \
--with-headers=$SYSROOT/usr/include \
--build=$BUILD \
--host=$TARGET \
--disable-nls \
--disable-profile \
--without-gd \
--without-cvs \
--enable-add-ons
fi
do_msg $OBJ "install"
make \
install-headers \
install_root=$SYSROOT \
install-bootstrap-headers=yes
do_msg $OBJ "crtX and fake libc"
make csu/subdir_lib
mkdir -p $SYSROOT/usr/lib
cp csu/crt1.o csu/crti.o csu/crtn.o $SYSROOT/usr/lib
# build a dummy libc
$TOOLCHAIN/bin/$TARGET-gcc \
-nostdlib \
-nostartfiles \
-shared \
-x c /dev/null \
-o $SYSROOT/usr/lib/libc.so
do_msg $OBJ "done"
touch $BUILDDIR/$OBJ.done
popd
}
eglibc() {
OBJ=$EGLIBC
do_msg $OBJ "start"
check_done $OBJ && return 0
mkdir -p $BUILDDIR/$OBJ
pushd $BUILDDIR/$OBJ
if [ ! -f Makefile ]; then
BUILD_CC=gcc \
CC=$TOOLCHAIN/bin/$TARGET-gcc \
CXX=$TOOLCHAIN/bin/$TARGET-g++ \
AR=$TOOLCHAIN/bin/$TARGET-ar \
RANLIB=$TOOLCHAIN/bin/$TARGET-ranlib \
$WORKDIR/$EGLIBC/configure \
--prefix=/usr \
--with-headers=$SYSROOT/usr/include \
--build=$BUILD \
--host=$TARGET \
--disable-nls \
--disable-profile \
--without-gd \
--without-cvs \
--enable-add-ons
fi
do_msg $OBJ "compile"
PATH=$TOOLCHAIN/bin:$PATH \
make $PARALLEL
do_msg $OBJ "install"
PATH=$TOOLCHAIN/bin:$PATH \
make install install_root=$SYSROOT
do_msg $OBJ "done"
touch $BUILDDIR/$OBJ.done
popd
}
# ==============================================
# MAIN
# ==============================================
do_msg "INIT" "creating directories"
mkdir -p $BUILDDIR
mkdir -p $WORKDIR
mkdir -p $SRCDIR
mkdir -p $SYSROOT
mkdir -p $TOOLCHAIN
do_msg "INIT" "download"
pushd $SRCDIR
get_url "http://ftp.gnu.org/gnu/binutils/$BINUTILS.tar.bz2"
get_url "ftp://ftp.gnu.org/gnu/gcc/$GCC/$GCC.tar.bz2"
get_url "ftp://ftp.kernel.org/pub/linux/kernel/v2.6/$KERNEL.tar.bz2"
# our very special friend eglibc has no release tarball
if [ ! -d $SRCDIR/$EGLIBC ]; then
svn export svn://svn.eglibc.org/branches/$EGLIBC/libc $SRCDIR/$EGLIBC
# arm is only supported in ports
svn export svn://svn.eglibc.org/branches/$EGLIBC/ports $SRCDIR/$EGLIBC/ports
fi
do_msg "INIT" "unpacking"
unpack "$BINUTILS.tar.bz2"
unpack "$GCC.tar.bz2"
unpack "$KERNEL.tar.bz2"
if [ ! -h $WORKDIR/$EGLIBC ]; then
ln -s $SRCDIR/$EGLIBC $WORKDIR/$EGLIBC
fi
binutils
gccstatic
kernelheader
eglibcheader
gccminimal
eglibc
gccfull
echo " _ "
echo " __| | ___ _ __ ___ "
echo " / _ |/ _ \| '_ \ / _ \ "
echo "| (_| | (_) | | | | __/ "
echo " \__,_|\___/|_| |_|\___| "
echo " "
echo " "