dnl Usage: SAGE_SHOULD_INSTALL_GCC(reason)
dnl
dnl Use this macro to indicate that we SHOULD install GCC.
dnl In this case, GCC will be installed unless SAGE_INSTALL_GCC=no.
dnl In the latter case, a warning is given.
AC_DEFUN([SAGE_SHOULD_INSTALL_GCC], [
    if test x$SAGE_INSTALL_GCC = xexists; then
        # Already installed in Sage, but it should remain selected
        true
    elif test x$SAGE_INSTALL_GCC = xno; then
        AC_MSG_WARN([$1])
    else
        AC_MSG_NOTICE([Installing GCC because $1])
        sage_spkg_install_gcc=yes
    fi
])

dnl Usage: SAGE_MUST_INSTALL_GCC(reason)
dnl
dnl Use this macro to indicate that we MUST install GCC.
dnl In this case, it is an error if SAGE_INSTALL_GCC=no.
AC_DEFUN([SAGE_MUST_INSTALL_GCC], [
    if test x$SAGE_INSTALL_GCC = xexists; then
        # Already installed in Sage, but it should remain selected
        true
    elif test x$SAGE_INSTALL_GCC = xno; then
        AC_MSG_ERROR([SAGE_INSTALL_GCC is set to 'no', but $1])
    else
        AC_MSG_NOTICE([Installing GCC because $1])
        sage_spkg_install_gcc=yes
    fi
])


dnl Test whether an existing GCC install in Sage exists and is broken
dnl If so set SAGE_BROKEN_GCC=yes
AC_DEFUN([SAGE_CHECK_BROKEN_GCC], [
    SAGE_BROKEN_GCC=no
    if test -n "$SAGE_LOCAL" -a -f "$SAGE_LOCAL/bin/gcc"; then
        if test -x "$SAGE_LOCAL/bin/g++"; then
            echo '#include <complex>' >conftest.cpp
            echo 'auto inf = 1.0 / std::complex<double>();' >>conftest.cpp

            # #31097: Do not try to source sage-env-config here - it is generated by configure
            # and is not needed to set up the compiler variables.
            if ! bash -c "source '$SAGE_SRC/bin/sage-env' && g++ -O3 -c -o conftest.o conftest.cpp"; then
                SAGE_BROKEN_GCC=yes
            fi
            rm -f conftest.*
        fi
    fi
])


SAGE_SPKG_CONFIGURE_BASE([gcc], [
        AC_REQUIRE([AC_PROG_CC])
        AC_REQUIRE([AC_PROG_CPP])
        AC_REQUIRE([AC_PROG_CXX])
        AC_REQUIRE([AC_PROG_OBJC])
        AC_REQUIRE([AC_PROG_OBJCXX])
        AC_REQUIRE([AC_CANONICAL_HOST])

    AC_ARG_ENABLE([gcc-version-check],
                  [AS_HELP_STRING([--disable-gcc-version-check],
                                  [do not check the version of gcc/gfortran])],
                  [enable_gcc_version_check=$enableval],
                  [enable_gcc_version_check=yes])

    AC_MSG_CHECKING([whether gcc is already installed in SAGE_LOCAL])
    if test -f "$SAGE_LOCAL/bin/gcc"; then
        CONFIGURED_CC_PROGNAME=$($CC --print-prog-name gcc 2>/dev/null)
        INSTALLED_GCC_PROGNAME=$($SAGE_LOCAL/bin/gcc --print-prog-name gcc 2>/dev/null)
        echo "CONFIGURED_CC_PROGNAME=$CONFIGURED_CC_PROGNAME" >& AS_MESSAGE_LOG_FD
        echo "INSTALLED_GCC_PROGNAME=$INSTALLED_GCC_PROGNAME" >& AS_MESSAGE_LOG_FD
        if test "$CONFIGURED_CC_PROGNAME" = "$INSTALLED_GCC_PROGNAME"; then
            dnl We get here when SAGE_LOCAL is set to something like /usr or $CONDA_ENV
            dnl as in our "conda for Sage developers" instructions.
            AC_MSG_RESULT([configured CC])
        else
            # Special value for SAGE_INSTALL_GCC if GCC is already installed
            SAGE_INSTALL_GCC=exists
            # Set yes since this implies we have already installed GCC and want to keep
            # it selected
            SAGE_MUST_INSTALL_GCC([gcc is already installed in SAGE_LOCAL])

            # Check whether it actually works...
            # See https://github.com/sagemath/sage/issues/24599
            SAGE_CHECK_BROKEN_GCC()
            if test x$SAGE_BROKEN_GCC = xyes; then
                # Prentend that GCC is not installed.
                # The gcc and g++ binaries as well as the "installed" file will
                # be removed by make before installing any packages such that
                # GCC will be built as if was never installed before.
                SAGE_INSTALL_GCC=yes
                SAGE_MUST_INSTALL_GCC([installed g++ is broken])
                AC_MSG_RESULT([yes, but broken])
            else
                AC_MSG_RESULT([yes])
            fi
        fi
    else
        AC_MSG_RESULT([no])
        if test -n "$SAGE_INSTALL_GCC"; then
            # Check the value of the environment variable SAGE_INSTALL_GCC
            AS_CASE([$SAGE_INSTALL_GCC],
                [yes], [
                    SAGE_MUST_INSTALL_GCC([SAGE_INSTALL_GCC is set to 'yes'])
                ], [no], [
                    true
                ], [
                    AC_MSG_ERROR([SAGE_INSTALL_GCC should be set to 'yes' or 'no'. You can also leave it unset to install GCC when needed])
                ])
        fi
    fi

    # Figuring out if we are using clang instead of gcc.
    AC_LANG_PUSH(C)
    AX_COMPILER_VENDOR()
    AS_IF([test "x$ax_cv_c_compiler_vendor" = xgnu], [
        IS_REALLY_GCC=yes
        AS_CASE([$host],
        [*-apple-darwin*], [
             AC_MSG_ERROR([Cannot build Sage on macOS with GNU's gcc.
               Make use gcc and g++ are actually Clang compilers.])])
    ], [
        IS_REALLY_GCC=no
    ])
    AC_LANG_POP()

    # Save the value of CXX without special flags to enable C++11 support
    AS_VAR_SET([SAGE_CXX_WITHOUT_STD], [$CXX])
    AC_SUBST(SAGE_CXX_WITHOUT_STD)
    # Modify CXX to include an option that enables C++11 support if necessary
    AX_CXX_COMPILE_STDCXX_11([], optional)
    if test $HAVE_CXX11 != 1; then
        SAGE_MUST_INSTALL_GCC([your C++ compiler does not support C++11])
    fi
    AC_SUBST(CXX)

    if test -z "$CC"; then
        SAGE_MUST_INSTALL_GCC([a C compiler is missing])
    fi

    # Check for C99 support detected by the AC_PROG_CC macro.
    if test "x$ac_cv_prog_cc_c99" = xno; then
        SAGE_MUST_INSTALL_GCC([your C compiler cannot compile C99 code])
    fi

    if test x$GXX != xyes; then
        SAGE_SHOULD_INSTALL_GCC([your C++ compiler isn't GCC (GNU C++)])
    elif test $sage_spkg_install_gcc = yes; then
        # If we're installing GCC anyway, skip the rest of these version
        # checks.
        true
    elif test x$GCC != xyes; then
        SAGE_SHOULD_INSTALL_GCC([your C compiler isn't GCC (GNU C)])
    elif test $enable_gcc_version_check = yes; then
        # Since sage_spkg_install_gcc is "no", we know that
        # at least C, C++ and Fortran compilers are available.
        # We also know that all compilers are GCC.

        # Find out the compiler versions:
        AX_GCC_VERSION()
        AX_GXX_VERSION()

        if test $IS_REALLY_GCC = yes ; then
            # Add the .0 because Debian/Ubuntu gives version numbers like
            # 4.6 instead of 4.6.4 (Issue #18885)
            AS_CASE(["$GXX_VERSION.0"],
                [[[0-8]].*], [
                    # Install our own GCC if the system-provided one is older than gcc 9
                    SAGE_SHOULD_INSTALL_GCC([you have $CXX version $GXX_VERSION, which is quite old])
                ],
                [1[[6-9]].*], [
                    # Install our own GCC if the system-provided one is newer than 15.x.
                    # See https://github.com/sagemath/sage/issues/29456
                    SAGE_SHOULD_INSTALL_GCC([$CXX is g++ version $GXX_VERSION, which is too recent for this version of Sage])
                ])
            fi

        # The following tests check that the version of the compilers
        # are all the same.
        if test "$GCC_VERSION" != "$GXX_VERSION"; then
            SAGE_SHOULD_INSTALL_GCC([$CC ($GCC_VERSION) and $CXX ($GXX_VERSION) are not the same version])
        fi

    fi

    # Check that the assembler and linker used by $CXX match $AS and $LD.
    # See https://github.com/sagemath/sage/issues/14296
    if test -n "$AS"; then
        CXX_as=`$CXX -print-prog-name=as 2>/dev/null`
        CXX_as=`command -v $CXX_as 2>/dev/null`
        cmd_AS=`command -v $AS`

        if ! (test "$CXX_as" = "" -o "$CXX_as" -ef "$cmd_AS"); then
            AC_MSG_NOTICE([       $CXX uses $CXX_as])
            AC_MSG_NOTICE([       \$AS equal to $AS])
            AC_MSG_ERROR([unset \$AS or set it to match your compiler's assembler])
        fi
    fi
    if test -n "$LD"; then
        CXX_ld=`$CXX -print-prog-name=ld 2>/dev/null`
        CXX_ld=`command -v $CXX_ld 2>/dev/null`
        cmd_LD=`command -v $LD`
        if ! (test "$CXX_ld" = "" -o "$CXX_ld" -ef "$cmd_LD"); then
            AC_MSG_NOTICE([       $CXX uses $CXX_ld])
            AC_MSG_NOTICE([       \$LD equal to $LD])
            AC_MSG_ERROR([unset \$LD or set it to match your compiler's linker])
        fi
    fi

    dnl A stamp file indicating that an existing, broken GCC install should be
    dnl cleaned up by make.
    if test x$SAGE_BROKEN_GCC = xyes; then
        AC_CONFIG_COMMANDS([broken-gcc], [
            # Re-run the check just in case, such as when re-running
            # config.status
            SAGE_CHECK_BROKEN_GCC()
            if test x$SAGE_BROKEN_GCC = xyes; then
                touch build/make/.clean-broken-gcc
            fi
        ], [
            SAGE_LOCAL="$SAGE_LOCAL"
            SAGE_SRC="$SAGE_SRC"
        ])
    fi

    # Determine which compiler flags should be set.
    if test x$sage_use_march_native = xno; then
        CFLAGS_MARCH=""
    elif test x$SAGE_FAT_BINARY = xyes; then
        CFLAGS_MARCH=""
    elif test x$sage_spkg_install_gcc = xyes; then
        CFLAGS_MARCH="-march=native"
    else
        AX_CHECK_COMPILE_FLAG("-march=native", [CFLAGS_MARCH="-march=native"], [CFLAGS_MARCH=""], [], [])
    fi
    AC_SUBST(CFLAGS_MARCH)

    # Determine whether compiler supports OpenMP.
    AC_LANG_PUSH([C])
    AX_OPENMP([
        AC_SUBST(OPENMP_CFLAGS)
    ])
    AC_LANG_POP()

    AC_LANG_PUSH([C++])
    AX_OPENMP([
        AC_SUBST(OPENMP_CXXFLAGS)
    ])
    AC_LANG_POP()


], , , [
    # Issue #27907: Find location of crti.o from the system CC, in case we build our own gcc
    AC_MSG_CHECKING([for the location of crti.o])
    CRTI=`$CC -print-file-name=crti.o 2>/dev/null || true`
    if test -n "$CRTI" ; then
        SAGE_CRTI_DIR=$(dirname -- "$CRTI")
        if test "$SAGE_CRTI_DIR" = "." ; then
            SAGE_CRTI_DIR=
        fi
    fi
    AC_SUBST(SAGE_CRTI_DIR)
    AC_MSG_RESULT($SAGE_CRTI_DIR)
])
