#!/usr/bin/env bash

if [ -z "$SAGE_LOCAL" ]; then
    echo >&2 "Error: SAGE_LOCAL undefined - exiting..."
    echo >&2 "Maybe run 'sage -sh'?"
    exit 1
fi

CUR=`pwd`

cd src/

###############################################################################
# Apply patches (if any):
###############################################################################

# Before applying patches, we manually move two wrongly named files,
# rather than doing this with diff/patch which lacks the ability of properly
# detecting filename changes. See Trac #13137.
# This fix can (and will have to) be removed once integrated upstream.
echo "Renaming *,asm files to *.asm..."
mv mpn/x86/p6/addmul_1,asm mpn/x86/p6/addmul_1.asm &&
mv mpn/x86/p6/submul_1,asm mpn/x86/p6/submul_1.asm
if [ $? -ne 0 ]; then
    echo >&2 "Error: moving *,asm files failed."
    exit 1
fi

echo "Applying patches to upstream sources..."
for patch in ../patches/*.patch; do
    patch -p1 <"$patch"
    if [ $? -ne 0 ]; then
        echo >&2 "Error: '$patch' failed to apply."
        exit 1
    fi
done

###############################################################################
# Previous MPIR installations are only removed after a *successful* (re)build,
# before installing the new one. (Done below.)
###############################################################################

###############################################################################
# Set up environment variables:
###############################################################################

# The Yasm build uses PYTHON from the environment to find the Python interpreter,
# so unset it in case it apparently contains nothing useful (like it did in Sage
# versions prior to 5.0.beta10; cf. #10492), to not break Yasm's 'configure':
if [ -n "$PYTHON" ]; then
    if ! $PYTHON --version &>/dev/null; then
        echo >&2 "Warning: Unsetting PYTHON (=\"$PYTHON\"), since it doesn't seem"
        echo >&2 "         to contain the name of / path to a Python interpreter."
        unset PYTHON
    fi
fi

user_cflags=$CFLAGS # Save them. 'sage-env' sets CC, but not CFLAGS.
required_cflags=""  # Additional mandatory settings required by Sage, accumulated below.
user_ldflags=$LDFLAGS # Save them.
required_ldflags=""   # Additional mandatory settings required by Sage, accumulated below.
user_abi=$ABI # Just save it.
# In case we changed CPPFLAGS or CXXFLAGS, too, we should save the user's here as well.
# We don't have to add (e.g.) '-m64' to CFLAGS/CPPFLAGS/CXXFLAGS/LDFLAGS, since
# MPIR's 'configure' is smart enough to add it if necessary or appropriate.


if [ -z "$CFLAG32" ]; then
    CFLAG32="-m32" # Only used in this script, no need to export it.
fi
if [ -z "$CFLAG64" ]; then
    CFLAG64="-m64" # Only used in this script, no need to export it.
fi


if [ "$SAGE_DEBUG" = yes ]; then
    # Disable optimization, add debug symbols:
    required_cflags="$required_cflags -g -O0"
    echo >&2 "Warning: Building MPIR with SAGE_DEBUG=yes disables optimization."
else
    # Add debug symbols by default
    required_cflags="$required_cflags -g"
fi


case "$UNAME" in
    SunOS)
        if [ "$SAGE64" = yes ]; then
            echo "Building a 64-bit version of MPIR."
            ABI=64
        else
            echo "Building a 32-bit version of MPIR."
            ABI=32
        fi;;
    Darwin)
        # In some cases (see SAGE_ROOT/spkg/bin/sage-env), on Darwin,
        # CC might be set to clang, but MPIR doesn't seem to build
        # with clang.
        CLANG=`command -v clang`
        GCC=`command -v gcc`
        if [ -n "$CC" ] && [ "$CC" = "$CLANG" ] && [ -n "$GCC" ] ; then
            export CC="$GCC"
        fi
        if [ "$SAGE64" = yes ]; then
            # Note that we do not support 64-bit builds on MacOS X PPC at all,
            # so we don't special-case on the architecture here.
            echo "Building a 64-bit version of MPIR."
            ABI=64
        else
            # Do not set ABI=32 on MacOS X 10.6 (Darwin 10) and later, since
            # there everything defaults to 64-bit:
            if [ "`uname -r | sed 's/\..*//'`" -lt 10 ]; then
                # Assume MacOS X 10.4 or 10.5 (Darwin 8 or 9); also, PPC CPUs
                # are only supported by these, not later versions.
                echo "Building a 32-bit version of MPIR, which is the only supported option."
                ABI=32
                case "`uname -m`" in
                    ppc|ppc64|[Pp]ower*) # Apple's 'uname' returns strange strings
                        # The Darwin assembler rejects code using an
                        # extended instruction set by default (cf. #8664):
                        required_cflags="$required_cflags -Wa,-force_cpusubtype_ALL"
                        ;;
                esac
            else
                # Darwin 10 (MacOS X 10.6) or later, SAGE64 not "yes"
                # We don't have to set ABI here.
                echo "Building a 64-bit version of MPIR, which is the default."
            fi
        fi
        ;; # Darwin
    Linux)
        # MPIR fails to build on 32-bit operating systems running on
        # 64-bit CPUs if CFLAGS happen to contain '-m32' and ABI is
        # *not* set, so we set it here if necessary:
        # (Cf. http://groups.google.com/group/mpir-devel/browse_thread/thread/46ccdc5dfc3485cd#)
        # Note: This code snippet could in principle be moved out of the
        #       Linux branch, but since we already set ABI for other
        #       OSs above (and print an according message), it's here.
        if [ -z "$ABI" ]; then
            echo "int main(){return 0;}" > foo.c
            # Try building and running a 64-bit executable:
            # (Building usually succeeds even on 32-bit systems, unless e.g. a 32-bit
            # CPU is explicitly selected by CFLAGS, while running does not.)
            if $CC $CFLAGS $CFLAG64 -o foo foo.c 2>/dev/null && ./foo 2>/dev/null; then
                # We can run 64-bit executables.
                # Setting ABI=64 shouldn't be necessary, but shouldn't hurt either.
                echo "Building a 64-bit version of MPIR."
                case "`uname -m`" in
                    ppc64) ABI=mode64;;
                    *)     ABI=64
                esac
            elif $CC $CFLAGS $CFLAG32 -o foo foo.c 2>/dev/null && ./foo 2>/dev/null; then
                # We're on a 32-bit OS which cannot run 64-bit executables.
                echo "Building a 32-bit version of MPIR."
                ABI=32
            else
                # It seems the compiler does not support -m32 nor -m64 (e.g.
                # GCC on Itanium rejects both); do not set ABI at all.
                echo "Your compiler does not support '$CFLAG32' nor '$CFLAG64'.  Leaving ABI unset."
            fi
            rm -f foo foo.c
        fi
        ;; # Linux
    CYGWIN)
        # For the moment, Cygwin is only 32-bits
        # and configure gets lost if the hardware is 64 bits
        ABI=32
        ;;
    *) # e.g. AIX or HP-UX
        echo >&2 "Warning: Your platform ($UNAME) isn't yet explicitly supported" \
            "by this MPIR spkg, i.e., by Sage's part of it."
esac

# Work around a bug in GCC 4.7.0 which breaks the build on Itanium CPUs.
# See #12765, #12751, and http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48496
if [ "`uname -m`" = ia64 ] && [ "`testcc.sh $CC`" = GCC ] ; then
    gcc_version=`$CC -dumpversion`
    case "$gcc_version" in
      4.7.0)
        required_cflags="$required_cflags -O0 -finline-functions -fschedule-insns"
        echo >&2 "Warning: Disabling almost all optimization due to a bug in GCC 4.7.0"
        echo >&2 "         on Itanium, which otherwise would break the build."
        echo >&2 "         See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48496"
        echo >&2 "         for current status and further details."
        ;;
    esac
fi

export ABI CFLAGS CXXFLAGS LDFLAGS # Partially redundant, but safe(r).
# We don't export CPPFLAGS here, since we don't (have to) modify them.

###############################################################################
# Now configure MPIR, eventually modifying CFLAGS [further]:
###############################################################################

MPIR_CONFIGURE="--enable-gmpcompat --enable-shared $MPIR_CONFIGURE"

# If we're bootstrapping GCC from the GCC spkg, don't build the C++
# interface (cf. #12782), static libraries and disable fat binary.
# After GCC is built, we will build MPIR again.
if [ "$SAGE_BUILD_TOOLCHAIN" = yes ]; then
    echo "Building a reduced version of MPIR to bootstrap GCC."
    echo "MPIR will later get rebuilt (with the C++ interface and static libraries"
    echo "enabled) using the new compiler."
    MPIR_CONFIGURE="$MPIR_CONFIGURE --disable-cxx --disable-static"
    SAGE_FAT_BINARY=no
else
    # Also build the static library to be used by e.g. ECM
    # unless we are on Cygwin where we can only build a shared
    # or a static library but not both:
    if [ "$UNAME" = "CYGWIN" ]; then
        echo "Building MPIR with the C++ interface and (only) shared libraries."
        MPIR_CONFIGURE="--enable-cxx $MPIR_CONFIGURE --disable-static"
    else
        echo "Building MPIR with the C++ interface and (also) static libraries."
        MPIR_CONFIGURE="--enable-cxx --enable-static $MPIR_CONFIGURE"
    fi
fi
# (Further options to 'configure' are added below.)

# If SAGE_FAT_BINARY is enabled, then add --enable-fat to configure
# options on Linux x86 systems.  On other systems, fat binaries are not
# supported.  Then we specify a build architecture which doesn't
# have a CPU name in it.  This means which use the vanilla config.guess
# (renamed to configfsf.guess in MPIR) file instead of MPIR's version.
if [ "$SAGE_FAT_BINARY" = "yes" ]; then
    case "$UNAME-`uname -m`" in
        Linux-i[3456]86)
            echo "** Building with \"fat binary\" support for 32-bit CPUs **"
            MPIR_CONFIGURE="--enable-fat $MPIR_CONFIGURE"
            ;;
        Linux-x86_64|Linux-amd64)
            echo "** Building with \"fat binary\" support for 64-bit CPUs **"
            MPIR_CONFIGURE="--enable-fat $MPIR_CONFIGURE"
            ;;
        *) # Anything else
            echo "** Building a generic binary (not assuming any specific CPU) **"
            MPIR_CONFIGURE="--build=`./configfsf.guess` $MPIR_CONFIGURE"
            ;;
    esac
fi


# Pre-configure MPIR to get the settings it would use if CFLAGS were empty:
echo "Checking what CFLAGS MPIR would use if they were empty..."
(unset CFLAGS CPPFLAGS CXXFLAGS && ./configure $MPIR_CONFIGURE) &>configure-empty.log
if [ $? -ne 0 ]; then
    # Output the log of the failed configure run
    cat configure-empty.log
    echo >&2 "Error configuring MPIR (with CFLAGS unset)."
    echo >&2 "Consult `pwd`/config.log for for details."
    exit 1
fi


# Read MPIR-selected flags from Makefile
mpir_cc=`sed -n 's/^CC *= *//p' Makefile`
mpir_cflags=`sed -n 's/^CFLAGS *= *//p' Makefile`
if [ -z "$mpir_cc" ]; then
    echo >&2 "Error: failed to determine \$CC from Makefile"
    echo >&2 "Please report this to <sage-devel@googlegroups.com>"
    exit 1
fi
echo "Settings chosen by MPIR when configuring with CFLAGS unset:"
echo "  CC:      $mpir_cc"
echo "  CFLAGS:  $mpir_cflags"
echo "Settings added by Sage to build MPIR, taking into account SAGE_DEBUG etc.:"
echo "  CFLAGS:  $required_cflags"  # Might be empty.
echo "  LDFLAGS: $required_ldflags" # Might be empty.
echo "  ABI:     $ABI" # Might be empty, or the one specified by the user.
echo "Settings from the \"global\" environment:"
echo "  CC:      $CC" # Set by Sage, maybe overridden by the user.
echo "  CFLAGS:  $user_cflags"
echo "  LDFLAGS: $user_ldflags"
echo "  ABI:     $user_abi"
echo "  (CPP, CPPFLAGS, CXX and CXXFLAGS are listed below; these don't get modified.)"

# Finally: use MPIR's flags, plus those required by Sage for the
# package to build properly, plus those specified by the user.
CFLAGS="$mpir_cflags $required_cflags $user_cflags"
LDFLAGS="$required_ldflags $user_ldflags"

echo "Finally using the following settings:"
echo "  CC=$CC"
echo "  CFLAGS=$CFLAGS"
echo "  CPP=$CPP"
echo "  CPPFLAGS=$CPPFLAGS"
echo "  CXX=$CXX"
echo "  CXXFLAGS=$CXXFLAGS"
echo "  LDFLAGS=$LDFLAGS"
echo "  ABI=$ABI"
echo "(These settings may still get overridden by 'configure' or Makefiles.)"

###############################################################################
# Now really configure MPIR with proper settings:
###############################################################################

# We also add '--libdir="$SAGE_LOCAL/lib"' below, since newer autotools may
# otherwise put the libraries into .../lib64 on 64-bit systems (cf. #12131).

echo "Configuring MPIR with the following options:"
echo "    --prefix=\"$SAGE_LOCAL\" --libdir=\"$SAGE_LOCAL/lib\" $MPIR_CONFIGURE"
echo "You can set MPIR_CONFIGURE to pass additional parameters."

# Clear the cache of the previous configure run
find . -name config.cache -exec rm -f {} \;

./configure --prefix="$SAGE_LOCAL" --libdir="$SAGE_LOCAL/lib" $MPIR_CONFIGURE
if [ $? -ne 0 ]; then
    echo >&2 "Error configuring MPIR. (See above for the options passed to it.)"
    exit 1
fi

###############################################################################
# Now build MPIR:
###############################################################################

echo "Now building MPIR..."
$MAKE
if [ $? -ne 0 ]; then
    echo >&2 "Error building MPIR."
    exit 1
fi

echo "Build succeeded."

###############################################################################
# Remove previous installation (if any), *after* a successful build:
###############################################################################

echo "Removing old GMP/MPIR headers..."
rm -f "$SAGE_LOCAL"/include/{gmp,mpir}*.h

# Do NOT delete old GMP/MPIR shared libraries as Sage's versions of libraries
# used by GCC might still refer to them, such that their deletion would break
# GCC inside Sage. (We could perhaps remove libmpir* though.)
if false; then
    echo "Removing old GMP/MPIR libraries..."
    rm -f "$SAGE_LOCAL"/lib/lib{gmp,mpir}*
else
    echo "Not removing old GMP/MPIR shared libraries, as other libraries"
    echo "and executables might still refer to them:"
    ls -l "$SAGE_LOCAL"/lib/lib{gmp,mpir}*.so.*
    echo "(Libraries with the same version number will get updated though.)"
fi

###############################################################################
# Now install MPIR:
###############################################################################

echo "Now installing MPIR..."
# The potential race condition in `make install` was fixed in MPIR 2.1.4.
$MAKE install
if [ $? -ne 0 ]; then
    echo >&2 "Error installing MPIR."
    if [ "$UNAME" != "CYGWIN" ]; then  # On Cygwin an error is not fatal.
        exit 1
    fi
fi

echo
echo "Remember to rebuild the Sage library ('./sage -b') such that it"
echo "will use the new MPIR."
echo "You may also have to (or want to) rebuild other Sage packages"
echo "that use MPIR.  Provided that this MPIR spkg is in 'spkg/standard/',"
echo "you can rebuild all packages depending on MPIR by typing:"
echo "    cd $SAGE_ROOT"
echo "    env SAGE_UPGRADING=yes make"
echo "but note that this will usually take quite a lot of time."
echo
