dnl detect if current compiler is clang or gcc (or...)

AC_DEFUN([NUT_COMPILER_FAMILY],
[
  AC_CACHE_CHECK([if CC compiler family is GCC],
    [nut_cv_GCC],
    [AS_IF([test -n "$CC"],
        [AS_IF([$CC --version 2>&1 | grep 'Free Software Foundation' > /dev/null],
            [nut_cv_GCC=yes],[nut_cv_GCC=no])],
        [AC_MSG_ERROR([CC is not set])]
    )])

  AC_CACHE_CHECK([if CXX compiler family is GCC],
    [nut_cv_GXX],
    [AS_IF([test -n "$CXX"],
        [AS_IF([$CXX --version 2>&1 | grep 'Free Software Foundation' > /dev/null],
            [nut_cv_GXX=yes],[nut_cv_GXX=no])],
        [AC_MSG_ERROR([CXX is not set])]
    )])

  AC_CACHE_CHECK([if CPP preprocessor family is GCC],
    [nut_cv_GPP],
    [AS_IF([test -n "$CPP"],
        [AS_IF([$CPP --version 2>&1 | grep 'Free Software Foundation' > /dev/null],
            [nut_cv_GPP=yes],[nut_cv_GPP=no])],
        [AC_MSG_ERROR([CPP is not set])]
    )])

  AS_IF([test "x$GCC" = "x" && test "$nut_cv_GCC" = yes],   [GCC=yes])
  AS_IF([test "x$GXX" = "x" && test "$nut_cv_GXX" = yes],   [GXX=yes])
  AS_IF([test "x$GPP" = "x" && test "$nut_cv_GPP" = yes],   [GPP=yes])

  AC_CACHE_CHECK([if CC compiler family is clang],
    [nut_cv_CLANGCC],
    [AS_IF([test -n "$CC"],
        [AS_IF([$CC --version 2>&1 | grep -E '(clang version|Apple LLVM version .*clang-)' > /dev/null],
            [nut_cv_CLANGCC=yes],[nut_cv_CLANGCC=no])],
        [AC_MSG_ERROR([CC is not set])]
    )])

  AC_CACHE_CHECK([if CXX compiler family is clang],
    [nut_cv_CLANGXX],
    [AS_IF([test -n "$CXX"],
        [AS_IF([$CXX --version 2>&1 | grep -E '(clang version|Apple LLVM version .*clang-)' > /dev/null],
            [nut_cv_CLANGXX=yes],[nut_cv_CLANGXX=no])],
        [AC_MSG_ERROR([CXX is not set])]
    )])

  AC_CACHE_CHECK([if CPP preprocessor family is clang],
    [nut_cv_CLANGPP],
    [AS_IF([test -n "$CPP"],
        [AS_IF([$CPP --version 2>&1 | grep -E '(clang version|Apple LLVM version .*clang-)' > /dev/null],
            [nut_cv_CLANGPP=yes],[nut_cv_CLANGPP=no])],
        [AC_MSG_ERROR([CPP is not set])]
    )])

  AS_IF([test "x$CLANGCC" = "x" && test "$nut_cv_CLANGCC" = yes],   [CLANGCC=yes])
  AS_IF([test "x$CLANGXX" = "x" && test "$nut_cv_CLANGXX" = yes],   [CLANGXX=yes])
  AS_IF([test "x$CLANGPP" = "x" && test "$nut_cv_CLANGPP" = yes],   [CLANGPP=yes])
])

AC_DEFUN([NUT_CHECK_COMPILE_FLAG],
[
dnl Note: with this line uncommented, builds report
dnl   sed: 0: conftest.c: No such file or directory
dnl so seemingly try to parse the method without args:
    dnl### AC_REQUIRE([AX_RUN_OR_LINK_IFELSE])

dnl Note: per https://stackoverflow.com/questions/52557417/how-to-check-support-compile-flag-in-autoconf-for-clang
dnl the -Werror below is needed to detect "warnings" about unsupported options
    COMPILERFLAG="$1"

dnl We also try to run an actual build since tools called from that might
dnl complain if they are forwarded unknown flags accepted by the front-end.
    SAVED_CFLAGS="$CFLAGS"
    SAVED_CXXFLAGS="$CXXFLAGS"

    AC_LANG_PUSH([C])
    AX_CHECK_COMPILE_FLAG([${COMPILERFLAG}],
        [CFLAGS="$CFLAGS ${COMPILERFLAG}"
         AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
            [], [CFLAGS="$SAVED_CFLAGS"])
        ], [], [-Werror])
    AC_LANG_POP([C])

    AC_LANG_PUSH([C++])
    AX_CHECK_COMPILE_FLAG([${COMPILERFLAG}],
        [CXXFLAGS="$CXXFLAGS ${COMPILERFLAG}"
         AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
            [], [CXXFLAGS="$SAVED_CXXFLAGS"])
        ], [], [-Werror])
    AC_LANG_POP([C++])
])

AC_DEFUN([NUT_COMPILER_FAMILY_FLAGS],
[
    AC_MSG_NOTICE([Detecting support for additional compiler flags])

dnl -Qunused-arguments:
dnl   Do not die due to `clang: error: argument unused during compilation: '-I .'`
dnl -Wno-unknown-warning-option: Do not die (on older clang releases) due to
dnl   error: unknown warning option '-Wno-double-promotion'; did you mean
dnl          '-Wno-documentation'? [-Werror,-Wunknown-warning-option]
dnl -fcolor-diagnostics: help find where bugs are in the wall of text (clang)
dnl -fdiagnostics-color=ARG: help find where bugs are in the wall of text (gcc)

    dnl First check for this to avoid failing on unused include paths etc:
    NUT_CHECK_COMPILE_FLAG([-Qunused-arguments])

    m4_foreach_w([TESTCOMPILERFLAG], [
        -Wno-reserved-identifier
    ], [
        NUT_CHECK_COMPILE_FLAG([TESTCOMPILERFLAG])
    ])

    dnl Note: each m4_foreach_w arg must be named uniquely
    dnl Note: Seems -fcolor-diagnostics is clang-only and sometimes
    dnl gcc blindly accepts it in test and fails to use later.
    AS_IF([test x"${nut_enable_Wcolor}" = xyes], [
        m4_foreach_w([TESTCOMPILERFLAG_COLOR], [
            -fdiagnostics-color=always
        ], [
            NUT_CHECK_COMPILE_FLAG([TESTCOMPILERFLAG_COLOR])
        ])
    ], [AC_MSG_NOTICE([NOT checking for options to request colorized compiler output (pass --enable-Wcolor for that)])])

    dnl Last check for this to avoid accepting anything regardless of support.
    dnl NOTE that some toolkit versions accept this option blindly and without
    dnl really supporting it (but not erroring out on it, either):
    dnl    cc1: note: unrecognized command-line option '-Wno-unknown-warning-option'
    dnl         may have been intended to silence earlier diagnostics
    NUT_CHECK_COMPILE_FLAG([-Wno-unknown-warning-option])

dnl # Older "brute-forced" settings:
dnl    AS_IF([test "x$CLANGCC" = xyes], [CFLAGS="$CFLAGS -Wno-unknown-warning-option"])
dnl    AS_IF([test "x$CLANGXX" = xyes], [CXXFLAGS="$CXXFLAGS -Wno-unknown-warning-option"])

dnl # Despite the internet lore, practical GCC versions seen so far
dnl # (4.x-10.x) do not know of this CLI option, with varied results
dnl # from "cc1: note: unrecognized command-line option '-Wno-unknown-warning'
dnl # may have been intended to silence earlier diagnostics"
dnl # to "cc1: error: unrecognized command line option '-Wno-unknown-warning'
dnl # [-Werror]"... so we do not pass it by default:
dnl    AS_IF([test "x$GCC" = xyes], [CFLAGS="$CFLAGS -Wno-unknown-warning"])
dnl    AS_IF([test "x$GXX" = xyes], [CXXFLAGS="$CXXFLAGS -Wno-unknown-warning"])

dnl # There should be no need to include standard system paths (and possibly
dnl # confuse the compiler assumptions - along with its provided headers)...
dnl # ideally; in practice however cppunit, net-snmp and some system include
dnl # files do cause grief to picky compiler settings (more so from third
dnl # party packages shipped via /usr/local/... namespace):
    AS_IF([test "x$CLANGCC" = xyes -o "x$GCC" = xyes], [
dnl #        CFLAGS="-isystem /usr/include $CFLAGS"
        AS_IF([test -d /usr/local/include],
            [CFLAGS="-isystem /usr/local/include $CFLAGS"])
        AS_IF([test -d /usr/pkg/include],
            [CFLAGS="-isystem /usr/pkg/include $CFLAGS"])
    ])
    AS_IF([test "x$CLANGXX" = xyes -o "x$GXX" = xyes], [
dnl #        CXXFLAGS="-isystem /usr/include $CXXFLAGS"
        AS_IF([test -d /usr/local/include],
            [CXXFLAGS="-isystem /usr/local/include $CXXFLAGS"])
        AS_IF([test -d /usr/pkg/include],
            [CXXFLAGS="-isystem /usr/pkg/include $CXXFLAGS"])
    ])

dnl # Default to avoid noisy warnings on older compilers
dnl # (gcc-4.x, clang-3.x) due to their preference of
dnl # ANSI C (C89/C90) out of the box. While NUT codebase
dnl # currently can build in that mode, reliability of
dnl # results is uncertain - third-party and/or system
dnl # headers and libs seemingly no longer care for C90
dnl # on modern systems, and we have no recent data from
dnl # truly legacy systems which have no choice.
dnl # Some distributions and platforms also have problems
dnl # building in "strict C" mode, so for the GNU-compatible
dnl # compilers we default to the GNU C/C++ dialects.
    AS_IF([test "x$GCC" = xyes -o "x$CLANGCC" = xyes],
        [AS_CASE(["${CFLAGS}"], [-std=*], [],
            [AC_LANG_PUSH([C])
             AX_CHECK_COMPILE_FLAG([-std=gnu99],
                [AC_MSG_NOTICE([Defaulting C standard support to GNU C99 on a GCC or CLANG compatible compiler])
                 CFLAGS="$CFLAGS -std=gnu99"
                ], [], [-Werror])
             AC_LANG_POP([C])
         ])
    ])

dnl # Note: this might upset some very old compilers
dnl # but then by default we wouldn't build C++ parts
    AS_IF([test "x$GCC" = xyes -o "x$CLANGCC" = xyes],
        [AS_CASE(["${CXXFLAGS}"], [-std=*], [],
            [AC_LANG_PUSH([C++])
             AX_CHECK_COMPILE_FLAG([-std=gnu++11],
                [AC_MSG_NOTICE([Defaulting C++ standard support to GNU C++11 on a GCC or CLANG compatible compiler])
                 CXXFLAGS="$CXXFLAGS -std=gnu++11"
                ], [], [-Werror])
             AC_LANG_POP([C++])
         ])
    ])

])

AC_DEFUN([NUT_COMPILER_FAMILY_FLAGS_DEFAULT_STANDARD],
[
dnl # Default to avoid noisy warnings on older compilers
dnl # (gcc-4.x, clang-3.x) due to their preference of
dnl # ANSI C (C89/C90) out of the box. While NUT codebase
dnl # currently can build in that mode, reliability of
dnl # results is uncertain - third-party and/or system
dnl # headers and libs seemingly no longer care for C90
dnl # on modern systems, and we have no recent data from
dnl # truly legacy systems which have no choice.
dnl # Some distributions and platforms also have problems
dnl # building in "strict C" mode, so for the GNU-compatible
dnl # compilers we default to the GNU C/C++ dialects.
    AS_IF([test "x$GCC" = xyes -o "x$CLANGCC" = xyes],
        [AS_CASE(["${CFLAGS}"], [*-std=*], [],
            [AC_LANG_PUSH([C])
             AX_CHECK_COMPILE_FLAG([-std=gnu99],
                [AC_MSG_NOTICE([Defaulting C standard support to GNU C99 on a GCC or CLANG compatible compiler])
                 CFLAGS="$CFLAGS -std=gnu99"
                ], [], [-Werror])
             AC_LANG_POP([C])
         ])
    ])

dnl # Note: this might upset some very old compilers
dnl # but then by default we wouldn't build C++ parts
    AS_IF([test "x$GCC" = xyes -o "x$CLANGCC" = xyes],
        [AS_CASE(["${CXXFLAGS}"], [*-std=*], [],
            [AC_LANG_PUSH([C++])
             AX_CHECK_COMPILE_FLAG([-std=gnu++11],
                [AC_MSG_NOTICE([Defaulting C++ standard support to GNU C++11 on a GCC or CLANG compatible compiler])
                 CXXFLAGS="$CXXFLAGS -std=gnu++11"
                ], [], [-Werror])
             AC_LANG_POP([C++])
         ])
    ])

])
