#!/bin/sh

#~ Copyright 2002-2019 Rene Rivera.
#~ Distributed under the Boost Software License, Version 1.0.
#~ (See accompanying file LICENSE_1_0.txt or copy at
#~ http://www.boost.org/LICENSE_1_0.txt)

# Reset the toolset.
B2_TOOLSET=
B2_OS=

# Run a command, and echo before doing so. Also checks the exit status and quits
# if there was an error.
echo_run ()
{
    echo "$@"
    $@
    r=$?
    if test $r -ne 0 ; then
        exit $r
    fi
}

# Print an error message, and exit with a status of 1.
error_exit ()
{
    echo "
${@}

You can specify the toolset as the argument, i.e.:
    ./build.sh gcc

Toolsets supported by this script are:
    acc, clang, como, gcc, intel-darwin, intel-linux, kcc, kylix, mipspro,
    pathscale, pgi, qcc, sun, sunpro, tru64cxx, vacpp

For any toolset you can override the path to the compiler with the CXX
environment variable. You can also use additional flags for the compiler
with the CXXFLAGS environment variable.

A special toolset; cxx, is available which is used as a fallback when a more
specific toolset is not found and the cxx command is detected. The 'cxx'
toolset will use the CXX, CXXFLAGS, and LIBS environment variables, if present.

Similarly, the cross-cxx toolset is available for cross-compiling by using the
BUILD_CXX, BUILD_CXXFLAGS, and BUILD_LDFLAGS environment variables to compile
binaries that will be executed on the build system. This allows CXX etc. to be
set for cross-compilers to be propagated to subprocesses.
"
    exit 1
}

# Check that a command is in the PATH.
test_path ()
{
    if `command -v command 1>/dev/null 2>/dev/null`; then
        command -v $1 1>/dev/null 2>/dev/null
    else
        hash $1 1>/dev/null 2>/dev/null
    fi
}

# Check that the OS name, as returned by "uname", is as given.
test_uname ()
{
    if test_path uname; then
        test `uname` = $*
    fi
}

# Try and guess the toolset to bootstrap the build with...
guess_toolset ()
{
    if test_uname Darwin ; then B2_TOOLSET=clang
    elif test_uname IRIX ; then B2_TOOLSET=mipspro
    elif test_uname IRIX64 ; then B2_TOOLSET=mipspro
    elif test_uname OSF1 ; then B2_TOOLSET=tru64cxx
    elif test_uname QNX && test_path QCC ; then B2_TOOLSET=qcc
    elif test_uname Linux && test_path xlC_r; then
       if /usr/bin/lscpu | grep Byte | grep Little > /dev/null 2>&1 ; then
          # Little endian linux
          B2_TOOLSET=xlcpp
       else
          #Big endian linux
          B2_TOOLSET=vacpp
       fi
    elif test_uname AIX && test_path xlC_r; then B2_TOOLSET=vacpp
    elif test_uname FreeBSD && test_path freebsd-version && test_path clang++; then B2_TOOLSET=clang
    elif test_path g++ ; then B2_TOOLSET=gcc
    elif test_path clang++ ; then B2_TOOLSET=clang
    elif test_path icc ; then B2_TOOLSET=intel-linux
    elif test -r /opt/intel/cc/9.0/bin/iccvars.sh ; then
        B2_TOOLSET=intel-linux
        B2_TOOLSET_ROOT=/opt/intel/cc/9.0
    elif test -r /opt/intel_cc_80/bin/iccvars.sh ; then
        B2_TOOLSET=intel-linux
        B2_TOOLSET_ROOT=/opt/intel_cc_80
    elif test -r /opt/intel/compiler70/ia32/bin/iccvars.sh ; then
        B2_TOOLSET=intel-linux
        B2_TOOLSET_ROOT=/opt/intel/compiler70/ia32/
    elif test -r /opt/intel/compiler60/ia32/bin/iccvars.sh ; then
        B2_TOOLSET=intel-linux
        B2_TOOLSET_ROOT=/opt/intel/compiler60/ia32/
    elif test -r /opt/intel/compiler50/ia32/bin/iccvars.sh ; then
        B2_TOOLSET=intel-linux
        B2_TOOLSET_ROOT=/opt/intel/compiler50/ia32/
    elif test_path pgc++ ; then B2_TOOLSET=pgi
    elif test_path pathCC ; then B2_TOOLSET=pathscale
    elif test_path como ; then B2_TOOLSET=como
    elif test_path KCC ; then B2_TOOLSET=kcc
    elif test_path bc++ ; then B2_TOOLSET=kylix
    elif test_path aCC ; then B2_TOOLSET=acc
    elif test_uname HP-UX ; then B2_TOOLSET=acc
    elif test -r /opt/SUNWspro/bin/cc ; then
        B2_TOOLSET=sunpro
        B2_TOOLSET_ROOT=/opt/SUNWspro/
    # Test for some common compile command as the default fallback.
    elif test_path $CXX ; then B2_TOOLSET=cxx
    elif test_path cxx ; then
        B2_TOOLSET=cxx
        CXX=cxx
    elif test_path cpp ; then
        B2_TOOLSET=cxx
        CXX=cpp
    elif test_path CC ; then
        B2_TOOLSET=cxx
        CXX=CC
    fi
    if test "$B2_TOOLSET" = "" ; then
        error_exit "Could not find a suitable toolset."
    fi
}

check_debug_build ()
{
    while test $# -gt 0
    do
        case "$1" in
            --debug) return 0 ;;
        esac
        shift
    done
    return 1
}

# The one option we support in the invocation
# is the name of the toolset to force building
# with.
case "$1" in
    --guess-toolset) guess_toolset ; echo "$B2_TOOLSET" ; exit 1 ;;
    -*) guess_toolset ;;
    ?*) B2_TOOLSET=$1 ; shift ;;
    *) guess_toolset ;;
esac
case $B2_TOOLSET in

    gcc)
        CXX=${CXX:=g++}
        # Check whether it's MinGW GCC, which has Windows headers and none of POSIX ones.
        machine=$(${CXX} -dumpmachine 2>/dev/null)
        if [ $? -ne 0 ]; then
            echo "B2_TOOLSET is gcc, but the 'gcc' command cannot be executed."
            echo "Make sure 'gcc' is in PATH, or use a different toolset."
            exit 1
        fi
        case $machine in
        *mingw*)
        # MinGW insists that its bin directory be in PATH.
        if test -r ${B2_TOOLSET_ROOT}bin/gcc ; then
            export PATH=${B2_TOOLSET_ROOT}bin:$PATH
        fi
        B2_CXX="${CXX} -x c++ -DNT"
        B2_CXXFLAGS_RELEASE="-O2 -s"
        B2_CXXFLAGS_DEBUG="-O0 -g"
        B2_OS="NT"
        ;;

        *)
        B2_CXX="${CXX} -x c++ -std=c++11"
        B2_CXXFLAGS_RELEASE="-O2 -s"
        B2_CXXFLAGS_DEBUG="-O0 -g"
        esac
    ;;

    intel-darwin)
    CXX=${CXX:=icc}
    echo_run ${CXX} --version
    B2_CXX="${CXX} -xc++"
    B2_CXXFLAGS_RELEASE="-O3 -s"
    B2_CXXFLAGS_DEBUG="-O0 -g -p"
    ;;

    intel-linux)
    CXX=${CXX:=icc}
    test_path ${CXX} >/dev/null 2>&1
    if test $? ; then
        echo "Found ${CXX} in environment"
        B2_TOOLSET_ROOT=`echo ${CXX}| sed -e 's/bin.*\/icc//'`
        # probably the most widespread
        ARCH=intel64
    else
        echo "No intel compiler in current path"
        echo "Look in a few old place for legacy reason"
        if test -r /opt/intel/cc/9.0/bin/iccvars.sh ; then
            B2_TOOLSET_ROOT=/opt/intel/cc/9.0/
        elif test -r /opt/intel_cc_80/bin/iccvars.sh ; then
            B2_TOOLSET_ROOT=/opt/intel_cc_80/
        elif test -r /opt/intel/compiler70/ia32/bin/iccvars.sh ; then
            B2_TOOLSET_ROOT=/opt/intel/compiler70/ia32/
        elif test -r /opt/intel/compiler60/ia32/bin/iccvars.sh ; then
            B2_TOOLSET_ROOT=/opt/intel/compiler60/ia32/
        elif test -r /opt/intel/compiler50/ia32/bin/iccvars.sh ; then
            B2_TOOLSET_ROOT=/opt/intel/compiler50/ia32/
        fi
    fi
    if test -r ${B2_TOOLSET_ROOT}bin/iccvars.sh ; then
        # iccvars does not change LD_RUN_PATH. We adjust LD_RUN_PATH here in
        # order not to have to rely on ld.so.conf knowing the icc library
        # directory. We do this before running iccvars.sh in order to allow a
        # user to add modifications to LD_RUN_PATH in iccvars.sh.
        if test -z "${LD_RUN_PATH}"; then
            LD_RUN_PATH="${B2_TOOLSET_ROOT}lib"
        else
            LD_RUN_PATH="${B2_TOOLSET_ROOT}lib:${LD_RUN_PATH}"
        fi
        export LD_RUN_PATH
        . ${B2_TOOLSET_ROOT}bin/iccvars.sh $ARCH
    fi
    B2_CXX="${CXX} -xc++"
    B2_CXXFLAGS_RELEASE="-O3 -s"
    B2_CXXFLAGS_DEBUG="-O0 -g -p"
    ;;

    vacpp)
    CXX=${CXX:=xlC_r}
    B2_CXX="${CXX}"
    B2_CXXFLAGS_RELEASE="-O3 -s -qstrict -qinline"
    B2_CXXFLAGS_DEBUG="-g -qNOOPTimize -qnoinline -pg"
    ;;

    xlcpp)
    CXX=${CXX:=xlC_r}
    B2_CXX="${CXX}"
    B2_CXXFLAGS_RELEASE="-s -O3 -qstrict -qinline"
    B2_CXXFLAGS_DEBUG="-g -qNOOPTimize -qnoinline -pg"
    ;;

    como)
    CXX=${CXX:=como}
    B2_CXX="${CXX}"
    B2_CXXFLAGS_RELEASE="-O3 --inlining"
    B2_CXXFLAGS_DEBUG="-O0 -g --no_inlining --long_long"
    ;;

    kcc)
    B2_CXX="KCC"
    B2_CXXFLAGS_RELEASE="+K2 -s"
    B2_CXXFLAGS_DEBUG="+K0 -g"
    ;;

    kylix)
    B2_CXX="bc++ -tC -q"
    B2_CXXFLAGS_RELEASE="-O2 -vi -w-inl -s"
    B2_CXXFLAGS_DEBUG="-Od -v -vi-"
    ;;

    mipspro)
    CXX=${CXX:=CC}
    B2_CXX="${CXX} -FE:template_in_elf_section -ptused"
    B2_CXXFLAGS_RELEASE="-Ofast -g0 \"-INLINE:none\" -s"
    B2_CXXFLAGS_DEBUG="-O0 -INLINE -g"
    ;;

    pathscale)
    CXX=${CXX:=pathCC}
    B2_CXX="${CXX}"
    B2_CXXFLAGS_RELEASE="-O3 -inline -s"
    B2_CXXFLAGS_DEBUG="-O0 -noinline -ggdb"
    ;;

    pgi)
    CXX=${CXX:=pgc++}
    B2_CXX="${CXX} -std=c++11"
    B2_CXXFLAGS_RELEASE="-fast -s"
    B2_CXXFLAGS_DEBUG="-O0 -gopt"
    ;;

    sun*)
    CXX=${CXX:=CC}
    if test -z "${B2_TOOLSET_ROOT}" -a -r /opt/SUNWspro/bin/CC ; then
        B2_TOOLSET_ROOT=/opt/SUNWspro/
    fi
    if test -r "${B2_TOOLSET_ROOT}/bin/CC" ; then
        PATH=${B2_TOOLSET_ROOT}bin:${PATH}
        export PATH
    fi
    B2_CXX="${CXX}"
    B2_CXXFLAGS_RELEASE="-xO4 -s"
    B2_CXXFLAGS_DEBUG="-g"
    ;;

    clang*)
    CXX=${CXX:=clang++}
    B2_CXX="${CXX} -x c++ -O3 -std=c++11"
    B2_TOOLSET=clang
    B2_CXXFLAGS_RELEASE="-O3 -s"
    B2_CXXFLAGS_DEBUG="-O0 -fno-inline -g"
    ;;

    tru64cxx)
    B2_CXX="cc"
    B2_CXXFLAGS_RELEASE="-O5 -inline speed -s"
    B2_CXXFLAGS_DEBUG="-O0 -pg -g"
    ;;

    acc)
    CXX=${CXX:=aCC}
    B2_CXX="${CXX} -AA"
    B2_CXXFLAGS_RELEASE="-O3 -s"
    B2_CXXFLAGS_DEBUG="+d -g"
    ;;

    qcc)
    CXX=${CXX:=QCC}
    B2_CXX="${CXX}"
    B2_CXXFLAGS_RELEASE="-O3 -Wc,-finline-functions"
    B2_CXXFLAGS_DEBUG="O0 -Wc,-fno-inline -gstabs+"
    ;;

    cxx)
    CXX=${CXX:=cxx}
    B2_CXX="${CXX}"
    ;;

    cross-cxx)
    CXX=${BUILD_CXX:=cxx}
    CXXFLAGS=${BUILD_CXXFLAGS}
    B2_CXX="${CXX}"
    ;;

    *)
    error_exit "Unknown toolset: $B2_TOOLSET"
    ;;
esac

echo "###"
echo "### Using '$B2_TOOLSET' toolset."
echo "###"
B2_SOURCES="\
 builtins.c \
 class.c \
 command.c \
 compile.c \
 constants.c \
 cwd.c \
 debug.c \
 debugger.c \
 execcmd.c \
 filesys.c \
 frames.c \
 function.c \
 glob.c\
 hash.c \
 hcache.c \
 hdrmacro.c \
 headers.c \
 jam.c \
 jambase.c \
 jamgram.c \
 lists.c \
 make.c \
 make1.c \
 md5.c \
 mem.c \
 modules.c \
 native.c \
 object.c \
 option.c \
 output.c \
 parse.c \
 pathsys.c \
 regexp.c \
 rules.c \
 scan.c \
 search.c \
 strings.c \
 subst.c \
 timestamp.c \
 variable.c \
 w32_getreg.c \
 modules/order.c \
 modules/path.c \
 modules/property-set.c \
 modules/regex.c \
 modules/sequence.c \
 modules/set.c \
 "
case $B2_OS in
    NT)
    B2_SOURCES="${B2_SOURCES} execnt.c filent.c pathnt.c"
    ;;

    *)
    B2_SOURCES="${B2_SOURCES} execunix.c fileunix.c pathunix.c"
    ;;
esac

B2_CXXFLAGS="\
 -DNDEBUG \
 -DYYSTACKSIZE=5000 \
 -DYYINITDEPTH=5000 \
 -o b2"
if check_debug_build "$@" ; then B2_CXXFLAGS="${B2_CXXFLAGS_DEBUG} ${B2_CXXFLAGS}"
else B2_CXXFLAGS="${B2_CXXFLAGS_RELEASE} ${B2_CXXFLAGS}"
fi
B2_CXXFLAGS="${CXXFLAGS} ${B2_CXXFLAGS}"
echo_run ${B2_CXX} ${B2_CXXFLAGS} ${B2_SOURCES}
echo_run cp b2 bjam
