| #!/bin/bash |
| |
| set -o errexit # Exit if any command fails |
| set -o pipefail # Return the last non-zero exit status in pipelines |
| #set -x # Print commands as they are executed |
| shopt -s nullglob |
| |
| # This script performs an automated self-hosted build of dragonegg. In |
| # other words it builds dragonegg, then builds GCC and LLVM with dragonegg, |
| # then uses those and dragonegg to rebuild dragonegg. It does this a couple |
| # of times until it reckons you must be fed up. At which point it checks |
| # that the dragonegg plugin is not changing at each iteration. |
| # |
| # This is all extreme overkill if all you want to do is try out dragonegg! If |
| # that's your goal then I suggest you consult the README file one directory up. |
| |
| DRAGONEGG_SOURCE=$PWD/dragonegg # Where to check out the dragonegg source |
| GCC_SOURCE=$PWD/gcc # Where to check out the GCC source |
| LLVM_SOURCE=$PWD/llvm # Where to check out the LLVM source |
| |
| DRAGONEGG_BUILD_BASE=$PWD/dragonegg-build # Where to build dragonegg |
| GCC_BUILD_BASE=$PWD/gcc-build # Where to build GCC |
| LLVM_BUILD_BASE=$PWD/llvm-build # Where to build LLVM |
| GCC_INSTALL_BASE=$PWD/gcc-install # Where to install GCC |
| |
| |
| STAGES="0 1 2" # Determines how many times we build GCC, LLVM and dragonegg |
| |
| #USE_KNOWN_GOOD_GCC_REVISION=0 # Use the most recent GCC revision |
| USE_KNOWN_GOOD_GCC_REVISION=1 # Use a GCC revision known to be good |
| |
| #USE_PER_STAGE_BUILD_DIRECTORIES=0 # Do not use per-stage build directories |
| USE_PER_STAGE_BUILD_DIRECTORIES=1 # Use per-stage build directories, helps |
| # when debugging self-host failures |
| |
| USE_PER_STAGE_INSTALL_DIRECTORIES=0 # Do not use per-stage install |
| # directories |
| #USE_PER_STAGE_INSTALL_DIRECTORIES=1 # Use per-stage install directories |
| # NOTE: turning on per-stage install directories automatically disables testing |
| # that dragonegg object files did not change from one stage to the next. This |
| # is because the GCC install directory name gets embedded in the object files |
| # due to use of __FILE__ in headers included from the GCC install directory. |
| |
| |
| # How to configure GCC. As a minimum you need to enable C and C++, but you can |
| # also enable other languages if you like. You must specify --enable-plugin and |
| # --enable-lto. The other flags are optional. The reason for --disable-multilib |
| # is that GCC fails to build on my machine without it (this is a GCC issue, and |
| # has nothing to do with dragonegg or LLVM). |
| GCC_OPTIONS="--enable-plugin --enable-lto --enable-languages=c,c++ \ |
| --disable-bootstrap --disable-multilib --enable-checking \ |
| $GCC_OPTIONS" |
| |
| # How to configure LLVM. These are all optional. On my machine, the debugger |
| # refuses to work with dragonegg unless I build LLVM with --disable-threads. |
| LLVM_OPTIONS="--enable-optimized --enable-assertions \ |
| --disable-threads --enable-debug-symbols $LLVM_OPTIONS" |
| |
| COMPARE="cmp --ignore-initial=16" # How to compare object files |
| MAKE="nice -n 20 make -j3 -l2" # How to run make |
| MAKE_INSTALL="nice -n 20 make install" # How to run make install |
| |
| |
| # Turn off plugin version checking, otherwise the check may fail if all stages |
| # are not built on the same day, since the version contains the build date. |
| export dragonegg_disable_version_check=yes |
| |
| # Check out or update the dragonegg source |
| if [ ! -e $DRAGONEGG_SOURCE ] ; then |
| echo "Checking out dragonegg" |
| svn co http://llvm.org/svn/llvm-project/dragonegg/trunk $DRAGONEGG_SOURCE |
| elif [ ! -L $DRAGONEGG_SOURCE ] ; then # Do not update symbolic links. This is |
| # for the benefit of the buildbots. |
| echo "Updating dragonegg" |
| svn update $DRAGONEGG_SOURCE |
| fi |
| |
| |
| # Check out or update the LLVM source |
| if [ ! -e $LLVM_SOURCE ] ; then |
| echo "Checking out LLVM" |
| svn co http://llvm.org/svn/llvm-project/llvm/trunk $LLVM_SOURCE |
| elif [ ! -L $LLVM_SOURCE ] ; then # Do not update symbolic links. This is |
| # for the benefit of the buildbots. |
| echo "Updating LLVM" |
| svn update $LLVM_SOURCE |
| fi |
| |
| |
| # Check out or update the GCC source |
| if (( USE_KNOWN_GOOD_GCC_REVISION )) ; then |
| GCC_REVISION=`cat $DRAGONEGG_SOURCE/gcc_revision_tested_with` |
| echo "Using GCC revision $GCC_REVISION" |
| else |
| GCC_REVISION=head |
| fi |
| |
| if [ ! -e $GCC_SOURCE ] ; then |
| echo "Checking out GCC" |
| svn co -r $GCC_REVISION svn://gcc.gnu.org/svn/gcc/branches/gcc-4_5-branch $GCC_SOURCE |
| elif [ ! -L $GCC_SOURCE ] ; then # Do not update symbolic links. This is |
| # for the benefit of the buildbots. |
| echo "Reverting any applied patches" |
| svn revert -R $GCC_SOURCE/gcc |
| echo "Updating GCC" |
| svn update -r $GCC_REVISION $GCC_SOURCE |
| fi |
| |
| |
| # Apply any needed patches to GCC |
| for PATCH in $DRAGONEGG_SOURCE/gcc-patches/*.diff ; do |
| echo "Applying patch $PATCH" |
| patch -d $GCC_SOURCE -p1 < $PATCH |
| done |
| |
| PLUGIN_OPTION= # No plugin yet |
| PREV_DRAGONEGG_BUILD= # No previous dragonegg |
| for STAGE in $STAGES ; do |
| |
| if (( USE_PER_STAGE_BUILD_DIRECTORIES )) ; then |
| DRAGONEGG_BUILD=$DRAGONEGG_BUILD_BASE-$STAGE |
| GCC_BUILD=$GCC_BUILD_BASE-$STAGE |
| LLVM_BUILD=$LLVM_BUILD_BASE-$STAGE |
| else |
| DRAGONEGG_BUILD=$DRAGONEGG_BUILD_BASE |
| GCC_BUILD=$GCC_BUILD_BASE |
| LLVM_BUILD=$LLVM_BUILD_BASE |
| fi |
| |
| if (( USE_PER_STAGE_INSTALL_DIRECTORIES )) ; then |
| GCC_INSTALL=$GCC_INSTALL_BASE-$STAGE |
| else |
| GCC_INSTALL=$GCC_INSTALL_BASE |
| fi |
| |
| # ==> begin: Build and install GCC |
| echo "Building stage $STAGE GCC" |
| rm -fr $GCC_BUILD |
| mkdir -p $GCC_BUILD |
| cd $GCC_BUILD |
| # NOTE: the configure arguments need to be the same at each stage, because |
| # they are recorded in the plugin version information. If they differed, |
| # then object files from different stages would not compare the same. This |
| # is the reason for configuring with the same prefix at each stage, even if |
| # we intend to install in a different directory each time. |
| $GCC_SOURCE/configure --prefix=$GCC_INSTALL_BASE $GCC_OPTIONS |
| $MAKE |
| |
| echo "Installing stage $STAGE GCC" |
| rm -fr $GCC_INSTALL $GCC_INSTALL_BASE |
| $MAKE_INSTALL |
| if [ "$GCC_INSTALL_BASE" != "$GCC_INSTALL" ] ; then |
| # Move the just built GCC to its definitive install directory. |
| mv $GCC_INSTALL_BASE $GCC_INSTALL |
| fi |
| # <== end: Build and install GCC |
| |
| |
| # From now on compile using the newly built GCC |
| export CC="$GCC_INSTALL/bin/gcc $PLUGIN_OPTION" |
| export CXX="$GCC_INSTALL/bin/g++ $PLUGIN_OPTION" |
| export GCC=$CC # Tells dragonegg what to build against |
| export PATH=$GCC_INSTALL/bin:$PATH # For gnatmake, gnatbind etc if building Ada |
| |
| # The built libstdc++ and libgcc may be more recent than the system versions. |
| # Set the library path so that programs compiled with the just built GCC will |
| # start successfully, rather than failing due to shared library dependencies. |
| export LD_LIBRARY_PATH=`$CC -print-search-dirs | grep "^libraries:" | \ |
| sed "s/^libraries: *=//"`:$LD_LIBRARY_PATH |
| |
| |
| # ==> begin: Build LLVM using the just built GCC |
| echo "Building stage $STAGE LLVM" |
| rm -fr $LLVM_BUILD |
| mkdir -p $LLVM_BUILD |
| cd $LLVM_BUILD |
| $LLVM_SOURCE/configure $LLVM_OPTIONS |
| $MAKE |
| # <== end: Build LLVM using the just built GCC |
| |
| |
| # From now on 'llvm-config' will be the just built one. |
| export LLVM_CONFIG=$LLVM_BUILD/*/bin/llvm-config |
| |
| |
| # ==> begin: Build dragonegg using the just built GCC and LLVM. |
| echo "Building pre-stage $STAGE dragonegg" |
| rm -fr $DRAGONEGG_BUILD-pre |
| mkdir -p $DRAGONEGG_BUILD-pre |
| cd $DRAGONEGG_BUILD-pre |
| $MAKE -f $DRAGONEGG_SOURCE/Makefile clean |
| SRC_DIR=$DRAGONEGG_SOURCE $MAKE -f $DRAGONEGG_SOURCE/Makefile VERBOSE=1 |
| # <== end: Build dragonegg using the just built GCC and DRAGONEGG. |
| |
| |
| # Compile using the just built dragonegg. |
| PLUGIN_OPTION="-fplugin=$DRAGONEGG_BUILD-pre/dragonegg.so" |
| export CC="$GCC_INSTALL/bin/gcc $PLUGIN_OPTION" |
| export CXX="$GCC_INSTALL/bin/g++ $PLUGIN_OPTION" |
| export GCC=$CC # Tells dragonegg what to build against |
| |
| |
| # ==> begin: Build dragonegg again using the just built dragonegg |
| echo "Building stage $STAGE dragonegg with itself" |
| rm -fr $DRAGONEGG_BUILD |
| mkdir -p $DRAGONEGG_BUILD |
| cd $DRAGONEGG_BUILD |
| $MAKE -f $DRAGONEGG_SOURCE/Makefile clean |
| SRC_DIR=$DRAGONEGG_SOURCE $MAKE -f $DRAGONEGG_SOURCE/Makefile VERBOSE=1 |
| # <== end: Build dragonegg again using the just built dragonegg |
| |
| |
| # Compile using the self-built dragonegg. |
| PLUGIN_OPTION="-fplugin=$DRAGONEGG_BUILD/dragonegg.so" |
| export CC="$GCC_INSTALL/bin/gcc $PLUGIN_OPTION" |
| export CXX="$GCC_INSTALL/bin/g++ $PLUGIN_OPTION" |
| export GCC=$CC # Tells dragonegg what to build against |
| |
| |
| # ==> begin: Compare the dragonegg objects with those from the previous stage |
| if (( !USE_PER_STAGE_INSTALL_DIRECTORIES )) ; then |
| |
| if [ "x$PREV_DRAGONEGG_BUILD" != "x" ] ; then |
| echo "Comparing $DRAGONEGG_BUILD objects to $PREV_DRAGONEGG_BUILD objects" |
| cd $DRAGONEGG_BUILD |
| for O in *.o ; do |
| P=$PREV_DRAGONEGG_BUILD/$O |
| $COMPARE $O $P |
| done |
| fi |
| |
| fi |
| # <== end: Compare the dragonegg objects with those from the previous stage |
| |
| |
| PREV_DRAGONEGG_BUILD=$DRAGONEGG_BUILD |
| done |