# Modified by Ben Burton from CheckCXX11Features, which was released as
# public domain by its original authors (Rolf Eike Beer and Andreas Weis).
# See http://pageant.ghulbus.eu/?p=664

# Checks for C++14 features
#  CXX14_FEATURE_LIST - a list containing all supported features
#  HAS_CXX14_DEPRECATED         - deprecated attribute
#  HAS_CXX14_DEPRECATED_TYPEDEF - deprecated typedefs
#  HAS_CXX14_DEPRECATED_USING   - deprecated "using" declarations
#
# Original script by Rolf Eike Beer
# Modifications by Andreas Weis
# Further modifications by William Pettersson and Ben Burton
#
# CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3)

SET(CHECK_CXX14_OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
IF(CMAKE_COMPILER_IS_GNUCXX) # G++ uses gnu++1y on versions < 4.9.
	EXECUTE_PROCESS(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
	IF(GCC_VERSION VERSION_GREATER 4.9 OR GCC_VERSION VERSION_EQUAL 4.9)
#		MESSAGE(STATUS "C++14 activated.")
		SET(CXX14_OPTION "-std=c++14")
	ELSE()
			MESSAGE(FATAL_ERROR "C++14 needed. Therefore a gcc compiler with a version at least 4.9 is needed.")
	endif()
ELSE()
	SET(CXX14_OPTION "-std=c++14") # CLang.
ENDIF()
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX14_OPTION}")

MACRO(CXX14_CHECK_FEATURE FEATURE_NAME FEATURE_NUMBER RESULT_VAR)
	IF (NOT DEFINED ${RESULT_VAR})
		SET(_bindir "${CMAKE_CURRENT_BINARY_DIR}/cxx14/cxx14_${FEATURE_NAME}")
		IF (${FEATURE_NUMBER})
			SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++14-tests/c++14-test-${FEATURE_NAME}-N${FEATURE_NUMBER})
			SET(_LOG_NAME "\"${FEATURE_NAME}\" (N${FEATURE_NUMBER})")
		ELSE (${FEATURE_NUMBER})
			SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++14-tests/c++14-test-${FEATURE_NAME})
			SET(_LOG_NAME "\"${FEATURE_NAME}\"")
		ENDIF (${FEATURE_NUMBER})
#		MESSAGE(STATUS "Checking C++14 support for ${_LOG_NAME}")

		SET(_SRCFILE "${_SRCFILE_BASE}.cpp")
		SET(_SRCFILE_FAIL "${_SRCFILE_BASE}_fail.cpp")
		SET(_SRCFILE_FAIL_COMPILE "${_SRCFILE_BASE}_fail_compile.cpp")

		IF (CROSS_COMPILING)
			try_compile(${RESULT_VAR} "${_bindir}" "${_SRCFILE}")
			IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
				try_compile(${RESULT_VAR} "${_bindir}_fail" "${_SRCFILE_FAIL}")
			ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
		ELSE (CROSS_COMPILING)
			try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
					"${_bindir}" "${_SRCFILE}"
					LINK_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}")
			IF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
				SET(${RESULT_VAR} TRUE)
			ELSE (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
				SET(${RESULT_VAR} FALSE)
			ENDIF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
			IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
				try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
						"${_bindir}_fail" "${_SRCFILE_FAIL}"
						LINK_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}")
				IF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
					SET(${RESULT_VAR} TRUE)
				ELSE (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
					SET(${RESULT_VAR} FALSE)
				ENDIF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
			ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
		ENDIF (CROSS_COMPILING)
		IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
			try_compile(_TMP_RESULT "${_bindir}_fail_compile" "${_SRCFILE_FAIL_COMPILE}")
			IF (_TMP_RESULT)
				SET(${RESULT_VAR} FALSE)
			ELSE (_TMP_RESULT)
				SET(${RESULT_VAR} TRUE)
			ENDIF (_TMP_RESULT)
		ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})

		IF (${RESULT_VAR})
#			MESSAGE(STATUS "Checking C++14 support for ${_LOG_NAME} -- works")
			LIST(APPEND CXX14_FEATURE_LIST ${RESULT_VAR})
		ELSE (${RESULT_VAR})
#			MESSAGE(STATUS "Checking C++14 support for ${_LOG_NAME} -- not supported")
		ENDIF (${RESULT_VAR})
		SET(${RESULT_VAR} ${${RESULT_VAR}} CACHE INTERNAL "C++14 support for ${_LOG_NAME}")
	ENDIF (NOT DEFINED ${RESULT_VAR})
ENDMACRO(CXX14_CHECK_FEATURE)

CXX14_CHECK_FEATURE("deprecated"           "" HAS_CXX14_DEPRECATED)
CXX14_CHECK_FEATURE("deprecated_typedef"   "" HAS_CXX14_DEPRECATED_TYPEDEF)
CXX14_CHECK_FEATURE("deprecated_using"     "" HAS_CXX14_DEPRECATED_USING)

MACRO(NEED_CXX14_FEATURE FEATURE)
    STRING(TOUPPER ${FEATURE} FEATURE_U)
    LIST(FIND CXX14_FEATURE_LIST "HAS_CXX14_${FEATURE_U}" CXX14_HAS_FEATURE)
    IF(CXX14_HAS_FEATURE EQUAL -1)
        MESSAGE(STATUS "Error: C++14 feature \"${FEATURE}\" not found.")
        SET(HAVE_CXX14_FEATURES FALSE)
        LIST(APPEND MISSING_FEATURES ${FEATURE})
    ELSE()
        MESSAGE(STATUS "C++14 feature \"${FEATURE}\" found.")
    ENDIF()
ENDMACRO()

MACRO(OPTIONAL_CXX14_FEATURE FEATURE)
    STRING(TOUPPER ${FEATURE} FEATURE_U)
    LIST(FIND CXX14_FEATURE_LIST "HAS_CXX14_${FEATURE_U}" CXX14_HAS_FEATURE)
    IF(CXX14_HAS_FEATURE EQUAL -1)
        MESSAGE(STATUS "Warning: C++14 feature \"${FEATURE}\" not found.")
        LIST(APPEND MISSING_FEATURES ${FEATURE})
    ELSE()
        MESSAGE(STATUS "C++14 feature \"${FEATURE}\" found.")
    ENDIF()
ENDMACRO()

SET(CXX14_FEATURE_LIST ${CXX14_FEATURE_LIST} CACHE STRING "C++14 feature support list")
MARK_AS_ADVANCED(FORCE CXX14_FEATURE_LIST)

SET(CXX14_SWITCH ${CXX14_OPTION} CACHE STRING "Command line switch to enable C++14 features")
MARK_AS_ADVANCED(FORCE CXX14_SWITCH)
SET(CMAKE_CXX_FLAGS ${CHECK_CXX14_OLD_CMAKE_CXX_FLAGS})
UNSET(CHECK_CXX14_OLD_CMAKE_CXX_FLAGS)

