#!/bin/sh
#
# vim: ts=4 sw=4 et
#
# Test the stage2 directory to see whether it passes
# a bootstrap check and/or a check using the tests directory.
# If stage2 passes, binary_step returns an exit status of 0 (true);
# if it fails, binary_step returns an exit status of 1 (false).
#
# binary_step remakes the archive in stage2/library and the executable
# in stage2/compiler. In the intended use, the binary script sets up
# these directories so that these actions cause no recompilations,
# either Mercury to C or C to object, only linking. Other uses probably
# won't work.

usage="\
Usage: $0 [options]
Options:
    -b-, --no-bootcheck
        Do not perform a bootcheck; check only the tests directory.
    -c, --compile-only
        Check the successful creation of the stage3 .c files,
        but do not compare stage2.ok and stage3.
    -C, --compare-to-bad
        Compile stage3 using the parameter settings in the stage2.bad
        directory, and compare stage3 to stage2.bad, not stage2.ok.
    -d, --dependency-only
        Check only that the dependencies can be made in stage3.
    -G <grade>, --grade <grade>
        Specify the grade to test.
    -h, --help
        Display this usage message.
    -j <num-jobs>, --jobs <num-jobs>
        Run using <num-jobs> different parallel processes.
    -l, --library-only
        Check the successful creation of the stage3 .c files in the
        library, but do not compile the compiler directory.
    -m <mmake-args>, --mmake-args <mmake-args>
        Pass <mmake-args> as options to \`mmake'.
    -o <filename>, --output-file <filename>
        Output results to <filename>.
    -s <command>, --single-command <command>
        Execute the given command using the constructed compiler.
    -t <testdir>, --test-dir <testdir>
        Execute runtests from the named subdirectory of tests.
"

# If you change this, you will also need to change the files indicated
# in scripts/c2init.in.
STD_LIB_NAME=mer_std
MDBCOMP_LIB_NAME=mer_mdbcomp
BROWSER_LIB_NAME=mer_browser

set -x

alltestdirs="benchmarks general hard_coded invalid valid warnings"

bootcheck="true"
compile_only="false"
dependency_only="false"
grade=""
library_only="false"
jfactor=""
mmake_opts=""
outfile="DIFF.BINARY"
single_command=""
testdirs=""
basis="ok"

while [ $# -gt 0 ]; do
    case "$1" in

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

    -c|--compile-only)
        compile_only="true" ;;

    -C|--compare-to-bad)
        basis="bad" ;;

    -d|--dependency-only)
        dependency_only="true" ;;

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

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

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

    -l|--library-only)
        library_only="true" ;;

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

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

    -s|--single-command)
        single_command="$2"; shift ;;
    -s*)
        single_command="` expr $1 : '-s\(.*\)' `" ;;
    --single-command*)
        single_command="` expr $1 : '--single-command\(.*\)' `" ;;

    -t|--test-dir)
        testdir="$2"; shift
        if test -d tests/$testdir
        then
            testdirs="$testdirs $testdir"
        else
            if test "$testdir" = "all"
            then
                testdirs="$alltestdirs"
            else
                echo "tests has no subdirectory named $testdir"
            fi
        fi ;;
    -t*)
        testdir="` expr $1 : '-t\(.*\)' `"
        if test -d tests/$testdir
        then
            testdirs="$testdirs $testdir"
        else
            if test "$testdir" = "all"
            then
                testdirs="$alltestdirs"
            else
                echo "tests has no subdirectory named $testdir"
            fi
        fi ;;

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

    *)
        echo "$usage" 1>&2
        exit 1 ;;
    esac
    shift
done

if test "${grade}" != ""
then
    grade_mmake_opts="GRADE=${grade}"
    mmake_opts="${grade_mmake_opts} ${mmake_opts}"
fi

root=`/bin/pwd`

MERCURY_COMPILER=$root/compiler/mercury_compile
export MERCURY_COMPILER

MERCURY_CONFIG_FILE=$root/scripts/Mercury.config
export MERCURY_CONFIG_FILE

MMAKE_VPATH=.
export MMAKE_VPATH
MMAKE_DIR=../scripts
export MMAKE_DIR

# Ensure that mmake will not disturb the .o and .c files in stage2
# that were placed there by the binary script.

set +x

touch stage2/library/*.c
touch stage2/mdbcomp/*.c
touch stage2/browser/*.c
touch stage2/compiler/*.c

sleep 2

touch stage2/library/*.int0
touch stage2/mdbcomp/*.int0
touch stage2/browser/*.int0
touch stage2/compiler/*.int0

sleep 2

touch stage2/library/*.date0
touch stage2/mdbcomp/*.date0
touch stage2/browser/*.date0
touch stage2/compiler/*.date0

sleep 2

touch stage2/library/*.int3
touch stage2/mdbcomp/*.int3
touch stage2/browser/*.int3
touch stage2/compiler/*.int3

sleep 2

touch stage2/library/*.date3
touch stage2/mdbcomp/*.date3
touch stage2/browser/*.date3
touch stage2/compiler/*.date3

touch stage2/library/*.int2
touch stage2/library/*.int
touch stage2/mdbcomp/*.int2
touch stage2/mdbcomp/*.int
touch stage2/browser/*.int2
touch stage2/browser/*.int
touch stage2/compiler/*.int2
touch stage2/compiler/*.int

sleep 2

touch stage2/library/*.date
touch stage2/mdbcomp/*.date
touch stage2/browser/*.date
touch stage2/compiler/*.date

touch stage2/library/*.opt

sleep 2

touch stage2/library/*.optdate
touch stage2/library/*.trans_opt

sleep 2

touch stage2/library/*.trans_opt_date
touch stage2/library/*.o
touch stage2/library/*.pic_o
touch stage2/mdbcomp/*.o
touch stage2/mdbcomp/*.pic_o
touch stage2/browser/*.o
touch stage2/browser/*.pic_o
touch stage2/compiler/*.o

# Rebuild the stage2 library, mdbcomp, browser and compiler
# from the C and object files already there.

set -x

/bin/rm -f stage2/library/lib${STD_LIB_NAME}.{a,so,dylib}
/bin/rm -f stage2/mdbcomp/lib${MDBCOMP_LIB_NAME}.{a,so,dylib}
/bin/rm -f stage2/browser/lib${BROWSER_LIB_NAME}.{a,so,dylib}
/bin/rm -f stage2/compiler/mercury_compile

if (cd stage2/library ; mmake $mmake_opts $jfactor)
then
    echo "building of stage 2 library successful"
else
    echo "building of stage 2 library not successful"
    touch .stage2_problem
    exit 1
fi

if (cd stage2/mdbcomp ; mmake $mmake_opts $jfactor library)
then
    echo "building of stage 2 mdbcomp successful"
else
    echo "building of stage 2 mdbcomp not successful"
    touch .stage2_problem
    exit 1
fi

if (cd stage2/browser ; mmake $mmake_opts $jfactor library)
then
    echo "building of stage 2 browser successful"
else
    echo "building of stage 2 browser not successful"
    touch .stage2_problem
    exit 1
fi

if (cd stage2/compiler ; mmake $mmake_opts $jfactor mercury_compile)
then
    echo "building of stage 2 compiler successful"
else
    echo "building of stage 2 compiler not successful"
    touch .stage2_problem
    exit 1
fi

unset MMAKE_VPATH
unset MMAKE_DIR

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

WORKSPACE=${root}/stage2
export WORKSPACE

MMAKE_DIR=${root}/stage2/scripts
export MMAKE_DIR

PATH=${root}/stage2/util:${root}stage2/scripts:$PATH
export PATH

ulimit -t 200

if test "$single_command" != ""
then
    echo "executing $single_command"
    arg $single_command
    if $single_command
    then
        echo "command successful"
    else
        echo "command not successful"
        exit 1
    fi
fi

if "$bootcheck"
then

    # Rebuild the stage3 library, mdbcomp, browser and compiler from scratch.

    for dir in library mdbcomp browser compiler
    do
        /bin/rm -f stage3/$dir/*.c
        /bin/rm -f stage3/$dir/*.c_date
        /bin/rm -f stage3/$dir/*.d
        /bin/rm -f stage3/$dir/*.optdate
        /bin/rm -f stage3/$dir/*.trans_opt_date
        /bin/rm -f stage3/$dir/*.date3
        /bin/rm -f stage3/$dir/*.date
        /bin/rm -f stage3/$dir/*.opt
        /bin/rm -f stage3/$dir/*.trans_opt
        /bin/rm -f stage3/$dir/*.int3
        /bin/rm -f stage3/$dir/*.int2
        /bin/rm -f stage3/$dir/*.int0
        /bin/rm -f stage3/$dir/*.int
    done

    if (cd stage3 ; mmake $mmake_opts \
        depend_library depend_mdbcomp depend_browser depend_compiler)
    then
        echo "building of stage 3 dependencies successful"
        if $dependency_only
        then
            exit 0
        fi
    else
        echo "building of stage 3 dependencies not successful"
        exit 1
    fi

    # MMAKE_VPATH=.
    # export MMAKE_VPATH
    MMAKE_DIR=../scripts
    export MMAKE_DIR

    if (cd stage3/library ; mmake -S $mmake_opts $jfactor int3s ints ; \
        mmake -S $mmake_opts $jfactor cs)
    then
        echo "building of stage 3 library successful"
        if $library_only
        then
            exit 0
        fi
    else
        echo "building of stage 3 library not successful"
        exit 1
    fi

    if (cd stage3/mdbcomp ; mmake -S $mmake_opts $jfactor int3s ints ; \
        mmake -S $mmake_opts $jfactor cs)
    then
        echo "building of stage 3 mdbcomp successful"
    else
        echo "building of stage 3 mdbcomp not successful"
        exit 1
    fi

    if (cd stage3/browser ; mmake -S $mmake_opts $jfactor int3s ints ; \
        mmake -S $mmake_opts $jfactor cs)
    then
        echo "building of stage 3 browser successful"
    else
        echo "building of stage 3 browser not successful"
        exit 1
    fi

    if (cd stage3/compiler ; mmake -S $mmake_opts $jfactor int3s ints ; \
        mmake -S $mmake_opts $jfactor cs)
    then
        echo "building of stage 3 compiler successful"
    else
        echo "building of stage 3 compiler not successful"
        exit 1
    fi

    if test "$compile_only" = false
    then
        founddiff=false
        cat /dev/null > $outfile
        for dir in library mdbcomp browser compiler
        do
            # `mmake cs' in the compiler directory doesn't build
            # `mercury_compile_init.c', so we only compare the `.c'
            # files present in the stage3 directory.
            for stage3file in stage3/$dir/*.c
            do
                stage2file="stage2.$basis/$dir/`basename $stage3file`"
                diff -u $stage2file $stage3file >> $outfile || founddiff=true
            done
        done

        if "$founddiff" = true
        then
            echo "error - stage2.$basis and stage3 differ!"
            exit 1
        else
            echo "stage2.$basis and stage3 compare ok"
        fi
    fi
fi

for testdir in $testdirs
do
    if (cd tests/$testdir; mmake $grade_mmake_opts runtests)
    then
        echo "tests in the $testdir directory successful"
    else
        echo "tests in the $testdir directory not successful"
        exit 1
    fi
done

exit 0
