#!/bin/sh
# vim: ts=4 sw=4 et ft=sh
#---------------------------------------------------------------------------#
# Copyright (C) 1995-2001 The University of Melbourne.
# This file may only be copied under the terms of the GNU General
# Public License - see the file COPYING in the Mercury distribution.
#---------------------------------------------------------------------------#

usage="\
Usage: $0 [options]
Options:
    -d <dirname>, --test-dir <dirname>
        Run the tests in directory <dirname>. Multiple such options
        may be given, in which case the tests in all the named
        directories will be run. In the absence of any such options,
        all tests in all directories will be run (unless testing
        as a whole is disabled).
    -s <testname>, --specified-test <testname>
        Run only the tests whose names are specified as arguments of this
        option, which may be given more than once. The test names must include
        the directory name component.
    -f, --failing-tests
        Run only the tests which failed on the last run, as recorded in the
        FAILED_TESTS files in the various test directories. Meaningful only
        in the absence of -s options.
    --error-file
        Run only the tests which failed on the last run, as recorded in the
        tests/runtests.errs file. Meaningful only in the absence of -s and -f
        options.
    --expect-no-failures
        Exit with a nonzero exit status if any test fails, even if the failure
        of that test is otherwise expected.
    -e, --extras
        Test the programs in the extras directory.
    -h, --help
        Display this usage message.
    -j <num-jobs>, --jobs <num-jobs>
        Run using <num-jobs> different parallel processes.
    -k, --keep-objs
        Keep the stage 2 object files even if stage 2 is successful.
    -m <mmake-args>, --mmake-opts <mmake-args>
        Pass <mmake-args> as options to \`mmake'.
    -M <make-args>, --make-opts <make-args>
        Pass <make-args> as options to \`make'.
    -o <filename>, --output-file <filename>
        Output results to <filename>.
    --target <target>
        Specify the target to use in creating stages 2 and 3.
    -G <grade>, --grade <grade>
        Specify the grade to use in creating stages 2 and 3.
        The tests will also be executed in this grade, unless
        the --test-grade option says otherwise. Implies -r -g.
    --gradedir <grade>
        Same as '--grade <grade>', except that it also causes
        the grade name to be included in the names of the stage 2
        and stage 3 directories. This can be useful if you have
        lots of disk space and want to run bootchecks in several
        grades at once. Note however that the name of the tests
        directory doesn't include the grade, so you might also
        need to use --no-test-suite (see below) for this to work.
    --test-grade <grade>
        Specify the grade to use in executing the tests.
        If this is the same as the grade of stages 2 and 3, then
        we use the stage 2 runtime, library etc for the tests.
        Otherwise, we use the stage 1 runtime, library etc,
        and trust that these are compatible with the given grade.
        Implies -r -g.
    --mercury-options <options-string>
        Set MERCURY_OPTIONS to the given string when doing the bootcheck.
    -g, --copy-boehm-gc
        Copy the boehm_gc directory instead of linking it.
        This is necessary if one wants to bootcheck a grade
        that is not compatible with the standard one.
    -r, --copy-runtime
        Copy the runtime directory instead of linking it.
        This is necessary if one wants to bootcheck a grade
        that is not compatible with the standard one.
    -p-, --no-copy-profilers
        Link the profiler directories instead of copying them.
    --no-copy-slice
        Link the slice directory instead of copying it.
    -b-, --no-bootcheck
        Do not run the bootstrap check; execute the test suite and/or
        the extras only. This option requires a previous bootstrap
        check to have left a working stage 2 directory.
    --no-check-namespace
        Don't build the check_namespace targets in the runtime,
        trace, browser, ssdb, mdbcomp and library directories.
    -t-, --no-test-suite
        By default, bootcheck will also run the test quite.
        This option prevents that.
    --skip-stage-2
        Take the existing stage 2 directory as given; do not run mmake
        in it.
    -2, --keep-stage-2
        Don't rebuild the stage 2 directory from scratch after
        building stage 1. Instead use the existing stage 2 directory
        as the starting point for mmake.
    -3, --keep-stage-3
        Don't rebuild the stage 3 directory from scratch after
        building stage 1. Instead use the existing stage 3 directory
        as the starting point for mmake.
    --no-test-params
        When executing the test suite, do not use the stage 2 Mmake.params
        file.
    --keep-success-log-files
        Keep every test case's .log file, renamed as a .kept_log file,
        even if the test passes. It can be useful to compare these files
        in a known-good workspace with the corresponding log files
        in a workspace containing a change that fails some test cases.
        Note that unneeded .kept_log files must be deleted manually;
        they do *not* get deleted by any mmake targets.
    --stop-after-stage-2
        Stop after building stage 2, even if it is successful.
    --use-subdirs
        Assume intermediate files are built in subdirectories.
        (Same as the \`--use-subdirs' option to mmake and mmc.)
    --use-mmc-make
        Use \`mmc --make' to build the files.
        (Same as the \`--use-mmc-make' option to mmake.)
    --compile-times
        Report information about compilation times in the stage 2
        library and compiler directories.
    --no-write-out-profile-data
        When doing bootcheck in a deep profiling grade, disable the
        writing out of profile data files. This makes the bootcheck
        faster, but avoiding writing out the profiling data also avoids
        the checks on its integrity.
    --type-stats TYPE_STATS_FILE_NAME
        Collect statistics about the builtin operations (unify, index
        and compare) performed on various types. The argument of this
        option should give the absolute pathname of the file in which
        the runtime has been configured to accumulate statistics. The
        statistics derived from the creation of the stage 3 compiler
        will be put TYPE_STATS_FILE_NAME.stage3.$$, while the
        statistics derived from the execution of the test suite will
        be put into TYPE_STATS_FILE_NAME.tests.$$. Both filenames will
        be reported in the output of bootcheck, to allow the statistics
        files to be matched with the bootcheck that created them.
    --trace-count
        Collect counts of the number of times each label is executed
        in modules compiled with debugging.
    --coverage-test
        Collect counts of the number of times each label is executed
        in modules compiled with debugging, and put the raw data needed
        by the mct script into a bunch of files in the coverage directory.
    -W, --windows
        Translate paths into the Microsoft Windows format and use the
        extension \`.lib' for libraries. This option also implies
        --no-sym-links.
    --no-sym-links
        Use this option on systems which don't support symbolic links.
    --disable-debug-libs
        Make the trace, browser, ssdb libraries empty. This can be useful
        when trying to track down the reason why they are being linked
        into the compiler in the first place.
    --delete-deep-data
        Delete any Deep.data and Deep.procrep files created by the bootcheck,
        in the interest of conserving disk space.
    --deep-all-write
        In deep profiling grades, write out the profiling tree on every
        invocation. (The default is to write it out only for every 25th
        invocation, on average.)
    --deep-debug
        Turn on the flag that enables debugging output from the deep
        profiling runtime.
    --progress
        Create a timestamp file when finishing the execution of each test case,
        to allow the user to monitor the bootcheck's progress. The timestamp
        files will have names of the form .date.<testname>.
"

unset WORKSPACE
testdirs=""
specified_tests_only=""
failing_tests_only=false
error_file_only=false
expect_listed_failures=true
extras=false
jfactor=""
keep_objs=false
mmake_opts="-k"
outfile=""
runtests=true
do_bootcheck=true
if test -f /bin/cygwin1.dll
then
    # Don't run check_namespace on Cygwin, unless explicitly asked,
    # because the `-nostdinc' option doesn't work with gcc 2.95 on Cygwin.
    # (This has been fixed in later versions of gcc, e.g. 3.2, so
    # we should reenable this at some point...)
    check_namespace=false
else
    check_namespace=true
fi
grade=
use_gradedir=false
target=c
test_grade=
test_params=true
copy_runtime=false
copy_boehm_gc=false
copy_slice=true
copy_profilers=true
mmake_stage_2=true
keep_stage_2=false
keep_stage_3=false
stop_after_stage_2=false
windows=false
use_cp=false
if test -d compiler/Mercury
then
    use_subdirs=${MMAKE_USE_SUBDIRS=yes}
else
    use_subdirs=${MMAKE_USE_SUBDIRS=no}
fi
use_mmc_make=no
compile_times=false
write_out_profile_data=true
type_stats=""
trace_count=false
coverage_test=false
disable_debug_libs=false
delete_deep_data=false
deep_write_sample=true
deep_debug=false
progress=false

if test -f .KEEP_OBJS
then
    keep_objs=true
fi

if test -f .DELETE_DEEP_DATA
then
    delete_deep_data=true
fi

if test -f .BOOT_GRADE
then
    grade=`cat .BOOT_GRADE`
fi

if test -f .NO_WRITE_DEEP
then
    write_out_profile_data=false
fi

if test -f .PROGRESS
then
    progress=true
fi

# If you change these, you will also need to change the files indicated
# in scripts/c2init.in.
# RT_LIB_NAME=mer_rt            # not used in this script
STD_LIB_NAME=mer_std
TRACE_LIB_NAME=mer_trace
BROWSER_LIB_NAME=mer_browser
SSDB_LIB_NAME=mer_ssdb
MDBCOMP_LIB_NAME=mer_mdbcomp

while test $# -gt 0
do
    case "$1" in

        -b-|--no-bootcheck)
            do_bootcheck=false
            ;;

        -d|--test-dir)
            testdirs="${testdirs} $2"
            shift
            ;;
        -d*)
            testdirs="${testdirs} ` expr X$1 : 'X-d\(.*\)' `";
            ;;

        -e|--extras)
            extras=true
            ;;

        -s|--specified-tests)
            specified_tests_only="${specified_tests_only} $2"
            shift
            ;;

        -f|--failing-tests)
            failing_tests_only=true
            ;;

        --error-file)
            error_file_only=true
            ;;

        --expect-no-failures)
            expect_listed_failures=false
            ;;

        -h|--help)
            echo "${usage}"
            exit 0
            ;;

        -j|--jobs)
            jfactor="-j$2"
            shift
            ;;
        -j*)
            jfactor="-j` expr X$1 : X'-j\(.*\)' `"
            ;;
        --jobs*)
            jfactor="--jobs` expr X$1 : 'X--jobs\(.*\)' `"
            ;;

        -k|--keep-objs)
            keep_objs=true
            ;;

        -m|--mmake|--mmake-opts)
            mmake_opts="${mmake_opts} $2"
            shift
            ;;

        -o|--output-file)
            outfile="$2"
            shift
            ;;
        -o*)
            outfile="` expr X$1 : 'X-o\(.*\)' `"
            ;;

        --target)
            case "$2" in
                c|java|csharp)
                    target="$2"
                    shift
                    ;;
                *)
                    echo "unknown target \`$2'" 1>&2
                    exit 1
                    ;;
            esac
            ;;

        -G|--grade)
            grade="$2"
            shift
            ;;
        -G*)
            grade="` expr X$1 : 'X-G\(.*\)' `"
            ;;

        --gradedir)
            use_gradedir=true
            grade="$2"
            shift
            ;;

        --test-grade)
            test_grade="$2"
            shift
            ;;

        --mercury-options)
            MERCURY_OPTIONS="$2"
            export MERCURY_OPTIONS
            shift
            ;;

        -r|--copy-runtime)
            copy_runtime=true
            ;;

        -g|--copy-boehm-gc)
            copy_boehm_gc=true
            ;;

        -p-|-no-copy-profilers)
            copy_profilers=false
            ;;

        --no-copy-slice)
            copy_slice=false
            ;;

        --check-namespace)
            check_namespace=true
            ;;
        --no-check-namespace)
            check_namespace=false
            ;;

        -t-|--no-test-suite)
            runtests=false
            ;;

        --skip-stage-2)
            keep_stage_2=true
            mmake_stage_2=false
            ;;

        -2|--keep-stage-2)
            keep_stage_2=true
            ;;

        -3|--keep-stage-3)
            keep_stage_3=true
            ;;

        --test-params)
            test_params=true
            ;;

        --no-test-params)
            test_params=false
            ;;

        --keep-success-log-files)
            KEEP_SUCCESS_LOG_FILES=keep_success_log_files
            export KEEP_SUCCESS_LOG_FILES
            ;;

        --stop-after-stage-2)
            stop_after_stage_2=true
            ;;

        --use-subdirs)
            use_subdirs=yes
            ;;
        --no-use-subdirs)
            use_subdirs=no
            ;;

        --use-mmc-make)
            use_mmc_make=yes
            use_subdirs=yes
            ;;
        --no-use-mmc-make)
            use_mmc_make=no
            ;;

        --compile-times)
            compile_times=true
            ;;
        --no-compile-times)
            compile_times=false
            ;;

        --no-write-out-profile-data)
            write_out_profile_data=false
            ;;

        --type-stats)
            type_stats="$2"
            shift
            ;;

        --trace-count|--trace-counts)
            trace_count=true
            ;;

        --coverage-test)
            coverage_test=true
            ;;

        -W|--windows)
            windows=true
            use_cp=true
            ;;

        --use-cp)
            use_cp=true
            ;;

        --no-sym-links)
            use_cp=true
            ;;

        --disable-debug-libs)
            disable_debug_libs=true
            ;;

        --delete-deep-data)
            delete_deep_data=true
            ;;

        --deep-all-write)
            deep_write_sample=false
            ;;

        --deep-debug)
            deep_debug=true
            ;;

        --progress)
            progress=true
            ;;

        --)
            shift
            break
            ;;
        -*)
            echo "$0: unknown option \`$1'" 1>&2
            echo "${usage}" 1>&2
            exit 1
            ;;
        *)
            break
            ;;

    esac
    shift
done

if test $# -ne 0
then
    echo "$0: unexpected argument(s) \`$*'" 1>&2
    echo "${usage}" 1>&2
    exit 1
fi

if test "${grade}" != "" -a "${test_grade}" = ""
then
    test_grade="${grade}"
fi

# For the C# and Java grades we must use mmc --make and should disable the
# namespace cleanliness check.
#
case "${grade}" in
    java)
        target=java
        use_mmc_make=yes
        use_subdirs=yes
        check_namespace=false
        ;;
    csharp)
        target=csharp
        use_mmc_make=yes
        use_subdirs=yes
        check_namespace=false
        ;;
esac
case ${use_subdirs} in
    yes)
        cs_subdir=Mercury/cs/
        css_subdir=Mercury/css/
        javas_subdir=Mercury/javas/jmercury/
        ;;
    no)
        cs_subdir=
        css_subdir=
        javas_subdir=
        ;;
esac

case ${target} in
    c)
        target_ext=c
        target_subdir=${cs_subdir}
        target_opt=
        ;;

    csharp)
        target_ext=cs
        target_subdir=${css_subdir}
        target_opt=
        ;;

    java)
        target_ext=java
        target_subdir=${javas_subdir}
        target_opt=
        ;;
esac

if test "${grade}" != "" -o "${test_grade}" != ""
then
    copy_runtime=true
    copy_boehm_gc=true
fi

#-----------------------------------------------------------------------------#

# Work out how to parallelise the bootcheck when -jN with N > 1 is given.
#
# If --use-mmc-make is *not* enabled then all parallelism is handled by mmake,
# using its -jN option.
#
# If --use-mmc-make is enabled, then each directory containing Mercury
# libraries or executables must be built using a single invocation of
# mmc --make.  Multiple invocation of mmc --make in the same directory
# will conflict with each other. Directories containing target code only,
# such as the runtime or trace directories, still need to be built with
# mmake in order to parallelise their builds.
#
# Regardless of whether --use-mmc-make is enabled or not, we run the test suite
# using mmake -jN.

if test "${jfactor}" != ""
then
    if test "${use_mmc_make}" = "yes"
    then
        mmake_jobs=
        mmc_make_jobs="MCFLAGS += ${jfactor}"
    else
        mmake_jobs="${jfactor}"
        mmc_make_jobs=
    fi
else
    mmake_jobs=
    mmc_make_jobs=
fi

#-----------------------------------------------------------------------------#

if ${use_cp}
then
    LN="cp -pr"
    LN_S="cp -pr"
else
    LN="ln"
    LN_S="ln -s"
fi

#-----------------------------------------------------------------------------#

if ${windows}
then
    CYGPATH='cygpath -m'
else
    CYGPATH='echo'
fi

#-----------------------------------------------------------------------------#

# Turn off the debugger, since accidentally leaving it on will result
# in user interaction every time we invoke any version of the compiler
# that was compiled with tracing. This has happened to me accidentally
# one too many times - zs.
if echo "${MERCURY_OPTIONS}" | grep '\-Di' > /dev/null
then
    MERCURY_OPTIONS=`echo "${MERCURY_OPTIONS}" | sed -e 's/-Di//'`
    export MERCURY_OPTIONS
fi

echo "starting at `date`"

# set -x

root=`/bin/pwd`
root=`${CYGPATH} ${root}`
PATH=${root}/tools:${PATH}
export PATH

#-----------------------------------------------------------------------------#

if test "${use_gradedir}" = "true"
then
    stage2dir=stage2.${grade}
    stage3dir=stage3.${grade}
else
    stage2dir=stage2
    stage3dir=stage3
fi

if ${progress}
then
    BOOTCHECK_TEST_PROGRESS=yes
    export BOOTCHECK_TEST_PROGRESS
fi

ORIG_MERCURY_OPTIONS="${MERCURY_OPTIONS}"

if ${write_out_profile_data}
then
    true
else
    # Turn off the writing out of deep profiling files, since
    # Deep.data will be overwritten many times in each directory,
    # and thus the time spent writing them out is wasted. If deep
    # profiling debugging is enabled, this also avoids the writing
    # of *huge* amounts of stuff on stderr.
    MERCURY_OPTIONS="${MERCURY_OPTIONS} -s"
    export MERCURY_OPTIONS
fi

# In deep profiling grades, we want to test the code for writing out the
# profiling tree, but there is no point in testing it on every single
# invocation of the compiler, and doing so leads to *very* slow bootchecks.
# We therefore enable it only for every 25th invocation, on average.
#
# When the profiling data is written out, however, we also want to test
# writing out the program representation.
if ${deep_write_sample}
then
    MERCURY_OPTIONS="${MERCURY_OPTIONS} --deep-random-write=25"
    export MERCURY_OPTIONS
fi

if ${deep_debug}
then
    MERCURY_OPTIONS="${MERCURY_OPTIONS} --deep-debug-file"
    export MERCURY_OPTIONS
fi

if ${trace_count}
then
    MERCURY_OPTIONS="${MERCURY_OPTIONS} --trace-count-if-exec=mercury_compile"
    export MERCURY_OPTIONS
fi

if ${coverage_test}
then
    mkdir -p ${root}/coverage
    # Don't contaminate the coverage test with old data.
    /bin/rm ${root}/coverage/COVERAGE_TEST_DATA* > /dev/null 2>&1
    MERCURY_OPTIONS="${MERCURY_OPTIONS} --coverage-test-if-exec=mercury_compile --trace-count-summary-file=${root}/coverage/COVERAGE_TEST_DATA --trace-count-summary-cmd=${root}/slice/mtc_union"
    export MERCURY_OPTIONS
    # Check whether we can compile the slice directory.
    copy_slice=true
fi

NEW_MERCURY_OPTIONS="${MERCURY_OPTIONS} --mdb-disable-progress"

if ${do_bootcheck}
then
    MERCURY_OPTIONS="${ORIG_MERCURY_OPTIONS}"
    export MERCURY_OPTIONS

    if mmake ${mmake_opts} MMAKEFLAGS=${jfactor} all
    then
        echo "building of stage 1 successful"
    else
        cd ${root}
        mmake ${mmake_opts} depend
        if mmake ${mmake_opts} MMAKEFLAGS=${jfactor} all
        then
            echo "building of stage 1 successful"
        else
            echo "building of stage 1 not successful"
            exit 1
        fi
    fi

    MMAKE_USE_SUBDIRS=${use_subdirs}
    export MMAKE_USE_SUBDIRS

    MMAKE_USE_MMC_MAKE=${use_mmc_make}
    export MMAKE_USE_MMC_MAKE

    MERCURY_OPTIONS="${NEW_MERCURY_OPTIONS}"
    export MERCURY_OPTIONS

    MERCURY_COMPILER=${root}/compiler/mercury_compile
    export MERCURY_COMPILER

    # now in FLAGS files
    # MERCURY_CONFIG_FILE=${root}/scripts/Mercury.config
    # export MERCURY_CONFIG_FILE

    test -d ${stage2dir} || mkdir ${stage2dir}
    if ${keep_stage_2}
    then
        echo keeping existing stage2
    else
        /bin/rm -fr ${root}/${stage2dir} < /dev/null
        mkdir ${root}/${stage2dir}
    fi

    if ${mmake_stage_2}
    then
        set +x
        echo linking stage 2... 1>&2
        cd ${stage2dir}
        ${LN_S} ${root}/RESERVED_MACRO_NAMES .

        mkdir compiler
        cd compiler
        # Break up the links into several chunks.
        # This is needed to cope with small limits
        # on the size of argument vectors.
        ${LN_S} ${root}/compiler/[a-h]*.m .
        ${LN_S} ${root}/compiler/[i-o]*.m .
        ${LN_S} ${root}/compiler/[p-s]*.m .
        ${LN_S} ${root}/compiler/[t-z]*.m .
        ${LN_S} ${root}/compiler/notes .
        cp ${root}/compiler/Mmake* ${root}/compiler/Mercury.options .
        cp ${root}/compiler/*_FLAGS.in .
        cp ${root}/compiler/.mgnu* .

        cd ${root}/${stage2dir}
        mkdir library
        cd library
        ${LN_S} ${root}/library/[a-l]*.m .
        ${LN_S} ${root}/library/[m-z]*.m .
        # See comment below for why we use ${LN} rather than ${LN_S} here
        ${LN} ${root}/library/library_strong_name.sn .
        ${LN_S} ${root}/library/print_extra_inits .
        ${LN_S} ${root}/library/MODULES_DOC .
        ${LN_S} ${root}/library/MODULES_UNDOC .
        cp ${root}/library/Mmake* ${root}/library/Mercury.options .
        cp ${root}/library/*_FLAGS.in .
        cp ${root}/library/INTER_FLAGS* .
        cp ${root}/library/.mgnu* .
        ${LN_S} ${root}/library/${STD_LIB_NAME}.init .
        ${LN_S} ${root}/library/RESERVED_MACRO_NAMES .

        cd ${root}/${stage2dir}
        mkdir mdbcomp
        cd mdbcomp
        ${LN_S} ${root}/mdbcomp/*.m .
        cp ${root}/mdbcomp/Mmake* ${root}/mdbcomp/Mercury.options .
        cp ${root}/mdbcomp/*_FLAGS.in .
        cp ${root}/mdbcomp/.mgnu* .
        ${LN_S} ${root}/mdbcomp/${MDBCOMP_LIB_NAME}.init .
        ${LN_S} ${root}/mdbcomp/RESERVED_MACRO_NAMES .

        cd ${root}/${stage2dir}
        mkdir browser
        cd browser
        ${LN_S} ${root}/browser/*.m .
        cp ${root}/browser/Mmake* ${root}/browser/Mercury.options .
        cp ${root}/browser/*_FLAGS.in .
        cp ${root}/browser/.mgnu* .
        ${LN_S} ${root}/browser/${BROWSER_LIB_NAME}.init .
        ${LN_S} ${root}/browser/RESERVED_MACRO_NAMES .

        cd ${root}/${stage2dir}
        mkdir ssdb
        cd ssdb
        ${LN_S} ${root}/ssdb/*.m .
        cp ${root}/ssdb/Mmake* ${root}/ssdb/Mercury.options .
        cp ${root}/ssdb/*_FLAGS.in .
        cp ${root}/ssdb/.mgnu* .
        ${LN_S} ${root}/ssdb/${SSDB_LIB_NAME}.init .
        ${LN_S} ${root}/ssdb/RESERVED_MACRO_NAMES .

        cd ${root}/${stage2dir}
        mkdir grade_lib
        cd grade_lib
        ${LN_S} ${root}/grade_lib/*.m .
        cp ${root}/grade_lib/Mmake* ${root}/grade_lib/Mercury.options .
        cp ${root}/grade_lib/*_FLAGS.in .
        cp ${root}/grade_lib/.mgnu* .

        cd ${root}/${stage2dir}
        mkdir mfilterjavac
        cd mfilterjavac
        ${LN_S} ${root}/mfilterjavac/*.m .
        cp ${root}/mfilterjavac/Mmake* .
        cp ${root}/mfilterjavac/*_FLAGS.in .
        cp ${root}/mfilterjavac/.mgnu* .
        cd ${root}/${stage2dir}

        cd ${root}/${stage2dir}
        if ${copy_runtime}
        then
            # Remove symbolic link to the stage 1 runtime
            # if it is present, which it can be with the -2 option.
            rm -f runtime
            mkdir runtime
            cd runtime
            ${LN_S} ${root}/runtime/*.h .
            ${LN_S} ${root}/runtime/*.c .
            ${LN_S} ${root}/runtime/*.cs .
            # We need to use ${LN} rather than ${LN_S} for the files
            # that get processed with Microsoft's tools, since
            # Microsoft's tools don't understand Cygwin symbolic links
            # (hard links are OK, Cygwin's ln just makes copies).
            rm -f mercury_conf*.h
            ${LN} ${root}/runtime/mercury_conf*.h .
            ${LN_S} ${root}/runtime/*.in .
            cp ${root}/runtime/Mmake* .
            cp ${root}/runtime/.mgnu* .
            ${LN_S} ${root}/runtime/machdeps .
            ${LN_S} ${root}/runtime/RESERVED_MACRO_NAMES .

            cd ${root}/${stage2dir}
            rm -f trace
            mkdir trace
            cd trace
            ${LN_S} ${root}/trace/*.h .
            ${LN_S} ${root}/trace/*.c .
            ${LN_S} ${root}/trace/*.[yl] .
            cp ${root}/trace/Mmake* .
            cp ${root}/trace/.mgnu* .
            ${LN_S} ${root}/trace/RESERVED_MACRO_NAMES .

            cd ${root}/${stage2dir}
            rm -f robdd
            mkdir robdd
            cd robdd
            ${LN_S} ${root}/robdd/*.h .
            ${LN_S} ${root}/robdd/*.c .
            cp ${root}/robdd/Mmake* .
            cp ${root}/robdd/Make* .
            cd ${root}/${stage2dir}
        else
            ${LN_S} ${root}/runtime .
            ${LN_S} ${root}/trace .
            ${LN_S} ${root}/robdd .
        fi
        if ${copy_boehm_gc}
        then
            # Remove symbolic link to the stage 1 gc
            # if it is present, which it can be with the -2 option.
            rm -f boehm_gc
            mkdir boehm_gc
            cd boehm_gc
            ${LN_S} ${root}/boehm_gc/*.c .
            ${LN_S} ${root}/boehm_gc/*.s .
            ${LN_S} ${root}/boehm_gc/*.S .
            ${LN_S} ${root}/boehm_gc/include .
            cp ${root}/boehm_gc/Mmake* .
            cp ${root}/boehm_gc/Makefile.direct .
            cp ${root}/boehm_gc/NT*_MAKEFILE .
            cp ${root}/boehm_gc/gc.mak .
            cp ${root}/boehm_gc/gc_cpp.cc .
            cp ${root}/boehm_gc/gc_cpp.cpp .
            cp -r ${root}/boehm_gc/cord .
            cp -r ${root}/boehm_gc/libatomic_ops .
            cp -r ${root}/boehm_gc/extra .
            cp -r ${root}/boehm_gc/tools .
            cd ${root}/${stage2dir}
        else
            ${LN_S} ${root}/boehm_gc .
        fi
        ${LN_S} ${root}/java .
        ${LN_S} ${root}/bindist .
        ${LN_S} ${root}/doc .
        ${LN_S} ${root}/scripts .
        ${LN_S} ${root}/tools .
        ${LN_S} ${root}/util .

        if ${copy_slice}
        then
            mkdir slice
            cd slice
            ${LN_S} ${root}/slice/*.m .
            cp ${root}/slice/Mmake* ${root}/slice/Mercury.options .
            cp ${root}/slice/*_FLAGS.in .
            cp ${root}/slice/.mgnu* .
            cd ${root}/${stage2dir}
        else
            ${LN_S} ${root}/slice .
        fi

        if ${copy_profilers}
        then
            mkdir profiler
            cd profiler
            ${LN_S} ${root}/profiler/*.m .
            cp ${root}/profiler/Mmake* ${root}/profiler/Mercury.options .
            cp ${root}/profiler/*_FLAGS.in .
            cp ${root}/profiler/.mgnu* .
            cd ${root}/${stage2dir}

            mkdir deep_profiler
            cd deep_profiler
            ${LN_S} ${root}/deep_profiler/*.m .
            cp ${root}/deep_profiler/Mmake* .
            cp ${root}/deep_profiler/Mercury.options .
            cp ${root}/deep_profiler/*_FLAGS.in .
            cp ${root}/deep_profiler/.mgnu* .
            cd ${root}/${stage2dir}
        else
            ${LN_S} ${root}/profiler .
            ${LN_S} ${root}/deep_profiler .
        fi

        ${LN_S} ${root}/conf* .
        ${LN_S} ${root}/aclocal.m4 .
        ${LN_S} ${root}/m4 .
        ${LN_S} ${root}/VERSION .
        ${LN_S} ${root}/install-sh .
        ${LN_S} ${root}/.*.in .
        ${LN_S} ${root}/mercury.snk .
        rm -f config*.log
        cp ${root}/Mmake* ${root}/Mercury.options .
        if test -f ${root}/Mmake.stage.params
        then
            /bin/rm -f Mmake.params
            cp ${root}/Mmake.stage.params Mmake.params
        fi
        if test -f ${root}/Mmake.stage.slice.params
        then
            /bin/rm -f slice/Mmake.slice.params
            cp ${root}/Mmake.stage.slice.params slice/Mmake.slice.params
        fi
        if test -f ${root}/Mmake.stage.mdbcomp.params
        then
            /bin/rm -f mdbcomp/Mmake.mdbcomp.params
            cp ${root}/Mmake.stage.mdbcomp.params mdbcomp/Mmake.mdbcomp.params
        fi
        if test -f ${root}/Mmake.stage.browser.params
        then
            /bin/rm -f browser/Mmake.browser.params
            cp ${root}/Mmake.stage.browser.params browser/Mmake.browser.params
        fi
        if test -f ${root}/Mmake.stage.ssdb.params
        then
            /bin/rm -f ssdb/Mmake.ssdb.params
            cp ${root}/Mmake.stage.ssdb.params ssdb/Mmake.ssdb.params
        fi
        if test -f ${root}/Mmake.stage.grade_lib.params
        then
            /bin/rm -f grade_lib/Mmake.grade_lib.params
            cp ${root}/Mmake.stage.grade_lib.params \
                grade_lib/Mmake.grade_lib.params
        fi
        if test -f ${root}/Mmake.stage.deep.params
        then
            /bin/rm -f deep_profiler/Mmake.deep.params
            cp ${root}/Mmake.stage.deep.params deep_profiler/Mmake.deep.params
        fi
        if test -f ${root}/Mmake.stage.compiler.params
        then
            /bin/rm -f compiler/Mmake.compiler.params
            cp ${root}/Mmake.stage.compiler.params \
                compiler/Mmake.compiler.params
        fi
        if test -f ${root}/Mmake.stage.library.params
        then
            /bin/rm -f library/Mmake.library.params
            cp ${root}/Mmake.stage.library.params library/Mmake.library.params
        fi
        if test -f ${root}/Mmake.stage.runtime.params
        then
            /bin/rm -f runtime/Mmake.runtime.params
            cp ${root}/Mmake.stage.runtime.params runtime/Mmake.runtime.params
        fi
        if test -f ${root}/Mmake.stage.trace.params
        then
            /bin/rm -f trace/Mmake.trace.params
            cp ${root}/Mmake.stage.trace.params trace/Mmake.trace.params
        fi
        if test -f ${root}/Mercury.stage.options
        then
            /bin/rm -f Mercury.options
            cp ${root}/Mercury.stage.options Mercury.options
        fi
        if test "${grade}" != ""
        then
            echo "GRADE = ${grade}" >> Mmake.params
        fi
        if test "${use_mmc_make}" = "yes"
        then
            echo "${mmc_make_jobs}" >> Mmake.params
        fi
        cd ${root}

        # set -x

        MMAKE_VPATH=.
        export MMAKE_VPATH
        MMAKE_DIR=${root}/scripts
        export MMAKE_DIR

        # Use the new mmake to build stage 2.
        MMAKE=${MMAKE_DIR}/mmake
        mmake_opts="${mmake_opts} ${target_opt}"

        MERCURY_MKINIT="${root}/util/mkinit"
        export MERCURY_MKINIT

        if (cd ${stage2dir} && ${MMAKE} ${mmake_opts} ${jfactor} runtime)
        then
            echo "building of stage 2 runtime successful"
        else
            echo "building of stage 2 runtime not successful"
            exit 1
        fi

        case ${use_mmc_make} in
            yes)
                # The rules to generate *_FLAGS files from *_FLAGS.in files
                # will not run if we are using `mmc --make', so run them now.
                if (cd ${stage2dir} && \
                    ${MMAKE} compiler/COMP_FLAGS library/LIB_FLAGS \
                        mdbcomp/MDBCOMP_FLAGS grade_lib/GRADE_LIB_FLAGS \
                        profiler/PROF_FLAGS deep_profiler/DEEP_FLAGS)
                then
                    echo "building of stage 2 flags files successful"
                else
                    echo "building of stage 2 flags files not successful"
                    exit 1
                fi
                ;;
        esac

        if (cd ${stage2dir} && \
            ${MMAKE} ${mmake_opts} \
                dep_library \
                dep_mdbcomp \
                dep_browser dep_browser_aux \
                dep_ssdb \
                dep_grade_lib \
                dep_compiler \
                dep_slice \
                dep_profiler dep_profiler_aux \
                dep_deep_profiler \
                dep_mfilterjavac)
        then
            echo "building of stage 2 dependencies successful"
        else
            echo "building of stage 2 dependencies not successful"
            exit 1
        fi

        # For the csharp grade, Mmake.workspace needs to see the grade setting
        # when it defines MLLIBS, otherwise we will try to reference a separate
        # Mercury runtime assembly, which we do not have for the csharp grade.
        # As per README.Csharp, we need to set GRADE as part of the command
        # line that invokes mmake.
        if test "${grade}" = "csharp"
        then
            ENVGRADE="GRADE=${grade}"
        else
            ENVGRADE=
        fi

        if (cd ${stage2dir}/library && \
            ${MMAKE} ${mmake_opts} ${mmake_jobs} all-ints mercury ${ENVGRADE})
        then
            echo "building of stage 2 library successful"
        else
            echo "building of stage 2 library not successful"
            exit 1
        fi

        if (cd ${stage2dir}/mdbcomp && \
            ${MMAKE} ${mmake_opts} ${mmake_jobs} library ${ENVGRADE})
        then
            echo "building of stage 2 mdbcomp successful"
        else
            echo "building of stage 2 mdbcomp not successful"
            exit 1
        fi

        if (cd ${stage2dir}/browser && \
            ${MMAKE} ${mmake_opts} ${mmake_jobs} library aux ${ENVGRADE})
        then
            echo "building of stage 2 browser successful"
        else
            echo "building of stage 2 browser not successful"
            exit 1
        fi

        if (cd ${stage2dir}/ssdb && \
            ${MMAKE} ${mmake_opts} ${mmake_jobs} library ${ENVGRADE})
        then
            echo "building of stage 2 ssdb successful"
        else
            echo "building of stage 2 ssdb not successful"
            exit 1
        fi

        if (cd ${stage2dir}/trace && \
            ${MMAKE} ${mmake_opts} ${jfactor} trace ${ENVGRADE})
        then
            echo "building of stage 2 trace successful"
        else
            echo "building of stage 2 trace not successful"
            exit 1
        fi

        if ${disable_debug_libs}
        then
            /bin/rm ${stage2dir}/browser/lib${BROWSER_LIB_NAME}.a
            ar cr ${stage2dir}/browser/lib${BROWSER_LIB_NAME}.a
            /bin/rm ${stage2dir}/ssdb/lib${SSDB_LIB_NAME}.a
            ar cr ${stage2dir}/ssdb/lib${SSDB_LIB_NAME}.a
            /bin/rm ${stage2dir}/trace/lib${TRACE_LIB_NAME}.a
            ar cr ${stage2dir}/trace/lib${TRACE_LIB_NAME}.a
        fi

        if (cd ${stage2dir}/compiler && \
            ${MMAKE} ${mmake_opts} ${mmake_jobs} mercury_compile ${ENVGRADE})
        then
            echo "building of stage 2 compiler successful"
        else
            echo "building of stage 2 compiler not successful"
            exit 1
        fi

        # We use "mmake" instead ${MMAKE} because we don't want to override
        # the mmc in ${PATH} with the one in scripts, since that one will
        # probably refer to a nonexistent executable in /usr/local/mercury-DEV.

        if (cd ${stage2dir}/grade_lib && \
            unset MMAKE && \
            unset MMAKE_VPATH && \
            unset MMAKE_DIR && \
            unset MERCURY_CONFIG_DIR && \
            unset MERCURY_STDLIB_DIR && \
            mmake ${mmake_opts} ${mmake_jobs} all ${ENVGRADE})
        then
            echo "building of stage 2 grade_lib successful"
        else
            echo "building of stage 2 grade_lib not successful"
            exit 1
        fi

        if (cd ${stage2dir}/slice && \
            unset MMAKE && \
            unset MMAKE_VPATH && \
            unset MMAKE_DIR && \
            unset MERCURY_CONFIG_DIR && \
            unset MERCURY_STDLIB_DIR && \
            mmake ${mmake_opts} ${mmake_jobs} all ${ENVGRADE})
        then
            echo "building of stage 2 slice successful"
        else
            echo "building of stage 2 slice not successful"
            exit 1
        fi

        if (cd ${stage2dir}/profiler && \
            unset MMAKE && \
            unset MMAKE_VPATH && \
            unset MMAKE_DIR && \
            unset MERCURY_CONFIG_DIR && \
            unset MERCURY_STDLIB_DIR && \
            mmake ${mmake_opts} ${mmake_jobs} all aux ${ENVGRADE})
        then
            echo "building of stage 2 profiler successful"
        else
            echo "building of stage 2 profiler not successful"
            exit 1
        fi

        if (cd ${stage2dir}/deep_profiler && \
            unset MMAKE && \
            unset MMAKE_VPATH && \
            unset MMAKE_DIR && \
            unset MERCURY_CONFIG_DIR && \
            unset MERCURY_STDLIB_DIR && \
            mmake ${mmake_opts} ${mmake_jobs} all ${ENVGRADE})
        then
            echo "building of stage 2 deep profiler successful"
        else
            echo "building of stage 2 deep profiler not successful"
            exit 1
        fi

        if (cd ${stage2dir}/mfilterjavac && \
            unset MMAKE && \
            unset MMAKE_VPATH && \
            unset MMAKE_DIR && \
            unset MERCURY_CONFIG_DIR && \
            unset MERCURY_STDLIB_DIR && \
            mmake ${mmake_opts} ${mmake_jobs} all ${ENVGRADE})
        then
            echo "building of stage 2 mfilterjavac successful"
        else
            echo "building of stage 2 mfilterjavac not successful"
            exit 1
        fi

        if (cd ${stage2dir} && \
            ${MMAKE} ${mmake_opts} MMAKEFLAGS=${mmake_jobs} all ${ENVGRADE})
        then
            echo "building of stage 2 successful"
        else
            echo "building of stage 2 not successful"
            exit 1
        fi

        if ${compile_times}
        then
            ls -lt ${stage2dir}/library/*.c
            ls -lt ${stage2dir}/library/*.o
            ls -lt ${stage2dir}/library/*.{a,so,dylib}
            ls -lt ${stage2dir}/compiler/*.c
            ls -lt ${stage2dir}/compiler/*.o
            ls -lt ${stage2dir}/compiler/mercury_compile
        fi
    fi
    echo "finishing stage 2 at `date`"

    # Build the check_namespace target in the relevant directories.
    # We want to do so before we delete any of the stage 2 object files.

    check_namespace_status=0
    if ${check_namespace}
    then
        cd ${root}/${stage2dir}/runtime
        mmake ${mmake_opts} check_namespace || {
            echo '** mmake check_namespace failed in runtime!'
            check_namespace_status=1
        }
        cd ${root}/${stage2dir}/trace
        mmake ${mmake_opts} check_namespace || {
            echo '** mmake check_namespace failed in trace!'
            check_namespace_status=1
        }
        cd ${root}/${stage2dir}/library
        mmake ${mmake_opts} check_namespace || {
            echo '** mmake check_namespace failed in library!'
            check_namespace_status=1
        }
        cd ${root}/${stage2dir}/mdbcomp
        mmake ${mmake_opts} check_namespace || {
            echo '** mmake check_namespace failed in mdbcomp!'
            check_namespace_status=1
        }
        cd ${root}/${stage2dir}/browser
        mmake ${mmake_opts} check_namespace || {
            echo '** mmake check_namespace failed in browser!'
            check_namespace_status=1
        }
        cd ${root}/${stage2dir}/ssdb
        mmake ${mmake_opts} check_namespace || {
            echo '** mmake check_namespace failed in ssdb!'
            check_namespace_status=1
        }
        cd ${root}
    fi

    check_stdlib_modules_status=0
    cd ${root}/${stage2dir}/library
    mmake ${mmake_opts} check_stdlib_modules || {
        echo '** mmake check_stdlib_modules failed in library!'
        check_stdlib_modules_status=1
    }
    cd ${root}

    if ${stop_after_stage_2}
    then
        echo "stopping after building stage 2"
        exit 0
    fi

    # We can now remove the object files from most stage 2 directories,
    # but we will keep the compiler objects for a while longer.
    if ${keep_objs}
    then
        true
    else
        libdirs="library mdbcomp browser ssdb"
        if ${copy_slice}
        then
            slicedirs="slice"
        else
            slicedirs=
        fi
        if ${copy_profilers}
        then
            profdirs="profiler deep_profiler"
        else
            profdirs=
        fi
        if ${copy_runtime}
        then
            rundirs="runtime trace"
        else
            rundirs=
        fi

        objdirs="${libdirs} ${slicedirs} ${profdirs} ${rundirs}"
        for rmdir in ${objdirs}
        do
            cd ${root}/${stage2dir}/${rmdir}
            /bin/rm -f *.o *.pic_o
        done

        if ${check_namespace}
        then
            for cleandir in runtime trace library mdbcomp browser ssdb
            do
                cd ${root}/${stage2dir}/${cleandir}
                mmake clean_check
            done
        fi

        cd ${root}
    fi

    # In the java grade, the generated mercury_compile wrapper script
    # will not set the CLASSPATH correctly when building stage 3.
    # Replace it with one that will.
    #
    if test "${grade}" = "java"
    then
cat > ${root}/${stage2dir}/compiler/mercury_compile << EOF
#!/bin/sh
case \$WINDIR in
   '') SEP=':' ;;
   *)  SEP=';' ;;
esac
CLASSPATH=${root}/${stage2dir}/compiler/mercury_compile.jar\${SEP}${root}/${stage2dir}/library/mer_rt.jar\${SEP}${root}/${stage2dir}/library/mer_std.jar\${SEP}${root}/${stage2dir}/mdbcomp/mer_mdbcomp.jar
export CLASSPATH
JAVA=\${JAVA:-/usr/bin/java}
exec "\$JAVA" -Xss32m jmercury.mercury_compile "\$@"
EOF

       # The Java version of the Mercury runtime does not currently support
       # most of the runtime options and will abort if they are passed to it.
       MERCURY_OPTIONS=
       export MERCURY_OPTIONS
    fi

    # In the csharp grade we also need to replace the generated mercury_compile
    # wrapper script.
    # XXX the following only works with Mono.
    if test "${grade}" = "csharp"
    then
cat > ${root}/${stage2dir}/compiler/mercury_compile << EOF
#!/bin/sh
MONO_PATH=\$MONO_PATH:${root}/${stage2dir}/library:${root}/${stage2dir}/mdbcomp
export MONO_PATH
CLI_INTERPRETER=\${CLI_INTERPRETER:-/usr/bin/mono}
exec "\$CLI_INTERPRETER" "${root}/${stage2dir}/compiler/mercury_compile.exe" "\$@"
EOF
    fi

    MERCURY_COMPILER=${root}/${stage2dir}/compiler/mercury_compile
    export MERCURY_COMPILER

    test -d ${stage3dir} || mkdir ${stage3dir}
    if ${keep_stage_3}
    then
        echo keeping existing stage3
    else
        /bin/rm -fr ${root}/${stage3dir} < /dev/null
        mkdir ${root}/${stage3dir}
    fi

    echo linking stage 3... 1>&2
    set +x

    cd ${stage3dir}
    mkdir compiler
    cd compiler
    # Break up the links into several chunks.
    # This is needed to cope with small limits
    # on the size of argument vectors.
    ${LN_S} ${root}/compiler/[a-h]*.m .
    ${LN_S} ${root}/compiler/[i-o]*.m .
    ${LN_S} ${root}/compiler/[p-s]*.m .
    ${LN_S} ${root}/compiler/[t-z]*.m .
    ${LN_S} ${root}/compiler/notes .
    cp ${root}/compiler/Mmake* ${root}/compiler/Mercury.options .
    cp ${root}/compiler/*_FLAGS.in .
    cp ${root}/compiler/.mgnu* .

    cd ${root}/${stage3dir}
    mkdir library
    cd library
    ${LN_S} ${root}/library/[a-l]*.m .
    ${LN_S} ${root}/library/[m-z]*.m .
    ${LN_S} ${root}/library/print_extra_inits .
    ${LN_S} ${root}/library/library_strong_name.sn .
    ${LN_S} ${root}/library/MODULES_DOC .
    ${LN_S} ${root}/library/MODULES_UNDOC .
    cp ${root}/library/Mmake* ${root}/library/Mercury.options .
    cp ${root}/library/*_FLAGS.in .
    cp ${root}/library/INTER_FLAGS* .
    cp ${root}/library/.mgnu* .
    ${LN_S} ${root}/library/${STD_LIB_NAME}.init .

    cd ${root}/${stage3dir}
    mkdir mdbcomp
    cd mdbcomp
    ${LN_S} ${root}/mdbcomp/*.m .
    cp ${root}/mdbcomp/Mmake* ${root}/mdbcomp/Mercury.options .
    cp ${root}/mdbcomp/*_FLAGS.in .
    cp ${root}/mdbcomp/.mgnu* .
    ${LN_S} ${root}/mdbcomp/${MDBCOMP_LIB_NAME}.init .

    cd ${root}/${stage3dir}
    mkdir browser
    cd browser
    ${LN_S} ${root}/browser/*.m .
    cp ${root}/browser/Mmake* ${root}/browser/Mercury.options .
    cp ${root}/browser/*_FLAGS.in .
    cp ${root}/browser/.mgnu* .
    ${LN_S} ${root}/browser/${BROWSER_LIB_NAME}.init .

    cd ${root}/${stage3dir}
    mkdir ssdb
    cd ssdb
    ${LN_S} ${root}/ssdb/*.m .
    cp ${root}/ssdb/Mmake* ${root}/ssdb/Mercury.options .
    cp ${root}/ssdb/*_FLAGS.in .
    cp ${root}/ssdb/.mgnu* .
    ${LN_S} ${root}/ssdb/${SSDB_LIB_NAME}.init .

    cd ${root}/${stage3dir}
    ${LN_S} ${root}/${stage2dir}/boehm_gc .
    ${LN_S} ${root}/${stage2dir}/java .
    ${LN_S} ${root}/bindist .
    ${LN_S} ${root}/doc .
    ${LN_S} ${root}/${stage2dir}/runtime .
    ${LN_S} ${root}/${stage2dir}/trace .
    ${LN_S} ${root}/${stage2dir}/robdd .
    ${LN_S} ${root}/scripts .
    ${LN_S} ${root}/tools .
    ${LN_S} ${root}/util .

    cd ${root}/${stage3dir}
    mkdir grade_lib
    cd grade_lib
    ${LN_S} ${root}/grade_lib/*.m .
    cp ${root}/grade_lib/Mmake* ${root}/grade_lib/Mercury.options .
    cp ${root}/grade_lib/*_FLAGS.in .
    cp ${root}/grade_lib/.mgnu* .

    cd ${root}/${stage3dir}
    mkdir slice
    cd slice
    ${LN_S} ${root}/slice/*.m .
    cp ${root}/slice/Mmake* ${root}/slice/Mercury.options .
    cp ${root}/slice/*_FLAGS.in .
    cp ${root}/slice/.mgnu* .

    cd ${root}/${stage3dir}
    mkdir profiler
    cd profiler
    ${LN_S} ${root}/profiler/*.m .
    cp ${root}/profiler/Mmake* ${root}/profiler/Mercury.options .
    cp ${root}/profiler/*_FLAGS.in .
    cp ${root}/profiler/.mgnu* .

    cd ${root}/${stage3dir}
    mkdir deep_profiler
    cd deep_profiler
    ${LN_S} ${root}/deep_profiler/*.m .
    cp ${root}/deep_profiler/Mmake* ${root}/deep_profiler/Mercury.options .
    cp ${root}/deep_profiler/*_FLAGS.in .
    cp ${root}/deep_profiler/.mgnu* .

    cd ${root}/${stage3dir}
    mkdir mfilterjavac
    cd mfilterjavac
    ${LN_S} ${root}/mfilterjavac/*.m .
    cp ${root}/mfilterjavac/Mmake* ${root}/mfilterjavac/Mercury.options .
    cp ${root}/mfilterjavac/*_FLAGS.in .
    cp ${root}/mfilterjavac/.mgnu* .

    cd ${root}/${stage3dir}
    ${LN_S} ${root}/conf* .
    ${LN_S} ${root}/aclocal.m4 .
    ${LN_S} ${root}/m4 .
    ${LN_S} ${root}/VERSION .
    ${LN_S} ${root}/install-sh .
    ${LN_S} ${root}/.*.in .
    rm -f config*.log
    cp ${root}/${stage2dir}/Mmake* ${root}/${stage2dir}/Mercury.options .
    cd ${root}
    # set -x

    MMAKE_VPATH=.
    export MMAKE_VPATH
    MMAKE_DIR=${root}/scripts
    export MMAKE_DIR

    # Use the new mmake to build stage 3.
    MMAKE=${MMAKE_DIR}/mmake

    # This setting is ignored unless the stage 2 was compiled with
    # -DMR_HO_CALL_STATS.
    HO_CALL_STATS="${root}/HO_CALL_STATS"
    export HO_CALL_STATS

    if test "${type_stats}" != ""
    then
        # Start collecting statistics from stage 3 with a clean slate,
        # while making sure that the existing stats are not lost.
        # Note: we do not have to go to any great lengths to restore
        # the old stats if bootcheck fails, since the save files
        # can easily be recovered outside bootcheck.

        cat "${type_stats}" >> "${type_stats}".save.$$
        cp /dev/null "${type_stats}"
    fi

    if (cd ${stage3dir} && \
        ${MMAKE} ${mmake_opts} \
            dep_library \
            dep_mdbcomp \
            dep_browser dep_browser_aux \
            dep_ssdb \
            dep_compiler \
            dep_grade_lib \
            dep_slice \
            dep_profiler dep_profiler_aux \
            dep_deep_profiler \
            dep_mfilterjavac)
    then
        echo "building of stage 3 dependencies successful"
    else
        echo "building of stage 3 dependencies not successful"
        exit 1
    fi

    if (cd ${stage3dir}/library &&
        ${MMAKE} ${mmake_opts} ${mmake_jobs} all-ints &&
        ${MMAKE} ${mmake_opts} ${mmake_jobs} ${target_ext}s)
    then
        echo "building of stage 3 library successful"
    else
        echo "building of stage 3 library initially not successful"
        df .
        # Try again, in case the failure cause was transient.
        if (cd ${stage3dir}/library &&
            ${MMAKE} ${mmake_opts} ${mmake_jobs} all-ints &&
            ${MMAKE} ${mmake_opts} ${mmake_jobs} ${target_ext}s)
        then
            echo "building of stage 3 library successful"
        else
            echo "building of stage 3 library not successful"
            exit 1
        fi
    fi

    # We delay deleting the stage 2 compiler objects until now,
    # so that if (a) an error manifests itself during the creation
    # of the stage 3 library, and (b) this error can be fixed by
    # changing the runtime, a bootcheck -2, which requires a relink,
    # will not have to expensively recreate the stage 2 compiler objects.

    if ${keep_objs}
    then
        true
    else
        find ${root}/${stage2dir}/compiler -name "*.o" -print |
        xargs /bin/rm -f
    fi

    if (cd ${stage3dir}/mdbcomp &&
        ${MMAKE} ${mmake_opts} ${mmake_jobs} all-ints &&
        ${MMAKE} ${mmake_opts} ${mmake_jobs} ${target_ext}s)
    then
        echo "building of stage 3 mdbcomp successful"
    else
        echo "building of stage 3 mdbcomp initially not successful"
        df .
        # Try again, in case the failure cause was transient.
        if (cd ${stage3dir}/mdbcomp && \
            ${MMAKE} ${mmake_opts} ${mmake_jobs} ${target_ext}s)
        then
            echo "building of stage 3 mdbcomp successful"
        else
            echo "building of stage 3 mdbcomp not successful"
            exit 1
        fi
    fi

    if (cd ${stage3dir}/browser &&
        ${MMAKE} ${mmake_opts} ${mmake_jobs} all-ints &&
        ${MMAKE} ${mmake_opts} ${mmake_jobs} ${target_ext}s)
    then
        echo "building of stage 3 browser successful"
    else
        echo "building of stage 3 browser initially not successful"
        df .
        # Try again, in case the failure cause was transient.
        if (cd ${stage3dir}/browser && \
            ${MMAKE} ${mmake_opts} ${mmake_jobs} ${target_ext}s)
        then
            echo "building of stage 3 browser successful"
        else
            echo "building of stage 3 browser not successful"
            exit 1
        fi
    fi

    if (cd ${stage3dir}/ssdb &&
        ${MMAKE} ${mmake_opts} ${mmake_jobs} all-ints &&
        ${MMAKE} ${mmake_opts} ${mmake_jobs} ${target_ext}s)
    then
        echo "building of stage 3 ssdb successful"
    else
        echo "building of stage 3 ssdb initially not successful"
        df .
        # Try again, in case the failure cause was transient.
        if (cd ${stage3dir}/ssdb && \
            ${MMAKE} ${mmake_opts} ${mmake_jobs} ${target_ext}s)
        then
            echo "building of stage 3 ssdb successful"
        else
            echo "building of stage 3 ssdb not successful"
            exit 1
        fi
    fi

    if (cd ${stage3dir}/compiler && \
        ${MMAKE} ${mmake_opts} ${mmake_jobs} ${target_ext}s)
    then
        echo "building of stage 3 compiler successful"
    else
        echo "building of stage 3 compiler initially not successful"
        df .
        # Try again, in case the failure cause was transient.
        if (cd ${stage3dir}/compiler && \
            ${MMAKE} ${mmake_opts} ${mmake_jobs} ${target_ext}s)
        then
            echo "building of stage 3 compiler successful"
        else
            echo "building of stage 3 compiler not successful"
            exit 1
        fi
    fi

    if (cd ${stage3dir}/grade_lib && \
        unset MMAKE && \
        unset MMAKE_VPATH && \
        unset MMAKE_DIR && \
        unset MERCURY_CONFIG_DIR && \
        unset MERCURY_STDLIB_DIR && \
        mmake ${mmake_opts} ${mmake_jobs} ${target_ext}s)
    then
        echo "building of stage 3 grade_lib successful"
    else
        echo "building of stage 3 grade_lib not successful"
        exit 1
    fi

    if (cd ${stage3dir}/slice && \
        unset MMAKE && \
        unset MMAKE_VPATH && \
        unset MMAKE_DIR && \
        unset MERCURY_CONFIG_DIR && \
        unset MERCURY_STDLIB_DIR && \
        mmake ${mmake_opts} ${mmake_jobs} ${target_ext}s)
    then
        echo "building of stage 3 slice successful"
    else
        echo "building of stage 3 slice not successful"
        exit 1
    fi

    if (cd ${stage3dir}/profiler && \
        unset MMAKE && \
        unset MMAKE_VPATH && \
        unset MMAKE_DIR && \
        unset MERCURY_CONFIG_DIR && \
        unset MERCURY_STDLIB_DIR && \
        mmake ${mmake_opts} ${mmake_jobs} ${target_ext}s)
    then
        echo "building of stage 3 profiler successful"
    else
        echo "building of stage 3 profiler not successful"
        exit 1
    fi

    if (cd ${stage3dir}/deep_profiler && \
        unset MMAKE && \
        unset MMAKE_VPATH && \
        unset MMAKE_DIR && \
        unset MERCURY_CONFIG_DIR && \
        unset MERCURY_STDLIB_DIR && \
        mmake ${mmake_opts} ${mmake_jobs} ${target_ext}s)
    then
        echo "building of stage 3 deep profiler successful"
    else
        echo "building of stage 3 deep profiler not successful"
        exit 1
    fi

    if (cd ${stage3dir}/mfilterjavac && \
        unset MMAKE && \
        unset MMAKE_VPATH && \
        unset MMAKE_DIR && \
        unset MERCURY_CONFIG_DIR && \
        unset MERCURY_STDLIB_DIR && \
        mmake ${mmake_opts} ${mmake_jobs} ${target_ext}s)
    then
        echo "building of stage 3 mfilterjavac successful"
    else
        echo "building of stage 3 mfilterjavac not successful"
        exit 1
    fi

    if test "${type_stats}" != ""
    then
        echo "Saving stage 3 stats in ${type_stats}.stage3.$$"
        mv "${type_stats}" "${type_stats}".stage3.$$
        cp /dev/null "${type_stats}"
    fi

    diff_status=0

    exec 3>&1       # save stdout in fd 3
    if test -n "${outfile}"
    then
        exec > "${outfile}"   # redirect stdout to ${outfile}
    fi

    for dir in library mdbcomp browser ssdb compiler \
        grade_lib slice profiler deep_profiler mfilterjavac
    do
        # `mmake cs' in the compiler directory doesn't build
        # `mercury_compile_init.c', so we only compare the `.c'
        # files present in the stage 3 directory.
        for file in ${stage3dir}/${dir}/${target_subdir}*.${target_ext}
        do
            diff -u ${stage2dir}/${dir}/${target_subdir}`basename ${file}` \
                ${file} \
            || diff_status=1
        done
    done

    exec >&3        # restore stdout from fd 3
    if test ${diff_status} -ne 0
    then
        echo "** error - stage 2 and stage 3 differ!"
    else
        echo "stage 2 and stage 3 compare ok"
        if test -d ${stage3dir}/library/ComplexityArgs
        then
            mv ${stage3dir}/library/ComplexityArgs \
                ${root}/stage3_library_ComplexityArgs
        fi
        if test -d ${stage3dir}/library/ComplexityData
        then
            mv ${stage3dir}/library/ComplexityData \
                ${root}/stage3_library_ComplexityData
        fi
        if test -d ${stage3dir}/compiler/ComplexityArgs
        then
            mv ${stage3dir}/compiler/ComplexityArgs \
                ${root}/stage3_compiler_ComplexityArgs
        fi
        if test -d ${stage3dir}/compiler/ComplexityData
        then
            mv ${stage3dir}/compiler/ComplexityData \
                ${root}/stage3_compiler_ComplexityData
        fi

        echo "removing stage 3..."
        /bin/rm -fr ${root}/${stage3dir} < /dev/null

        if ${keep_objs}
        then
            true
        else
            case "${grade}" in
                *debug*)
                    # These files take up a lot of disk space, so we compress
                    # them. This reduces the probability that running the tests
                    # will run out of disk space, while still allowing the
                    # original files to be reconstructed relatively quickly.
                    gzip ${root}/${stage2dir}/library/*.c
                    gzip ${root}/${stage2dir}/mdbcomp/*.c
                    gzip ${root}/${stage2dir}/browser/*.c
                    gzip ${root}/${stage2dir}/ssdb/*.c
                    gzip ${root}/${stage2dir}/compiler/*.c
                    ;;
            esac
        fi
    fi

    echo "finishing stage 3 at `date`"
else
    MMAKE_USE_SUBDIRS=${use_subdirs}
    export MMAKE_USE_SUBDIRS

    MMAKE_USE_MMC_MAKE=${use_mmc_make}
    export MMAKE_USE_MMC_MAKE

    diff_status=0
    check_namespace_status=0
    check_stdlib_modules_status=0
    echo "building of stages 1 and 2 skipped"
fi

#-----------------------------------------------------------------------------#

mdb_command_test_inp_status=0

if test "${runtests}" = "true" -o "${extras}" = "true"
then
    # Use everything from stage 2, unless the options say that the tests
    # should be done in grade different from the grade of stage 2,
    # in which case use everything from stage 1, trusting the user
    # that the grade of the tests and the grade of stage 1 are compatible.

    MERCURY_COMPILER=${root}/${stage2dir}/compiler/mercury_compile
    export MERCURY_COMPILER

    # now in FLAGS files
    # MERCURY_CONFIG_FILE=${root}/scripts/Mercury.config
    # export MERCURY_CONFIG_FILE

    if test "${test_grade}" = "${grade}"
    then
        stage2_insert="/${stage2dir}"
    else
        stage2_insert=""
    fi

    WORKSPACE="${root}${stage2_insert}"
    export WORKSPACE

    MMAKE_DIR="${root}${stage2_insert}/scripts"
    export MMAKE_DIR

    # Set PATH for mkinit, mmc, mgnuc, ml etc
    PATH=${root}${stage2_insert}/util:${root}${stage2_insert}/scripts:${PATH}
    export PATH
fi

#-----------------------------------------------------------------------------#

# Run the tests in the tests/* directories.

if test -s ${HOME}/.bootcheck_diff_opts
then
    DIFF_OPTS=`cat ${HOME}/.bootcheck_diff_opts`
    export DIFF_OPTS
fi

test_status=0
if ${runtests}
then
    echo "starting the test suite at `date`"

    # If the workspace has been moved since ${root}/scripts/test_mdbrc
    # was last built, that file will refer to the OLD location of
    # the workspace, which may not exist anymore. We therefore rebuild
    # the file.
    (cd ${root}/scripts; /bin/rm test_mdbrc; mmake test_mdbrc)
    MERCURY_DEBUGGER_INIT=${root}/scripts/test_mdbrc
    export MERCURY_DEBUGGER_INIT

    MERCURY_SUPPRESS_STACK_TRACE=yes
    export MERCURY_SUPPRESS_STACK_TRACE

    if test "${test_grade}" != ""
    then
        test_grade_opt="GRADE=${test_grade}"
    else
        test_grade_opt=""
    fi

    test_status=0
    if test -d tests
    then
        tests_prefix=""
    elif test -d ../tests
    then
        tests_prefix="../"
    else
        echo "cannot find test directory"
        test_status=1
    fi

    if test "${test_status}" = 0
    then
        if ${test_params}
        then
            cp ${root}/${stage2dir}/Mmake.params ${tests_prefix}tests
        else
            /bin/rm ${tests_prefix}tests/Mmake.params > /dev/null 2>&1
        fi

        if cmp \
            ${root}/doc/mdb_command_test.inp \
            ${tests_prefix}tests/debugger/mdb_command_test.inp
        then
            true
        else
            mdb_command_test_inp_status=1
        fi

        cp ${root}/doc/mdb_command_test.inp ${tests_prefix}tests/debugger

        sed -e "s:@WORKSPACE@:${WORKSPACE}:" \
            < ${tests_prefix}tests/WS_FLAGS.ws \
            > ${tests_prefix}tests/WS_FLAGS

        sed -e "s:@WORKSPACE@:${WORKSPACE}:" \
            < ${tests_prefix}tests/.mgnuc_copts.ws \
            > ${tests_prefix}tests/.mgnuc_copts

        # If you modify this, modify SUBDIRS in tests/Mmakefile as well.
        all_test_dirs="
            accumulator
            analysis
            analysis_ctgc
            analysis_excp
            analysis_external
            analysis_sharing
            analysis_table
            analysis_trail
            analysis_unused_args
            benchmarks
            debugger
            declarative_debugger
            dppd
            exceptions
            feedback
            general
            grade_subdirs
            hard_coded
            invalid
            invalid_make_int
            invalid_nodepend
            invalid_onlydepend
            invalid_options_file
            invalid_purity
            invalid_submodules
            misc_tests
            mmc_make
            options_file
            par_conj
            purity
            recompilation
            string_format
            structure_reuse
            submodules
            tabling
            term
            trailing
            typeclasses
            valid
            valid_make_int
            valid_seq
            warnings"

        for d in ${all_test_dirs}
        do
            cp ${tests_prefix}tests/.mgnuc_copts ${tests_prefix}tests/${d}
            cp ${tests_prefix}tests/.mgnuc_opts ${tests_prefix}tests/${d}
        done

        WORKSPACE_FLAGS=yes
        export WORKSPACE_FLAGS

        if test "${grade}" = "java"
        then
            MERCURY_STAGE2_LAUNCHER_BASE=${root}/${stage2dir}
            export MERCURY_STAGE2_LAUNCHER_BASE
        fi

        # Tell the executables for the tests where the stage 2 library lives.
        # XXX this only works for Mono; MS .NET doesn't have an equivalent of
        # the MONO_PATH environment variable. (To support MS .NETm we may just
        # have to copy the library DLL into any test directory that creates
        # executables.)
        if test "${grade}" = "csharp"
        then
            MONO_PATH=${root}/${stage2dir}/library
            export MONO_PATH
        fi

        case ${error_file_only} in
            true)
                if test ! -f ${tests_prefix}tests/runtests.errs
                then
                    echo "bootcheck: \`--failing-tests' specified but" 1>&2
                    echo \
                    "\`${tests_prefix}tests/runtests.errs' does not exist." \
                        1>&2
                    exit 1
                fi

                mv ${tests_prefix}tests/runtests.errs \
                    ${tests_prefix}tests/runtests.$$
                test_log_opt="ERROR_FILE=${root}/${tests_prefix}tests/runtests.$$"
                ;;
            false)
                test_log_opt=""
                ;;
        esac

        case ${failing_tests_only} in
            true)
                test_log_opt="FAILED_TESTS_ONLY=yes"
                ;;
        esac

        cd ${root}/${tests_prefix}tests
        true > FAILED_TESTS_SUMMARY
        true > NOMAKE_DIRS

        /bin/rm -fr PASSED_TC_DIR FAILED_TC_DIR > /dev/null 2>&1
        mkdir -p PASSED_TC_DIR FAILED_TC_DIR
        echo 0 > PASSED_TC_DIR/NEXT_NUMBER
        echo 0 > FAILED_TC_DIR/NEXT_NUMBER
        SLICE_DIR="${root}/slice/"
        export SLICE_DIR

        if test "${specified_tests_only}" != ""
        then
            test_status=0
            for specified_test in ${specified_tests_only}
            do
                specified_test_dir=`dirname ${specified_test}`
                specified_test_base=`basename ${specified_test}`
                if test -d \
                    "${root}/${tests_prefix}/tests/${specified_test_dir}"
                then
                    cd ${root}/${tests_prefix}tests/${specified_test_dir}
                    mmake ${mmake_opts} ${target_opt} ${jfactor} \
                        ${test_grade_opt} \
                        SPECIFIED_TESTS="${specified_test_base}" runtests_local
                    if test "$?" -ne "0"
                    then
                        test_status=$?
                    fi
                else
                    test_status=1
                fi
            done
        else
            if test "${testdirs}" = ""
            then
                testdirs="${all_test_dirs}"
            fi

            test_status=0
            for testdir in ${testdirs}
            do
                if test -d ${root}/${tests_prefix}tests/${testdir}
                then
                    cd ${root}/${tests_prefix}tests/${testdir}
                    mmake ${mmake_opts} ${target_opt} ${jfactor} \
                        ${test_grade_opt} ${test_log_opt} runtests_dir
                    if test "$?" -ne 0
                    then
                        test_status=1
                    fi
                else
                    echo "test dir ${testdir} does not exist"
                    test_status=1
                fi
            done
        fi

        case ${failing_tests_only} in
            true)
                rm -f ${tests_prefix}tests/runtests.$$
                ;;
        esac

        if test "${type_stats}" != ""
        then
            echo "Saving test suite stats in ${type_stats}.test.$$"
            mv "${type_stats}" "${type_stats}".test.$$
        fi

        cd ${root}/${tests_prefix}tests
        for tcdir in PASSED_TC_DIR FAILED_TC_DIR
        do
            if test "`cat ${tcdir}/NEXT_NUMBER`" -gt 0
            then
                ${SLICE_DIR}slice/mtc_union -o ${tcdir}/SUMMARY \
                    ${tcdir}/trace_counts.*
                /bin/rm ${tcdir}/trace_counts.*
            fi
        done

        cd ${root}
    fi
fi

#-----------------------------------------------------------------------------#

# Run the tests in the extras/* directories.

extras_status=0
if ${extras}
then
    cd ${root}/extras
    if test -f Mmake.params
    then
        mv Mmake.params Mmake.params.$$
    fi

    if test -f ${root}/Mmake.stage.params
    then
        cp ${root}/Mmake.stage.params Mmake.params
    elif test -f ${root}/Mmake.params
    then
        cp ${root}/Mmake.params Mmake.params
    else
        cp /dev/null Mmake.params
    fi

    if test "${test_grade}" != ""
    then
        echo "GRADE = ${test_grade}" >> Mmake.params
    elif test "${grade}" != ""
    then
        echo "GRADE = ${grade}" >> Mmake.params
    fi

    for testdir in *
    do
        if test -f ${testdir}/Mmakefile -a ! -f ${testdir}/NOBOOTTEST
        then
            (cd ${testdir};
            mmake ${mmake_opts} ${mmake_jobs} realclean;
            mmake ${mmake_opts} ${mmake_jobs} depend &&
            mmake ${mmake_opts} ${mmake_jobs} &&
            mmake ${mmake_opts} ${mmake_jobs} check &&
            mmake ${mmake_opts} ${mmake_jobs} realclean ) ||
            extras_status=1
        fi
    done

    if test -f Mmake.params.$$
    then
        mv Mmake.params.$$ Mmake.params
    else
        /bin/rm Mmake.params
    fi

    cd ${root}
fi

if ${delete_deep_data}
then
    (cd ${root}; \
        find stage2 tests -name Deep.data -o -name Deep.procrep -print \
        | xargs /bin/rm -f)
fi

#-----------------------------------------------------------------------------#

if test "${type_stats}" != ""
then
    mv "${type_stats}".save.$$ "${type_stats}"
fi

tests_dir="${root}/${tests_prefix}tests"

cat /dev/null > ${tests_dir}/EXPECT_FAIL_TESTS

if test -s ${tests_dir}/FAILED_TESTS_SUMMARY
then
    sed -e 's/ .*//' < ${tests_dir}/FAILED_TESTS_SUMMARY \
        > ${tests_dir}/FAIL_TESTS

    if test -f ${tests_dir}/EXPECT_FAIL_TESTS.all_grades
    then
        cat ${tests_dir}/EXPECT_FAIL_TESTS.all_grades >> \
            ${tests_dir}/EXPECT_FAIL_TESTS
    fi
    if test -f ${tests_dir}/EXPECT_FAIL_TESTS.${test_grade}
    then
        cat ${tests_dir}/EXPECT_FAIL_TESTS.${test_grade} >> \
            ${tests_dir}/EXPECT_FAIL_TESTS
    fi

    sort ${tests_dir}/EXPECT_FAIL_TESTS > ${tests_dir}/EXPECT_FAIL_TESTS.sort
    mv ${tests_dir}/EXPECT_FAIL_TESTS.sort ${tests_dir}/EXPECT_FAIL_TESTS

    sort ${tests_dir}/FAIL_TESTS > ${tests_dir}/FAIL_TESTS.sort
    mv ${tests_dir}/FAIL_TESTS.sort ${tests_dir}/FAIL_TESTS

    comm -23 ${tests_dir}/FAIL_TESTS \
        ${tests_dir}/EXPECT_FAIL_TESTS \
        > ${tests_dir}/UNEXPECTED_FAILED_TESTS
    comm -12 ${tests_dir}/FAIL_TESTS \
        ${tests_dir}/EXPECT_FAIL_TESTS \
        > ${tests_dir}/EXPECTED_FAILED_TESTS

    if ${expect_listed_failures}
    then
        if test ! -s ${tests_dir}/UNEXPECTED_FAILED_TESTS
        then
            test_status=0
        fi
    fi
fi

echo "-----------------------------------------------------------------------"

exitstatus=0

if test "${diff_status}" != 0
then
    echo "ERROR EXIT: stages 2 and 3 differ"
    exitstatus=1
fi

if test "${mdb_command_test_inp_status}" != 0
then

    echo "ERROR EXIT: unexpected change in" \
        "${tests_prefix}tests/debugger/mdb_command_test.inp"
    exitstatus=1
fi

if test "${test_status}" != 0
then
    echo "ERROR EXIT: some tests failed"
    exitstatus=1
fi

if test "${extras_status}" != 0
then
    echo "ERROR EXIT: some tests failed in extras"
    exitstatus=1
fi

if test "${check_namespace_status}" != 0
then
    echo "ERROR EXIT: some namespace isn't clean"
    exitstatus=1
fi

if test "${check_stdlib_modules_status}" != 0
then
    echo "ERROR EXIT: mismatch in list of stdlib modules"
    exitstatus=1
fi

if test -s ${tests_dir}/NOMAKE_DIRS
then
    echo "ERROR EXIT: some test directories were left out"
    cat ${tests_dir}/NOMAKE_DIRS
    exitstatus=1
fi

if test -s ${tests_dir}/FAILED_TESTS_SUMMARY
then
    num_expected_failures=`wc -l < ${tests_dir}/EXPECTED_FAILED_TESTS`
    case "${num_expected_failures}" in
        0)
            ;;
        1)
            echo "one expected test case failure:"
            echo
            sed -e 's/^/    /' < ${tests_dir}/EXPECTED_FAILED_TESTS
            echo
            ;;
        *)
            echo "${num_expected_failures} expected test case failures:"
            echo
            sed -e 's/^/    /' < ${tests_dir}/EXPECTED_FAILED_TESTS
            echo
            ;;
    esac

    num_unexpected_failures=`wc -l < ${tests_dir}/UNEXPECTED_FAILED_TESTS`
    case "${num_unexpected_failures}" in
        0)
            ;;
        1)
            echo "one unexpected test case failure:"
            echo
            sed -e 's/^/    /' < ${tests_dir}/UNEXPECTED_FAILED_TESTS
            echo
            ;;
        *)
            echo "${num_unexpected_failures} unexpected test case failures:"
            echo
            sed -e 's/^/    /' < ${tests_dir}/UNEXPECTED_FAILED_TESTS
            echo
            ;;
    esac
fi

if test "${exitstatus}" = "0"
then
    echo "SUCCESSFUL EXIT"
fi

echo "-----------------------------------------------------------------------"

echo "finishing at `date`"
exit ${exitstatus}

#-----------------------------------------------------------------------------#
