CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 FATAL_ERROR)

if(POLICY CMP0063)
  cmake_policy(SET CMP0063 NEW)
endif()

INCLUDE(GNUInstallDirs)

# ---[ Options.
SET(CPUINFO_RUNTIME_TYPE "default" CACHE STRING "Type of runtime library (shared, static, or default) to use")
SET_PROPERTY(CACHE CPUINFO_RUNTIME_TYPE PROPERTY STRINGS default static shared)
SET(CPUINFO_LOG_LEVEL "default" CACHE STRING "Minimum logging level (info with lower severity will be ignored)")
SET_PROPERTY(CACHE CPUINFO_LOG_LEVEL PROPERTY STRINGS default debug info warning error fatal none)

MACRO(CPUINFO_TARGET_ENABLE_C99 target)
  IF(${CMAKE_VERSION} VERSION_LESS "3.1")
    IF(NOT MSVC)
      TARGET_COMPILE_OPTIONS(${target} PRIVATE -std=c99)
    ENDIF()
  ELSE()
    SET_TARGET_PROPERTIES(${target} PROPERTIES
      C_STANDARD 99
      C_EXTENSIONS NO)
  ENDIF()
ENDMACRO()

MACRO(CPUINFO_TARGET_ENABLE_CXX11 target)
  IF(${CMAKE_VERSION} VERSION_LESS "3.1")
    IF(NOT MSVC)
      TARGET_COMPILE_OPTIONS(${target} PRIVATE -std=c++11)
    ENDIF()
  ELSE()
    SET_TARGET_PROPERTIES(${target} PROPERTIES
      CXX_STANDARD 11
      CXX_EXTENSIONS NO)
  ENDIF()
ENDMACRO()

MACRO(CPUINFO_TARGET_RUNTIME_LIBRARY target)
  IF(MSVC AND NOT CPUINFO_RUNTIME_TYPE STREQUAL "default")
    IF(CPUINFO_RUNTIME_TYPE STREQUAL "shared")
      TARGET_COMPILE_OPTIONS(${target} PRIVATE
        "/MD$<$<CONFIG:Debug>:d>")
    ELSEIF(CPUINFO_RUNTIME_TYPE STREQUAL "static")
      TARGET_COMPILE_OPTIONS(${target} PRIVATE
        "/MT$<$<CONFIG:Debug>:d>")
    ENDIF()
  ENDIF()
ENDMACRO()

# ---[ Build flags
SET(CPUINFO_SUPPORTED_PLATFORM TRUE)
IF(NOT CMAKE_SYSTEM_PROCESSOR)
  IF(NOT IOS)
    MESSAGE(WARNING
      "Target processor architecture is not specified. "
      "cpuinfo will compile, but cpuinfo_initialize() will always fail.")
    SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
  ENDIF()
ELSEIF(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?|armv[5-8].*|aarch64|arm64)$")
  MESSAGE(WARNING
    "Target processor architecture \"${CMAKE_SYSTEM_PROCESSOR}\" is not supported in cpuinfo. "
    "cpuinfo will compile, but cpuinfo_initialize() will always fail.")
  SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
ENDIF()

IF(NOT CMAKE_SYSTEM_NAME)
    MESSAGE(WARNING
      "Target operating system is not specified. "
      "cpuinfo will compile, but cpuinfo_initialize() will always fail.")
  SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
ELSEIF(NOT CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN|MSYS|Darwin|Linux|Android)$")
  IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14" AND NOT CMAKE_SYSTEM_NAME STREQUAL "iOS")
    MESSAGE(WARNING
      "Target operating system \"${CMAKE_SYSTEM_NAME}\" is not supported in cpuinfo. "
      "cpuinfo will compile, but cpuinfo_initialize() will always fail.")
    SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
  ENDIF()
ENDIF()

# ---[ cpuinfo library
SET(CPUINFO_SRCS
  src/init.c
  src/api.c)

IF(CPUINFO_SUPPORTED_PLATFORM)
  IF(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten" AND (CMAKE_SYSTEM_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?)$" OR IOS_ARCH MATCHES "^(i386|x86_64)$"))
    LIST(APPEND CPUINFO_SRCS
      src/x86/x86_init.c
      src/x86/vendor.c
      src/x86/isa.c)
    IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
      LIST(APPEND CPUINFO_SRCS
        src/x86/linux/init.c)
    ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "iOS")
      LIST(APPEND CPUINFO_SRCS src/x86/mach/x86_mach_init.c)
    ELSEIF(CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN|MSYS)$")
      LIST(APPEND CPUINFO_SRCS src/x86/windows/init.c)
    ENDIF()
  ENDIF()

  IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
    SET(CMAKE_THREAD_PREFER_PTHREAD TRUE)
    SET(THREADS_PREFER_PTHREAD_FLAG TRUE)
    FIND_PACKAGE(Threads REQUIRED)
  ENDIF()
ENDIF()

ADD_LIBRARY(cpuinfo OBJECT ${CPUINFO_SRCS})

CPUINFO_TARGET_ENABLE_C99(cpuinfo)

INCLUDE_DIRECTORIES(deps/clog/include)

SET_PROPERTY(TARGET cpuinfo PROPERTY POSITION_INDEPENDENT_CODE ON)

CPUINFO_TARGET_RUNTIME_LIBRARY(cpuinfo)
IF(CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN|MSYS)$")
  # Target Windows 7+ API
  TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE _WIN32_WINNT=0x0601)
ENDIF()
SET_TARGET_PROPERTIES(cpuinfo PROPERTIES PUBLIC_HEADER include/cpuinfo.h)
TARGET_INCLUDE_DIRECTORIES(cpuinfo BEFORE PUBLIC include)
TARGET_INCLUDE_DIRECTORIES(cpuinfo BEFORE PRIVATE src)
IF(CPUINFO_LOG_LEVEL STREQUAL "default")
  # default logging level: error (subject to change)
  TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=2)
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "debug")
  TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=5)
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "info")
  TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=4)
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "warning")
  TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=3)
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "error")
  TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=2)
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "fatal")
  TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=1)
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "none")
  TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=0)
ELSE()
  MESSAGE(FATAL_ERROR "Unsupported logging level ${CPUINFO_LOG_LEVEL}")
ENDIF()

IF(CPUINFO_SUPPORTED_PLATFORM)
  TARGET_COMPILE_DEFINITIONS(cpuinfo INTERFACE CPUINFO_SUPPORTED_PLATFORM=1)
  IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
    TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE _GNU_SOURCE=1)
  ENDIF()
ELSE()
  TARGET_COMPILE_DEFINITIONS(cpuinfo INTERFACE CPUINFO_SUPPORTED_PLATFORM=0)
ENDIF()

# ---[ cpuinfo dependencies: clog
IF(NOT DEFINED CLOG_SOURCE_DIR)
  SET(CLOG_SOURCE_DIR "deps/clog")
ENDIF()
IF(NOT TARGET clog)
  SET(CLOG_BUILD_TESTS OFF CACHE BOOL "")
  SET(CLOG_RUNTIME_TYPE "${CPUINFO_RUNTIME_TYPE}" CACHE STRING "")
  ADD_SUBDIRECTORY(
    "${CLOG_SOURCE_DIR}")
  # We build static version of clog but a dynamic library may indirectly depend on it
  SET_PROPERTY(TARGET clog PROPERTY POSITION_INDEPENDENT_CODE ON)
ENDIF()

ADD_LIBRARY(cpuinfo_public INTERFACE)
TARGET_SOURCES(cpuinfo_public INTERFACE
    $<TARGET_OBJECTS:cpuinfo>
    $<TARGET_OBJECTS:clog>)
