| #!/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 <arch list> 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 <dir> 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 |
| } |
| |
| if [ "$OS" = "Linux" ]; then |
| COUNT=`grep processor /proc/cpuinfo | wc -l` |
| PARALLEL=-j`expr $COUNT + $COUNT` |
| fi |
| if [ "$OS" = "Darwin" ]; then |
| # needed to work around problem with clang compiler and some generated code in gcc |
| export CXXFLAGS="-fbracket-depth=1024" |
| fi |
| MAKE=make |
| if [ "$OS" = "FreeBSD" ]; then |
| 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 $PATCHES/binutils-patch.txt |
| 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 |
| |
| COMMON_CONFIG=--with-included-gettext |
| |
| 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 $COMMON_CONFIG --target=$TARGET --prefix=$INSTALLPATH --disable-werror --enable-initfini-array --enable-gold |
| 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 $COMMON_CONFIG --target=$TARGET --prefix=$INSTALLPATH --enable-languages=c,c++ $ARCH_OPTIONS --disable-werror |
| 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 $COMMON_CONFIG --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 |