#!/bin/sh set -ex #------------------------------------------------------------------------------ # Dan Kegel # # For entertainment purposes only. Do not operate heavy machinery # while under the influence of this script. # Automated script to build toolchains for a few combinations of # source language { c, c++, fortran } # compiler version { gcc-2.95.3, gcc-3.3.4, gcc-3.4.1 } # C library verison { glibc-2.1.3, glibc-2.3.2 } # target processor { i686, Opteron } # host processor { i686-rh71, i686-rh9 } # Uses http://kegel.com/crosstool to do the actual building of gcc and glibc # (Can also build Java, and can host on Opteron, but we don't # do that at the moment) # # Before running, please read the sections marked NOTES and CONFIGURATION # at the bottom! #------------------------------------------------------------------------------ # TARBALLS_DIR: where this script will access GNU source tarballs # (it will download them to here if missing). TARBALLS_DIR=tarballs # Normal umask is 027, but that leaves the resulting toolchain non-world-usable. # Let's start off with a more permissive umask so world can execute the compiler umask 022 if test ! -w /tmp; then echo "Cannot build if /tmp is not writable" exit 1 fi SOURCE_TOP=`pwd` ORIG_PATH="$PATH" export TARBALLS_DIR mkdir -p $TARBALLS_DIR TARBALLS_DIR=`cd $TARBALLS_DIR; pwd` # Which version of crosstool to run VERSION=crosstool-0.28 if test ! -f $TARBALLS_DIR/$VERSION.tar.gz; then wget -c -P $TARBALLS_DIR kegel.com/crosstool/$VERSION.tar.gz fi # We might need toolchains that build not just on x86, but also sometimes on # x86_64, MacOSX, and Cygwin so encode the build machine type in the path # (note: not so sure this is a good idea, it confuses users) GNU_BUILD=`./config.guess` if test "$GNU_BUILD" = "" ; then echo "config.guess failed?" exit 1 fi # Use a local disk for the build area, c'est plus vite # FIXME: check for sufficient free space if test -d /usr/local/mytemp/.; then SCRATCHDIR=/usr/local/mytemp/$HOME/toolchain else SCRATCHDIR=/tmp/toolchain.$USER fi setCanadianCrossVariables() { # If $1 is 'yes', sets CC et. appropriatly for canadian cross build # according to values of GNU_BUILD, GNU_HOST and CLIENT_TOP # For example, if GNU_HOST is x86_64-unknown-linux-gnu, it will # set CC to point to a compiler that generates code that runs on x86_64-unknown-linux-gnu # so the resulting compiler can run on the compile host. case "$1" in no) # Unset all the variables exported in the 'yes' case by this # function or by buildTarget for var in \ AR AR_FOR_BUILD AS AS_FOR_BUILD BUILD CC CC_FOR_BUILD CFLAGS \ CFLAGS_FOR_BUILD CROSS CXX CXXFLAGS CXXFLAGS_FOR_BUILD \ CXX_FOR_BUILD DLLTOOL_FOR_BUILD GCC_HOST GCJ_FOR_BUILD \ BUILD_CC BUILD_CFLAGS HOST HOST_TOOLCOMBO LD \ LDFLAGS LDFLAGS_FOR_BUILD LD_FOR_BUILD NM NM_FOR_BUILD \ RANLIB RANLIB_FOR_BUILD localedef_FOR_BUILD rpcgen_FOR_BUILD \ zic_FOR_BUILD do unset $var done # Return PATH to original value PATH="$ORIG_PATH" ;; yes) # Gotta build with the right compiler for it to run on production machines # Assumes that this script builds the client compilers first). # Note: HOST_TOOLCOMBO must match one of the combinations in buildTarget case $GNU_HOST in i686*) HOST_TOOLCOMBO=gcc-3.3.4-glibc-2.1.3 ;; x86_64*) HOST_TOOLCOMBO=gcc-3.3.4-glibc-2.3.2 ;; *) exit 1 ;; esac HOST_BINDIR="$CLIENT_TOP/$GNU_BUILD/$GNU_HOST/$HOST_TOOLCOMBO/bin" CROSS="$HOST_BINDIR/$GNU_HOST-" # By convention, $tool is the version of 'tool' distcc uses when dealing # with object files for the GNU_HOST, and $toolFLAGS are the options # to pass to that program (more or less) CFLAGS='' CXXFLAGS='' LDFLAGS='' AR=${CROSS}ar AS=${CROSS}gas CC=${CROSS}gcc CXX=${CROSS}g++ LD=${CROSS}ld NM=${CROSS}nm RANLIB=${CROSS}ranlib export AR AS CC CXX LD NM RANLIB export CFLAGS CXXFLAGS LDFLAGS # By convention, $tool_FOR_BUILD is the version of 'tool' gcc and autoconf use # when building a helper app that has to run on the build system during gcc # build,and $toolFLAGS_FOR_BUILD are the options to pass to that program. # We set everything that might conceivably be used here in a fit of overkill. # Set things we don't expect to be used to 'false'; if they do get used, # that'll make the build script abort. CFLAGS_FOR_BUILD='' CXXFLAGS_FOR_BUILD='' LDFLAGS_FOR_BUILD='' AR_FOR_BUILD=ar AS_FOR_BUILD=gas CC_FOR_BUILD=gcc CXX_FOR_BUILD=g++ DLLTOOL_FOR_BUILD=false GCJ_FOR_BUILD=false LD_FOR_BUILD=ld NM_FOR_BUILD=nm RANLIB_FOR_BUILD=ranlib export AR_FOR_BUILD AS_FOR_BUILD CC_FOR_BUILD export CXX_FOR_BUILD DLLTOOL_FOR_BUILD GCJ_FOR_BUILD export LD_FOR_BUILD NM_FOR_BUILD RANLIB_FOR_BUILD export CFLAGS_FOR_BUILD CXXFLAGS_FOR_BUILD LDFLAGS_FOR_BUILD # $BUILD_tool is the version of 'tool' glibc uses when building # helpers apps that have to run on the build system during glibc build # This *ought* to default to gcc for cross builds, but let's set it just in case. BUILD_CC=$CC_FOR_BUILD BUILD_CFLAGS="$CFLAGS_FOR_BUILD" export BUILD_CC BUILD_CFLAGS # export GCC_HOST to crosstool.sh so it knows we're doing a canadian cross GCC_HOST=$GNU_HOST export GCC_HOST # glibc has been patched to let us override its helper programs # FIXME: figure out more reliable path for these three programs, as this # will fail unless a compatible glibc is installed! localedef_FOR_BUILD=localedef rpcgen_FOR_BUILD=rpcgen zic_FOR_BUILD=zic export localedef_FOR_BUILD rpcgen_FOR_BUILD zic_FOR_BUILD ;; *) echo usage: setCanadianCrossVariables '[yes|no]' exit 1 ;; esac } checkFreeMB() { spaceInMB=`df -Pk $1 | awk '/%/ {printf "%d\n", $4/1024}'` test "$spaceInMB" -gt $2 || abort "$1 only has $spaceInMB MB free, needed $2" } buildTarget() { echo "canadian-foo.sh: buildTarget: start" # Check disk space in build area and in destination # Destination only uses 60-130MB for C/C++; leave a little room checkFreeMB $RESULT_TOP 256 # Build area takes up 500-2000MB; hope 2200 is always enough checkFreeMB $SCRATCHDIR 2200 # Extract GNU_TARGET, TARGT_TOOLCOMBO, and PREFIX from arguments. # This is annoyingly fragile... eval `cat $1 $2 | egrep '^TARGET=|^GCC_DIR=|^GLIBC_DIR'` GNU_TARGET=$TARGET TARGET_TOOLCOMBO=$GCC_DIR-$GLIBC_DIR PREFIX=$RESULT_TOP/$GNU_TARGET/$TARGET_TOOLCOMBO if test "$GNU_HOST" != "$GNU_BUILD"; then echo "canadian-foo.sh: buildTarget: canadian cross requires both $GNU_HOST-gcc and $GNU_TARGET-gcc on the path" TARGET_BINDIR="$CLIENT_TOP/$GNU_BUILD/$GNU_TARGET/$TARGET_TOOLCOMBO/bin" PATH="$TARGET_BINDIR:$HOST_BINDIR:$ORIG_PATH" echo "canadian-foo.sh: buildTarget: Setting PATH to $PATH" CROSS=${GNU_TARGET}- CFLAGS_FOR_TARGET='' CXXFLAGS_FOR_TARGET='' LDFLAGS_FOR_TARGET='' AR_FOR_TARGET=${CROSS}ar AS_FOR_TARGET=${CROSS}gas CC_FOR_TARGET=${CROSS}gcc CXX_FOR_TARGET=${CROSS}g++ DLLTOOL_FOR_TARGET=false GCJ_FOR_TARGET=false LD_FOR_TARGET=${CROSS}ld NM_FOR_TARGET=${CROSS}nm RANLIB_FOR_TARGET=${CROSS}ranlib export AR_FOR_TARGET AS_FOR_TARGET CC_FOR_TARGET CXX_FOR_TARGET export DLLTOOL_FOR_TARGET GCJ_FOR_TARGET LD_FOR_TARGET NM_FOR_TARGET export RANLIB_FOR_TARGET export CFLAGS_FOR_TARGET CXXFLAGS_FOR_TARGET LDFLAGS_FOR_TARGET fi # build and install toolchain. # (Enable static nss if you need to link *really* static programs.) LOGFILE=$SCRATCHDIR/$VERSION/$GNU_HOST-$TARGET-$TARGET_TOOLCOMBO.log echo "canadian-foo.sh: buildTarget: Building one toolchain, logging to $LOGFILE" eval $SITE `cat $1 $2` GLIBC_EXTRA_CONFIG=\""--disable-multilib\"" sh all.sh --notest > $LOGFILE 2>&1 # The legacy hermetic gcc-2.95.3 toolchain doesn't have the C++ standard shared # library, so delete it. This forces g++ to link that library statically. # This might be a Red Hat workaround for an exception handling bug; see # http://www.mail-archive.com/linux-arm@lists.arm.linux.org.uk/msg03091.html the_lib_dir=$PREFIX/$GNU_TARGET/lib case $GCC_DIR in *gcc-2.95*) mkdir -p $the_lib_dir/save mv $the_lib_dir/libstdc++*so* $the_lib_dir/save/ ;; *) ;; esac # Each run consumes 500MB (i686/glibc-2.1.3) to 1.5GB(x86_64/glibc-2.3.2) # of disk space in $SCRATCHDIR. Running out of disk space can cause # the build machine to go offline, so clean up after the build. # (You might want to comment this out if you want the sources to hang # around, e.g. if you're building glibc with TARGET_CFLAGS='-O -g' # in order to debug it.) rmrf $SCRATCHDIR/$VERSION/build/$GNU_TARGET echo "canadian-foo.sh: buildTarget: done" } # rm -rf is notoriously slow on cygwin, so use native tool to speed things up rmrf() { # don't fail no matter what set +e test -d c:/ && (cd `dirname $1` && cmd /c del /q/s/f `basename $1` > /dev/null) rm -rf $1 set -e } buildAllTargets() { echo "canadian-foo.sh: buildAllTargets: start" NOARCH_TOP=$1 if test "$GNU_HOST" = ""; then echo you must set GNU_HOST exit 1 fi cd $SOURCE_TOP echo "canadian-foo.sh: buildAllTargets: Put config.guess at the top level's common/bin so Makefile can get it" if test ! -x $NOARCH_TOP/common/bin/config.guess; then install -d $NOARCH_TOP/common/bin install config.guess $NOARCH_TOP/common/bin/config.guess fi echo "canadian-foo.sh: buildAllTargets: Put a copy of the server scripts in common/bin" # Normally only used when building the client version, but the paths # to the server versions have to be right, too! for file in startdistccd.sh wq.sh local.sh; do sed "s,__RH71_SERVER_TOP__,$RH71_SERVER_TOP,;s,__SERVER_TOP__,$SERVER_TOP,;s,__CLIENT_TOP__,$CLIENT_TOP," \ < $file.in > $NOARCH_TOP/common/bin/$file chmod +x $NOARCH_TOP/common/bin/$file done RESULT_TOP=$NOARCH_TOP/$GNU_HOST export RESULT_TOP echo "canadian-foo.sh: buildAllTargets: RESULT_TOP is $RESULT_TOP" mkdir -p $RESULT_TOP RESULT_TOP=`cd $RESULT_TOP; pwd` # If you are working on changes to crosstool, and you don't # want to create a new tarball for each run, you can change # 'true' to false here. if true; then rmrf $SCRATCHDIR mkdir -p $SCRATCHDIR cd $SCRATCHDIR tar -xzvf $TARBALLS_DIR/$VERSION.tar.gz else cd $SCRATCHDIR/$VERSION fi echo "canadian-foo.sh: buildAllTargets: Build distcc, and set environment variables for cross-compiling if needed." # Make distcc RPM if desired (see note in buildTarget()) case $RESULT_TOP in $SERVER_TOP*) BUILD_DISTCC_RPM="--buildrpm" ;; *) BUILD_DISTCC_RPM="" ;; esac if test "$GNU_HOST" = "$GNU_BUILD"; then setCanadianCrossVariables no sh mkdistcc.sh $BUILD_DISTCC_RPM else setCanadianCrossVariables yes EXTRA_DISTCC_CONFIG="--build=$GNU_BUILD --host=$GNU_HOST" sh mkdistcc.sh $BUILD_DISTCC_RPM fi if test ! -z "${BUILD_DISTCC_RPM}"; then cp $SCRATCHDIR/$VERSION/build/distcc*/RPMS/*.rpm $CLIENT_TOP/. fi echo "canadian-foo.sh: buildAllTargets: Finally, build all the toolchains." # (Don't enable java before gcc-3.4.0, it wasn't very good before then.) # Note: java disabled for moment; java library is freakin' huge, # and has to be built with -Os and stripped. We'll add it back later. # Note: HOST_TOOLCOMBO above must match one of these. GCC_LANGUAGES="c,c++" buildTarget i686.dat gcc-2.95.3-glibc-2.1.3.dat GCC_LANGUAGES="c,c++" buildTarget i686.dat gcc-3.3.4-glibc-2.1.3.dat GCC_LANGUAGES="c,c++" buildTarget x86_64.dat gcc-3.3.4-glibc-2.3.2.dat GCC_LANGUAGES="c,c++,f77" buildTarget i686.dat gcc-3.4.1-glibc-2.1.3.dat GCC_LANGUAGES="c,c++,f77" buildTarget x86_64.dat gcc-3.4.1-glibc-2.3.2.dat echo "canadian-foo.sh: buildAllTargets: Make symlinks for distcc." cd $RESULT_TOP; sh common/bin/mkdistcclinks.sh # Fix permissions in case the umask change above didn't do the trick # This just propagates the 'r' and 'x' bits from user to group and world # (fixme: does this get confused by symlinks?) find $NOARCH_TOP -perm -400 -not -perm -044 | xargs --no-run-if-empty chmod ag+r find $NOARCH_TOP -perm -100 -not -perm -011 | xargs --no-run-if-empty chmod ag+x echo "canadian-foo.sh: buildAllTargets: done" } #------------------------- NOTES ------------------------------- # # Resource requirements: # CPU time: approximately eight hours on a 2.8GHz Pentium 4 # Disk space: # /usr/local/mytemp : 6 gigabytes # /opt: 1.2 gigabytes # /home/...: 2.3 gigabytes (if you build everything) # # Note 1: this is an old script, you might need to tweak it to get # it to work with current crosstool # # Note 2: Please read this script carefully before running it! # In particular, read the section below that starts with the line # ------------ CONFIGURATION -------------------------------- # You will probably want to change the value of a few variables defined there. # # Note 3: before running this script, do # sudo mkdir -p $CLIENT_TOP # sudo chown $USER $CLIENT_TOP # # Note 4: *Do not* run this script as root (it's not been tested to be # safe against operator error when run as root). # Once it's run, you can chown the result back to root. # # Note 5: this script should run on any Linux machine. # # Note 6: When building compilers, # GNU_BUILD refers to the machine you're compiling the compiler on # GNU_HOST refers to the machine the compiler will run on # GNU_TARGET refers to the machine the compiler will generate code for # (These terms are sometimes misused, and are sometimes used from a different # point of view. As Phil Edwards wrote, # You will slowly go insane if you do not grok the following fact: when # building libstdc++-v3 as part of the compiler, the top-level /target/ # becomes the library's /host/. `configure' then causes --target to default # to --host, exactly like any other package using autoconf. Therefore, # 'target' and 'host' will always be the same. This makes sense both for # native and cross compilers, just think about it for a little while. :-)") # # Note 7: there is no Note 7. # # Note 8: As Dilbert said when his mom asked why it took so long, # "um, it was hard." #-------------------- CONFIGURATION ------------------------------------- # Please read this section carefully. You may need to change values # of the following variables: # CLIENT_TOP: where this script will install compilers to be accessed by users CLIENT_TOP=/home/dkegel/blort # SERVER_TOP: where this script installs compilers run by local compile servers # NOTE: this must be correct even if you're only building the client compilers # if you expect $CLIENT_TOP/common/bin/local.sh to correctly install the server SERVER_TOP=/opt/mytemp/local # RH71_SERVER_TOP: where this script installs compilers to be run on rh71 machines # NOTE: this must be correct even if you're only building the client compilers # if you expect $CLIENT_TOP/common/bin/wq.sh to correctly start the server on the rh71 machines RH71_SERVER_TOP=/opt/mytemp/local # The next three sections build the compilers in three ways. # Each is optional. To enable, change 'if false' to 'if true'. # Let's be paranoid and require 5GB free space in temporary build area mkdir -p $SCRATCHDIR checkFreeMB $SCRATCHDIR 5000 # CLIENT_TOP must exist, since we save .rpm's and tarballs there mkdir -p $CLIENT_TOP # Build compilers at $CLIENT_TOP suitable for running on rh9 workstations # (optional if you've already done this previously): if true; then echo "canadian-foo.sh: Building for clients" rmrf $CLIENT_TOP mkdir -p $CLIENT_TOP checkFreeMB $CLIENT_TOP 5000 for GNU_HOST in $GNU_BUILD; do buildAllTargets $CLIENT_TOP done echo "canadian-foo.sh: saving $CLIENT_TOP/$GNU_HOST-client.tar.gz for unpacking on NFS volume" tar -C $CLIENT_TOP -czvf $CLIENT_TOP/$GNU_HOST-client.tar.gz --exclude $GNU_HOST-client.tar.gz . fi # optional - build compiler(s) for a local compile cluster # and/or clients who wish to install via RPM if true; then echo "canadian-foo.sh: Building for local distcc servers" rmrf $SERVER_TOP mkdir -p $SERVER_TOP checkFreeMB $SERVER_TOP 5000 for GNU_HOST in $GNU_BUILD; do buildAllTargets $SERVER_TOP # gcc and distcc rpms already built and saved in $CLIENT_TOP echo "canadian-foo.sh: saving $CLIENT_TOP/$GNU_HOST-server.tar.gz for unpacking on local distcc servers" tar -C $SERVER_TOP -czvf $CLIENT_TOP/$GNU_HOST-server.tar.gz . done # Build RPM for host- and target-independent local odds and ends export SCRATCHDIR export TARBALLSDIR export NOARCH_TOP=$SERVER_TOP cd /$USER sh mkbaserpm.sh cp $SCRATCHDIR/RPMS/local-base*.rpm $CLIENT_TOP/ fi # optional - build canadian cross compiler(s) for a compile cluster on the rh71 machines # have to build with the cross-compiler we built earlier! if true; then echo "canadian-foo.sh: Building for rh71" rmrf $RH71_SERVER_TOP mkdir -p $RH71_SERVER_TOP checkFreeMB $RH71_SERVER_TOP 5000 for GNU_HOST in i686-unknown-linux-gnu; do buildAllTargets $RH71_SERVER_TOP echo "canadian-foo.sh: saving $CLIENT_TOP/$GNU_HOST-server.tar.gz for unpacking on rh71 distcc servers" tar -C $RH71_SERVER_TOP -czvf $CLIENT_TOP/$GNU_HOST-server.tar.gz . done fi #----------------------------------------------------------------- echo "canadian-foo.sh: Done" exit 0