# Compilers:
#
# - TENGINE_GCC                   - GNU compiler (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# - TENGINE_CLANG                 - Clang-compatible compiler (CMAKE_CXX_COMPILER_ID MATCHES "Clang" - Clang or AppleClang, see CMP0025)
# - TENGINE_ICC                   - Intel compiler
# - TENGINE_MSVC                  - MSVC, Microsoft Visual Compiler (CMake variable)
# - TENGINE_MINGW TENGINE_CYGWIN  - MINGW / CYGWIN / CMAKE_COMPILER_IS_MINGW / CMAKE_COMPILER_IS_CYGWIN (CMake original variables)
#
# CPU Platforms:
# - X86 / X86_64
# - ARM - ARM CPU, not defined for AArch64
# - AARCH64 - ARMv8+ (64-bit)
# - PPC64 / PPC64LE - PowerPC
# - MIPS
#
# OS:
# - WIN32 - Windows | MINGW
# - UNIX - Linux | MacOSX | ANDROID
# - ANDROID
# - IOS
# - APPLE - MacOSX | iOS


# use relative file path for microsoft visual studio
IF (MSVC)
  SET (CMAKE_USE_RELATIVE_PATHS ON CACHE INTERNAL "" FORCE)
ENDIF()


# check target cpu
IF (TENGINE_SKIP_TARGET_PROCESSOR_CHECK)
ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|x86_64.*|AMD64.*")
    SET (TENGINE_TARGET_PROCESSOR        "X86"   CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_32Bit  FALSE   CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_64Bit  TRUE    CACHE INTERNAL "" FORCE)
ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "i686.*|i386.*|x86.*")
    SET (TENGINE_TARGET_PROCESSOR        "X86"   CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_32Bit  TRUE    CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_64Bit  FALSE   CACHE INTERNAL "" FORCE)
ELSEIF ((IOS AND CMAKE_OSX_ARCHITECTURES MATCHES "arm") OR (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*|arm64.*|ARM64.*)"))
    SET (TENGINE_TARGET_PROCESSOR        "ARM"   CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_32Bit  FALSE   CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_64Bit  TRUE    CACHE INTERNAL "" FORCE)
ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)")
    SET (TENGINE_TARGET_PROCESSOR        "ARM"   CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_32Bit  TRUE    CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_64Bit  FALSE   CACHE INTERNAL "" FORCE)
ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64le")
    SET (TENGINE_TARGET_PROCESSOR        "PPCLE" CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_32Bit  FALSE   CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_64Bit  TRUE    CACHE INTERNAL "" FORCE)
ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
    SET (TENGINE_TARGET_PROCESSOR        "PPC"   CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_32Bit  FALSE   CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_64Bit  TRUE    CACHE INTERNAL "" FORCE)
ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "^(mips.*|MIPS.*)")
    SET (TENGINE_TARGET_PROCESSOR        "MIPS"  CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_32Bit  TRUE    CACHE INTERNAL "" FORCE)
    SET (TENGINE_TARGET_PROCESSOR_64Bit  FALSE   CACHE INTERNAL "" FORCE)
ELSE()
    IF (NOT TENGINE_SUPPRESS_TARGET_PROCESSOR_CHECK)
        MESSAGE (WARNING "TENGINE: Unrecognized target processor configuration.")
    ENDIF()
ENDIF()


# Workaround for 32-bit operating systems on x86_64
IF ((CMAKE_SIZEOF_VOID_P EQUAL 4) AND (TENGINE_TARGET_PROCESSOR MATCHES "X86") AND (NOT TENGINE_FORCE_BUILD_X86_64))
    IF (NOT TENGINE_SUPPRESS_TARGET_PROCESSOR_CHECK)
        MESSAGE (WARNING "TENGINE: 32Bit target OS is detected. Assume 32-bit compilation mode.")
    ENDIF()
    IF (TENGINE_TARGET_PROCESSOR_64Bit)
        SET (TENGINE_TARGET_PROCESSOR_64Bit  FALSE   CACHE INTERNAL "" FORCE)
        SET (TENGINE_TARGET_PROCESSOR_32Bit  TRUE    CACHE INTERNAL "" FORCE)
    ENDIF()
ENDIF()

# Workaround for 32-bit operating systems on aarch64 processor
IF ((CMAKE_SIZEOF_VOID_P EQUAL 4) AND (TENGINE_TARGET_PROCESSOR MATCHES "ARM") AND (NOT TENGINE_FORCE_BUILD_AARCH64))
    IF (NOT TENGINE_SUPPRESS_TARGET_PROCESSOR_CHECK)
        MESSAGE (STATUS "TENGINE: 32Bit target OS is detected. Assume 32-bit compilation mode.")
    ENDIF()
    IF (TENGINE_TARGET_PROCESSOR_64Bit)
        SET (TENGINE_TARGET_PROCESSOR_32Bit  TRUE    CACHE INTERNAL "" FORCE)
        SET (TENGINE_TARGET_PROCESSOR_64Bit  FALSE   CACHE INTERNAL "" FORCE)
    ENDIF()
ENDIF()


# system is Linux
IF (CMAKE_SYSTEM_NAME MATCHES "Linux")
    IF (${TENGINE_TARGET_PROCESSOR} MATCHES "ARM" AND TENGINE_TARGET_PROCESSOR_32Bit)
        SET (TENGINE_THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/linux/armv7-a" CACHE INTERNAL "" FORCE)
    ENDIF()

    IF (${TENGINE_TARGET_PROCESSOR} MATCHES "ARM" AND TENGINE_TARGET_PROCESSOR_64Bit)
        SET (TENGINE_THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/linux/armv8-a" CACHE INTERNAL "" FORCE)
    ENDIF()

    IF (${TENGINE_TARGET_PROCESSOR} MATCHES "X86" AND TENGINE_TARGET_PROCESSOR_32Bit)
        SET (TENGINE_THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/linux/x86" CACHE INTERNAL "" FORCE)
    ENDIF()

    IF (${TENGINE_TARGET_PROCESSOR} MATCHES "X86" AND TENGINE_TARGET_PROCESSOR_64Bit)
        SET (TENGINE_THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/linux/x86_64" CACHE INTERNAL "" FORCE)
    ENDIF()
# system is Windows
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Windows")
    IF (${TENGINE_TARGET_PROCESSOR} MATCHES "ARM" AND TENGINE_TARGET_PROCESSOR_32Bit)
        SET (TENGINE_THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/windows/armv7-a" CACHE INTERNAL "" FORCE)
    ENDIF()

    IF (${TENGINE_TARGET_PROCESSOR} MATCHES "ARM" AND TENGINE_TARGET_PROCESSOR_64Bit)
        SET (TENGINE_THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/windows/armv8-a" CACHE INTERNAL "" FORCE)
    ENDIF()

    IF (${TENGINE_TARGET_PROCESSOR} MATCHES "X86" AND TENGINE_TARGET_PROCESSOR_32Bit)
        SET (TENGINE_THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/windows/x86" CACHE INTERNAL "" FORCE)
    ENDIF()

    IF (${TENGINE_TARGET_PROCESSOR} MATCHES "X86" AND TENGINE_TARGET_PROCESSOR_64Bit)
        SET (TENGINE_THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/windows/x86_64" CACHE INTERNAL "" FORCE)
    ENDIF()

    # microsoft virtual c++ builder version
    IF (MSVC_VERSION LESS 1900)
        IF     (MSVC_VERSION EQUAL 1400)
            SET (TENGINE_VC_RUNTIME vc8)
        ELSEIF (MSVC_VERSION EQUAL 1500)
            SET (TENGINE_VC_RUNTIME vc9)
        ELSEIF (MSVC_VERSION EQUAL 1600)
            SET (TENGINE_VC_RUNTIME vc10)
        ELSEIF (MSVC_VERSION EQUAL 1700)
            SET (TENGINE_VC_RUNTIME vc11)
        ELSEIF (MSVC_VERSION EQUAL 1800)
            SET (TENGINE_VC_RUNTIME vc12)
        ENDIF()
        MESSAGE (FATAL_ERROR "${PROJECT_NAME}: The version of MS VC++ is too old(${TENGINE_VC_RUNTIME}).")
    ELSEIF (MSVC_VERSION EQUAL 1900)
        SET (TENGINE_VC_RUNTIME vc14)
    ELSEIF (MSVC_VERSION MATCHES "^191[0-9]$")
        SET (TENGINE_VC_RUNTIME vc15)
    ELSEIF (MSVC_VERSION MATCHES "^192[0-9]$")
        SET (TENGINE_VC_RUNTIME vc16)
    ELSEIF (MINGW)
        SET (TENGINE_VC_RUNTIME mingw)
    ELSE()
        MESSAGE (FATAL_ERROR "${PROJECT_NAME}: The version of MS VC++ is too high(${TENGINE_VC_RUNTIME}).")
    ENDIF()

    SET (TENGINE_THIRD_PARTY_ROOT "${TENGINE_THIRD_PARTY_ROOT}/${TENGINE_VC_RUNTIME}" CACHE INTERNAL "" FORCE)
# system is FreeBSD
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
    MESSAGE(STATUS "Current platform: FreeBSD")
    MESSAGE (FATAL_ERROR "${PROJECT_NAME}: Do not support FreeBSD for new.")

# system is Android
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Android")
    IF (${TENGINE_TARGET_PROCESSOR} MATCHES "ARM" AND TENGINE_TARGET_PROCESSOR_32Bit)
        SET (TENGINE_THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/android/armv7-a" CACHE INTERNAL "" FORCE)
    ENDIF()

    IF (${TENGINE_TARGET_PROCESSOR} MATCHES "ARM" AND TENGINE_TARGET_PROCESSOR_64Bit)
        SET (TENGINE_THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/android/armv8-a" CACHE INTERNAL "" FORCE)
    ENDIF()

    IF (${TENGINE_TARGET_PROCESSOR} MATCHES "X86" AND TENGINE_TARGET_PROCESSOR_32Bit)
        SET (TENGINE_THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/android/x86" CACHE INTERNAL "" FORCE)
    ENDIF()

    IF (${TENGINE_TARGET_PROCESSOR} MATCHES "X86" AND TENGINE_TARGET_PROCESSOR_64Bit)
        SET (TENGINE_THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/android/x86_64" CACHE INTERNAL "" FORCE)
    ENDIF()
ENDIF()


# Check which compiler
# GCC, the GNU Compiler Collection
IF (NOT DEFINED TENGINE_COMPILER_GCC AND CMAKE_CXX_COMPILER_ID MATCHES "GNU")
    SET (TENGINE_COMPILER_GCC TRUE)
ENDIF()

# Clang, C Language Family Frontend for LLVM
if(NOT DEFINED TENGINE_COMPILER_CLANG AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")  # Clang or AppleClang (see CMP0025)
    SET (TENGINE_COMPILER_CLANG TRUE)
ENDIF()

# ICC, Intel C++ Compiler
IF (UNIX)
    IF     (__ICL)
        SET (TENGINE_COMPILER_ICC   __ICL)
    ELSEIF (__ICC)
        SET (TENGINE_COMPILER_ICC   __ICC)
    ELSEIF (__ECL)
        SET (TENGINE_COMPILER_ICC   __ECL)
    ELSEIF (__ECC)
        SET (TENGINE_COMPILER_ICC   __ECC)
    ELSEIF (__INTEL_COMPILER)
        SET (TENGINE_COMPILER_ICC   __INTEL_COMPILER)
    ELSEIF (CMAKE_C_COMPILER MATCHES "icc")
        SET (TENGINE_COMPILER_ICC   icc_matches_c_compiler)
    ENDIF()
ENDIF()

IF (MSVC AND CMAKE_C_COMPILER MATCHES "icc|icl")
    SET (TENGINE_COMPILER_ICC   __INTEL_COMPILER_FOR_WINDOWS)
ENDIF()

# MSVC, Microsoft Visual C++ Compiler
IF (MSVC)
    SET (TENGINE_COMPILER_MSVC TRUE)
ENDIF()

# MinGW, Minimalist GNU for Windows
IF (MINGW OR CMAKE_COMPILER_IS_MINGW)
    SET (TENGINE_COMPILER_MINGW TRUE)
ENDIF()

# Cygwin
IF (CYGWIN OR CMAKE_COMPILER_IS_CYGWIN)
    SET (TENGINE_COMPILER_CYGWIN TRUE)
ENDIF()


# Check C/C++ standard support
INCLUDE (CheckLanguage)
INCLUDE (CheckCCompilerFlag)
INCLUDE (CheckCXXCompilerFlag)

# C99 is the base required standard
SET (CMAKE_C_STANDARD 99)
SET (CMAKE_C_STANDARD_REQUIRED TRUE)
SET (CMAKE_C_EXTENSIONS ON)

# Try to enable C11 standard
IF (TENGINE_USE_LASTEST_C_STANDARD OR TENGINE_USE_LASTEST_STANDARD)
    CHECK_C_COMPILER_FLAG ("-std=c11" TENGINE_ENV_HAS_C11)

    IF (TENGINE_ENV_HAS_C11)
        SET (CMAKE_C_STANDARD 11)
    ENDIF()
ENDIF()


# C++11 is the base required standard
SET (CMAKE_CXX_STANDARD 11)
SET (CMAKE_CXX_STANDARD_REQUIRED TRUE)
SET (CMAKE_CXX_EXTENSIONS OFF)

# Try to enable C++14 standard
IF (TENGINE_USE_LASTEST_CXX_STANDARD OR TENGINE_USE_LASTEST_STANDARD)
    CHECK_CXX_COMPILER_FLAG ("-std=c++14" TENGINE_ENV_HAS_CXX14)

    IF (TENGINE_ENV_HAS_CXX14)
        SET (CMAKE_CXX_STANDARD 14)
    ENDIF()

    CHECK_CXX_COMPILER_FLAG ("-std=c++17" TENGINE_ENV_HAS_CXX17)
ENDIF()
