#!/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

# unset RM since it messes with libtool
unset RM

mpfr_patch()
{
    # Apply a patch on Solaris, but only on the sun4v architecture
    # by default. On other Solaris systems, it can be overridden.
    # The patch to the C code was developed by Paul Zimmermann, the patch
    # to the spkg-install by David Kirkby. See Ticket #6453.
    if [ "$UNAME" = SunOS ]; then
        # Add a patch to MPFR on Solaris if either:
        # 1) The machine is a sun4v architecture.
        # 2) The environment variable INCLUDE_MPFR_PATCH is set to 1 or "yes".
        #    This will allow creating of binaries on a machine other than
        #    sun4v, which will run on sun4v.
        echo
        echo "This computer is running Solaris on which some problems have been observed"
        echo "with the MPFR library running on a T2+ processor (sun4v architecture)."
        echo "See http://sagetrac.org/sage_trac/ticket/6453  A patch can be applied"
        echo "to bypass this problem.  The problem has NEVER been seen on Solaris on x86"
        echo "or on sun4u (UltraSPARC II etc.).  To determine the architecture run:"
        echo "    /usr/bin/arch -k"
        echo "If you experience MPFR test failures, or you wish to ensure the binary will run"
        echo "on a sun4v system, set the environment variable INCLUDE_MPFR_PATCH to 1, with:"
        echo "    export INCLUDE_MPFR_PATCH=1"
        echo "If you specifically wish to exclude the patch, set INCLUDE_MPFR_PATCH to 0 with:"
        echo "    export INCLUDE_MPFR_PATCH=0"
        echo "By default, the patch will only be applied on sun4v systems (T1, T2 and T2+"
        echo "processors), but this can be overridden on other systems.  Binaries for"
        echo "Solaris SPARC should be built with INCLUDE_MPFR_PATCH set to 1 or \"yes\","
        echo "unless you are 100% sure they will not be used on a sun4v system."
        echo
        # Note: "/usr/bin/arch" will return "sun4" on any SPARC system.
        # If given the '-k' option, aditional information will be displayed
        # to indicate if the system is sun4m (very old), sun4u or sun4v.

        # Set PATCH_MPFR to something other than 0 or 1 if it is unset:
        PATCH_MPFR="${INCLUDE_MPFR_PATCH-2}"
        do_apply=false
        case "$PATCH_MPFR" in
          1|yes)
            echo "Since INCLUDE_MPFR_PATCH was set to 1 or \"yes\", the MPFR library will be"
            echo "patched.  The binaries should be safe on any Solaris system."
            do_apply=true;;
          0|no)
            echo "Since INCLUDE_MPFR_PATCH was set to 0 or \"no\", the MPFR library will not"
            echo "be specifically patched.  You would be unwise to distribute SPARC binaries"
            echo "unless you are sure they will not be used on sun4v systems.";;
          2) # INCLUDE_MPFR_PATCH isn't set at all.
            if [ "`arch -k`" = sun4v ]; then
                echo "This is a sun4v system, so the MPFR library will be patched.  The binaries"
                echo "should run correctly on any SPARC system whose operating system is"
                echo "no older than the system used to build the binaries."
                do_apply=true
            else
                echo "Since this is not a sun4v system, the MPFR binary will not be patched."
                # Issue a warning on SPARC, but not (e.g.) x86 systems.
                if [ "`arch`" = sun4 ]; then
                    echo >&2 "WARNING: Problems may occur if you try to run this SPARC binary on a sun4v"
                    echo >&2 "system (T1, T2 or T2+ processors).  Binaries created like this should not"
                    echo >&2 "be distributed unless you know the end users' systems will not be sun4v."
                    echo >&2 "Set INCLUDE_MPFR_PATCH to 1, to include the patch, if you are unsure."
                fi
            fi;;
          *)
            echo >&2 "Warning: The environment variable INCLUDE_MPFR_PATCH was incorrectly"
            echo >&2 "set to \"$PATCH_MPFR\".  The MPFR library will be patched as a precaution."
            do_apply=true
        esac
        if $do_apply && ! patch -p1 < ../patches/mpn_exp.c.patch; then
            echo >&2 "Error: Patch for Solaris SPARC ('mpn_exp.c.patch') failed to apply."
            exit 1
        fi
        echo
    fi # $UNAME=SunOS

    # Further patches for Sage should get applied here
}

mpfr_get_upstream_selected_cflags() # Get MPFR's choice on empty CC and CFLAGS.
{
    if [ $# -ne 1 ]; then
        echo >&2 "Error: mpfr_get_upstream_selected_cflags() requires 'file' parameter."
        exit 1
    fi
    config_file=$1
    # Note: We currently extract MPFR's settings of CC and CFLAGS from
    #       'config.status', not 'mpfr.h' (which are both created by 'configure').
    mpfr_cc_pat="s/^CC='\([^']*\)'/\1/p"
    mpfr_cflags_pat="s/^CFLAGS='\([^']*\)'/\1/p"
    if ! [ -f "$config_file" ]; then
        upstream_cc=""
        upstream_cflags=""
        return 1
    fi
    upstream_cc=`sed -n -e "$mpfr_cc_pat" "$config_file"`
    upstream_cflags=`sed -n -e "$mpfr_cflags_pat" "$config_file"`
    # CFLAGS might probably be empty, CC shouldn't:
    if [ -z "$upstream_cc" ]; then
        # A warning will be issued by the code calling this function.
        return 1
    fi
    return 0
}

mpfr_configure()
{
    ###########################################################################
    # Set up environment variables:
    ###########################################################################

    user_cflags=$CFLAGS # Save them. 'sage-env' sets CC, but not CFLAGS.
    required_cflags="" # Additional mandatory settings required by Sage, accumulated below.
    default_cflags="" # Spkg defaults that can and might get overridden.

    if [ "$SAGE_DEBUG" = yes ]; then
        # Disable optimization, add debug symbols:
        required_cflags="$required_cflags -g -O0"
        echo >&2 "Warning: Building MPFR with SAGE_DEBUG=yes disables optimization."
    else
        # Add debug symbols by default, enable optimization, but do not (yet)
        # add processor-specific flags (these are eventually added later):
        default_cflags="$default_cflags -g -O3"
    fi

    if [ "$SAGE64" = yes ]; then
        if [ -z "$CFLAG64" ]; then
            CFLAG64=-m64
        fi
        echo "Building a 64-bit version of MPFR (using '$CFLAG64')."
        required_cflags="$required_cflags $CFLAG64"
        CPPFLAGS="$CPPFLAGS $CFLAG64"
        LDFLAGS="$LDFLAGS $CFLAG64"
        # As MPFR doesn't have C++ files, we don't have to modify CXXFLAGS.
    fi

    # Work around a bug in GCC 4.7.0 which breaks the build on Itanium CPUs.
    # See #12837, #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

    # Enabling thread-safe (which meanwhile is or at least may be the default)
    # currently causes problems on a few systems:
    SAGE_CONF_OPTS="--disable-thread-safe"

    if [ "$UNAME" = CYGWIN ]; then
        SAGE_CONF_OPTS="$SAGE_CONF_OPTS --disable-static --enable-shared"
    fi

    ###########################################################################
    # Pre-configure MPFR with CC and CFLAGS unset:
    ###########################################################################
    echo "Checking what CC and CFLAGS MPFR would use if they were empty..."
    if (unset CC CFLAGS CPPFLAGS CXXFLAGS &&
        ./configure --with-gmp="$SAGE_LOCAL" $SAGE_CONF_OPTS $MPFR_CONFIGURE) &>/dev/null;
    then
        mpfr_config_file=config.status
        if mpfr_get_upstream_selected_cflags "$mpfr_config_file"; then
            mpfr_cflags=$upstream_cflags
            mpfr_cc=$upstream_cc
            echo "Settings chosen by MPFR when configuring with CC and CFLAGS unset:"
            echo "  CC:      $mpfr_cc"
            echo "  CFLAGS:  $mpfr_cflags"
        else
            echo >&2 "Warning: Couldn't determine MPFR-selected CC and CFLAGS from '$mpfr_config_file'."
        fi
    else
        # We ignore errors in the first place, since we redirected all
        # messages to /dev/null. (The messages can be found in the 'config.log'
        # files if someone really wants to read them.)
        :;
    fi
    find . -name config.cache -o -name config.status -exec rm -f {} \;

    echo "Settings required to properly build MPFR, taking into account SAGE_DEBUG etc.:"
    echo "  CFLAGS:  $required_cflags"
    echo "  LDFLAGS: $LDFLAGS" # Might be empty, or specified by the user.
    echo "  ABI:     $ABI" # Might be empty, or 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 "  (CPPFLAGS, CXX and CXXFLAGS are listed below; these don't get modified.)"

    if [ -z "$user_cflags" ]; then
        # No CFLAGS specified by user => Use either MPFR's or our default ones,
        # plus those required by Sage for the package to build properly:
        if [ -n "$mpfr_cflags" ]; then
            # Fine. Use upstream settings.
            echo "Using MPFR's settings (plus mandatory ones)."
            CFLAGS="$mpfr_cflags $required_cflags"
        else # Use spkg's defaults.
            echo "Using the spkg's (i.e. Sage's) default (plus mandatory) settings."
            CFLAGS="$default_cflags $required_cflags"
        fi
    else
        # CFLAGS were specified by the user, so don't override them (unless
        # necessary).
        echo "Using user-specified settings (overriding defaults), with some additions."
        CFLAGS="$default_cflags $user_cflags $required_cflags"
    fi

    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.)"

    export CFLAGS CPPFLAGS LDFLAGS # 'sage-env' does *not* export all of them.

    ###########################################################################
    # Now really configure MPFR with proper settings:
    ###########################################################################
    echo
    if [ -z "$MPFR_CONFIGURE" ]; then
        echo "Configuring MPFR with the following options:"
    else
        echo "Configuring MPFR with additional options as specified by" \
            "MPFR_CONFIGURE:"
        echo "  $MPFR_CONFIGURE"
        echo "Finally configuring MPFR with the following options:"
    fi
    echo "  --prefix=\"$SAGE_LOCAL\""
    echo "  --libdir=\"$SAGE_LOCAL/lib\""
    echo "  --with-gmp=\"$SAGE_LOCAL\""
    for opt in $SAGE_CONF_OPTS $MPFR_CONFIGURE; do
        echo "  $opt"
    done
    if [ -z "$MPFR_CONFIGURE" ]; then
        echo "You can set MPFR_CONFIGURE to pass additional parameters."
    fi

    ./configure --prefix="$SAGE_LOCAL" \
                --libdir="$SAGE_LOCAL/lib" \
                --with-gmp="$SAGE_LOCAL" \
                $SAGE_CONF_OPTS $MPFR_CONFIGURE
}

mpfr_build()
{
    echo "Patching MPFR..."
    mpfr_patch
    if [ $? -ne 0 ]; then
        echo >&2 "Error patching MPFR."
        exit 1
    fi

    echo
    echo "Now configuring MPFR..."
    mpfr_configure
    if [ $? -ne 0 ]; then
        echo >&2 "Error configuring MPFR."
        echo >&2 "See above for the options passed to it, and the file"
        echo >&2 "  `pwd`/config.log"
        echo >&2 "for details."
        exit 1
    fi

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

    echo
    echo "Building MPFR succeeded.  Now deleting old headers..."
    rm -f "$SAGE_LOCAL"/include/*mpfr*
    # Do not delete old libraries as this causes gcc to break during
    # parallel builds.
    # rm -f "$SAGE_LOCAL"/lib/libmpfr.*

    echo "Now installing MPFR..."
    $MAKE install
    if [ $? -ne 0 ];  then
        echo >&2 "Error installing MPFR."
        exit 1
    fi
}

cd src

mpfr_build
# All potential errors catched in the above function.
