#!/usr/bin/env bash OS=`uname` HOSTARCH=`uname -m` PARALLEL= FETCH=0 QUIET=0 STRIP=0 GNU_MIRROR=https://mirrors.kernel.org/gnu # Get absolute path, will spawn a subshell then exit so our pwd is retained SCRIPTROOT=$(cd "$(dirname $0)" && pwd) PATCHES=$SCRIPTROOT/patches/ # Cause errors in pipes to return failure when necessary set -o pipefail function err() { echo "doit: error during build" if [ "$QUIET" = "1" ]; then echo "doit: dumping last 50 lines of build log..." echo "doit: see $OUTDIR/build.log for the full details" tail -50 $OUTDIR/build.log fi exit 1 } trap err ERR function help() { echo "Options" echo " -a architectures to build" echo " example: -a 'arm' or -a 'arm i386 x86_64' for multiple" echo " -c use compilation cache (ccache must be installed)" echo " -f fetch source releases from upstream" echo " -h|-? display this help message" echo " -j<#> use <#> parallel workers to build" echo " -o output directory" echo " -q make the build quieter" echo " -s strip the binaries" exit 1 } function log() { if [ "$QUIET" = "1" ]; then "$@" >> $OUTDIR/build.log 2>&1 else "$@" 2>&1 | tee -a $OUTDIR/build.log fi } function extract-tool() { #echo "extract-tool " $1 $2 $3 $4 TARFILE=${1}-${2}.tar$3 TARGETDIR=${1}-${2} HASH="$4" PATCH="$5" if [ -f ${TARGETDIR}/.extracted ]; then log echo "$TARFILE already extracted into $TARGETDIR, skipping" return 0 fi if [ ! -f $ARCHIVES/$TARFILE ]; then log echo "error, missing $TARFILE" exit 1 fi echo "checking $TARFILE integrity" if [ "$(shasum -a 256 -b "$ARCHIVES/$TARFILE" | cut -f1 -d' ')" != "$HASH" ]; then log echo "$TARFILE failed integrity check" exit 1 fi echo extracting $TARFILE pushd $OUTDIR rm -rf $TARGETDIR tar xf $ARCHIVES/$TARFILE || exit 1 if [ -n "$PATCH" ]; then log echo patching $1 log patch -d $TARGETDIR -p1 < "$PATCH" || exit 1 fi touch $TARGETDIR/.extracted || exit 1 popd } MAKE=make if [ "$OS" = "Linux" ]; then COUNT=`grep processor /proc/cpuinfo | wc -l` PARALLEL=-j`expr $COUNT + $COUNT` fi if [ "$OS" = "Darwin" ]; then PARALLEL=-j`sysctl -n hw.ncpu` export CXXFLAGS="-fbracket-depth=1024" fi if [ "$OS" = "FreeBSD" ]; then PARALLEL=-j`sysctl -n hw.ncpu` export CXXFLAGS="-fbracket-depth=1024" MAKE=gmake fi if [ "$HOSTARCH" = "amd64" ]; then HOSTARCH=x86_64 fi if [ $# == "0" ]; then help fi while getopts a:cfhj:o:qs? arg do case $arg in a ) ARCHES=$OPTARG ;; c ) CCACHE=1 ;; j ) PARALLEL="-j$OPTARG" ;; f ) FETCH=1 ;; o ) OUTDIR=$OPTARG ;; q ) QUIET=1 ;; s ) STRIP=1 ;; h ) help ;; ? ) help ;; * ) echo "unrecognized option '$arg'" ; exit 1 ;; esac done if [ -z "$ARCHES" ]; then echo need to specify architectures to build echo ie -a "arm sh" exit 1 fi if [ -z "$OUTDIR" ]; then OUTDIR=`pwd` fi ARCHIVES=$OUTDIR/archives if [ -z $(which makeinfo) ]; then echo makeinfo not found. On debian/ubuntu this is provided by the texinfo package. exit 1 fi export CC="cc" export CXX="c++" if [ "$CCACHE" = "1" ]; then export CC="ccache $CC" export CXX="ccache $CXX" fi log date log echo "ARCHES='$ARCHES' PARALLEL='$PARALLEL' FETCH='$FETCH' CCACHE='$CCACHE'" # load GCCVER and BINVER . toolvers if [ "$FETCH" = "1" ]; then if [ ! -f $ARCHIVES/binutils-$BINVER.tar.bz2 ]; then echo fetching binutils-$BINVER log wget -P $ARCHIVES -N $GNU_MIRROR/binutils/binutils-$BINVER.tar.bz2 fi if [ ! -f $ARCHIVES/gcc-$GCCVER.tar.bz2 ]; then echo fetching gcc-$GCCVER log wget -P $ARCHIVES -N $GNU_MIRROR/gcc/gcc-$GCCVER/gcc-$GCCVER.tar.bz2 fi if [ ! -f $ARCHIVES/gdb-$GDBVER.tar.xz ]; then echo fetching gdb-$GDBVER log wget -P $ARCHIVES -N $GNU_MIRROR/gdb/gdb-$GDBVER.tar.xz fi if [ ! -f $ARCHIVES/mpfr-$MPFRVER.tar.bz2 ]; then echo fetching mpfr-$MPFRVER log wget -P $ARCHIVES -N $GNU_MIRROR/mpfr/mpfr-$MPFRVER.tar.bz2 fi if [ ! -f $ARCHIVES/mpc-$MPCVER.tar.gz ]; then echo fetching mpc-$MPCVER log wget -P $ARCHIVES -N $GNU_MIRROR/mpc/mpc-$MPCVER.tar.gz fi if [ ! -f $ARCHIVES/gmp-$GMPVER.tar.bz2 ]; then echo fetching gmp-$GMPVER log wget -P $ARCHIVES -N $GNU_MIRROR/gmp/gmp-$GMPVER.tar.bz2 fi fi if [ ! -f $OUTDIR/.extracted-stamp ]; then extract-tool binutils $BINVER .bz2 $BINHASH extract-tool gcc $GCCVER .bz2 $GCCHASH $PATCHES/gcc-patch.txt extract-tool gdb $GDBVER .xz $GDBHASH $PATCHES/gdb-patch.txt extract-tool gmp $GMPVER .bz2 $GMPHASH extract-tool mpc $MPCVER .gz $MPCHASH extract-tool mpfr $MPFRVER .bz2 $MPFRHASH touch $OUTDIR/.extracted-stamp fi # link the last three libs into gcc pushd $OUTDIR/gcc-$GCCVER ln -sf ../gmp-$GMPVER gmp ln -sf ../mpc-$MPCVER mpc ln -sf ../mpfr-$MPFRVER mpfr popd for ARCH in $ARCHES; do echo building for arch \"$ARCH\" if [ "$ARCH" == "arm" ]; then TARGET=arm-eabi else TARGET=$ARCH-elf fi INSTALLPATH=$OUTDIR/$TARGET-$GCCVER-$OS-$HOSTARCH BINBUILDPATH=$OUTDIR/build-binutils-$BINVER-$ARCH-$OS-$HOSTARCH GCCBUILDPATH=$OUTDIR/build-gcc-$GCCVER-$ARCH-$OS-$HOSTARCH GDBBUILDPATH=$OUTDIR/build-gdb-$GDBVER-$ARCH-$OS-$HOSTARCH export PATH=$INSTALLPATH/bin:$PATH # Building Binutils if [ ! -f $BINBUILDPATH/built.txt ]; then echo building binutils mkdir -p $BINBUILDPATH pushd $BINBUILDPATH log ../binutils-$BINVER/configure --target=$TARGET --prefix=$INSTALLPATH --with-sysroot --disable-nls --disable-werror log $MAKE $PARALLEL log $MAKE install touch built.txt popd fi # Building GCC if [ ! -f $GCCBUILDPATH/built.txt ]; then echo building gcc ARCH_OPTIONS= if [ $ARCH == "arm" ]; then ARCH_OPTIONS="--with-cpu=arm926ej-s --with-fpu=vfp" fi mkdir -p $GCCBUILDPATH pushd $GCCBUILDPATH log ../gcc-$GCCVER/configure --target=$TARGET --prefix=$INSTALLPATH --enable-languages=c --disable-nls --without-headers $ARCH_OPTIONS log $MAKE all-gcc $PARALLEL log $MAKE all-target-libgcc $PARALLEL log $MAKE install-gcc log $MAKE install-target-libgcc touch built.txt popd fi if [ ! -f $GDBBUILDPATH/built.txt ]; then case "$TARGET" in aarch64-elf) EXTRA_TARGETS="--enable-targets=arm-eabi" ;; *) EXTRA_TARGETS="" ;; esac echo building gdb mkdir -p $GDBBUILDPATH pushd $GDBBUILDPATH log ../gdb-$GDBVER/configure --target=$TARGET --prefix=$INSTALLPATH --disable-werror $EXTRA_TARGETS log make $PARALLEL log make install touch built.txt popd fi # Optionally strip the binaries if [ "${STRIP}" = "1" ]; then find "${INSTALLPATH}/bin" -type f -exec strip {} \; for filename in $(find "${INSTALLPATH}/libexec" -type f); do (file "${filename}" | grep -q ELF) && strip "${filename}" done fi done echo all done