cmake_minimum_required(VERSION 3.7)
project(Simd)

option(SIMD_AVX512 "AVX-512 (AVX-512F, AVX-512CD, AVX-512VL, AVX-512DQ, AVX-512BW) enable" ON)
option(SIMD_AVX512VNNI "AVX-512VNNI enable" ON)
option(SIMD_AMXBF16 "AMX-INT8, AMX-BF16 and AVX-512BF16 enable" OFF)
option(SIMD_TEST "Test framework enable" ON)
option(SIMD_INFO "Print build information" ON)
option(SIMD_PERF "Internal performance statistic" OFF)
option(SIMD_SHARED "Build as SHARED library" OFF)
option(SIMD_GET_VERSION "Get Simd Library version" ON)
option(SIMD_SYNET "Synet optimizations enable" ON)
option(SIMD_INT8_DEBUG "Synet INT8 debug enable" OFF)
option(SIMD_HIDE "Hide internal functions of Simd Library" OFF)
option(SIMD_AMX_EMULATE "AMX emulation enable" OFF)
option(SIMD_RUNTIME "Runtime faster algorithm choise enable" ON)
option(SIMD_OPENCV "OpenCV tests enable" OFF)
option(SIMD_INSTALL "Enabling of install target" ON)
option(SIMD_UNINSTALL "Enabling of uninstall target" ON)
option(SIMD_PYTHON "Enabling of Simd Python wrapper" ON)
set(MAX_ERRORS 5)

if((NOT DEFINED SIMD_ROOT) OR (SIMD_ROOT STREQUAL ""))
	set(SIMD_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../..")
endif()

if((NOT DEFINED CMAKE_BUILD_TYPE) OR (CMAKE_BUILD_TYPE STREQUAL ""))
    set(CMAKE_BUILD_TYPE "Release")
endif()

if(NOT ${SIMD_TARGET} STREQUAL "")
    set(CMAKE_SYSTEM_PROCESSOR ${SIMD_TARGET})
endif()

if(SIMD_HIDE AND SIMD_TEST)
	message("Test framework requires access to internal functions! Parameter SIMD_HIDE is ignored!")
	set(SIMD_HIDE OFF)
endif()

if(SIMD_SHARED)
    set(SIMD_LIB_TYPE "SHARED")
else()
    set(SIMD_LIB_TYPE "STATIC")
endif()

if(NOT SIMD_TOOLCHAIN STREQUAL "")
    set(CMAKE_C_COMPILER ${SIMD_TOOLCHAIN})
    set(CMAKE_CXX_COMPILER ${SIMD_TOOLCHAIN})
    execute_process(COMMAND "${CMAKE_CXX_COMPILER}" -dumpversion OUTPUT_VARIABLE CMAKE_CXX_COMPILER_VERSION)
	string(REGEX REPLACE "\n$" "" CMAKE_CXX_COMPILER_VERSION "${CMAKE_CXX_COMPILER_VERSION}")
endif()

if(SIMD_INFO)
	message("Simd Library:")
	message("Build type: '${CMAKE_BUILD_TYPE}'")
	message("Target: ${CMAKE_SYSTEM_PROCESSOR}")
	message("Library type: ${SIMD_LIB_TYPE}")
	message("Toolchain: ${CMAKE_CXX_COMPILER}")
	message("Compiler ID: ${CMAKE_CXX_COMPILER_ID}")
	message("Compiler Version: ${CMAKE_CXX_COMPILER_VERSION}")
	message("Test framework: ${SIMD_TEST}")
	message("Performance statistic: ${SIMD_PERF}")
	message("Synet: ${SIMD_SYNET}")
	message("Debug INT8: ${SIMD_INT8_DEBUG}")
	message("Hide internal: ${SIMD_HIDE}")
	message("AMX emulation: ${SIMD_AMX_EMULATE}")
	message("Runtime algorithm choise: ${SIMD_RUNTIME}")
	message("OpenCV tests: ${SIMD_OPENCV}")
	message("Install target: ${SIMD_INSTALL}")
	message("Uninstall target: ${SIMD_UNINSTALL}")
	message("Python wrapper: ${SIMD_PYTHON}")
	if(NOT ${SIMD_TEST_FLAGS} STREQUAL "")
		message("Test flags: ${SIMD_TEST_FLAGS}")
	endif()
endif()

if(UNIX AND NOT APPLE AND ((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER MATCHES "gnu")))
	execute_process(COMMAND ld -v OUTPUT_VARIABLE LD_OUTPUT)
	string(FIND ${LD_OUTPUT} " " LAST_SPACE REVERSE)
	math(EXPR VER_BEG "${LAST_SPACE} + 1")
	string(FIND ${LD_OUTPUT} "\n" LINE_END)
	math(EXPR VER_LEN "${LINE_END} - ${VER_BEG}")
	string(SUBSTRING ${LD_OUTPUT} ${VER_BEG} ${VER_LEN} BINUTILS_VERSION)
	if(SIMD_INFO)
		message("Binutils Version: ${BINUTILS_VERSION}")
	endif()
endif()

if(NOT SIMD_SYNET)
	add_definitions(-DSIMD_SYNET_DISABLE)
endif()

if(NOT SIMD_INT8_DEBUG)
	add_definitions(-DSIMD_INT8_DEBUG_DISABLE)
endif()

if(SIMD_HIDE)
	add_definitions(-DSIMD_HIDE_INTERNAL)
endif()

if(SIMD_PERF)
	add_definitions(-DSIMD_PERFORMANCE_STATISTIC)
endif()

if(SIMD_AMX_EMULATE)
	add_definitions(-DSIMD_AMX_EMULATE)
endif()

if(NOT SIMD_RUNTIME)
	add_definitions(-DSIMD_RUNTIME_DISABLE)
endif()

include_directories("${SIMD_ROOT}/src")

if(SIMD_GET_VERSION)
	if (WIN32 AND NOT (CYGWIN OR MSYS))
		string(REPLACE "/" "\\" SIMD_ROOT_WINDOWS ${SIMD_ROOT})
		execute_process(COMMAND "${SIMD_ROOT}/prj/cmd/GetVersion.cmd" "${SIMD_ROOT_WINDOWS}" "${SIMD_INFO}")
	else()
		execute_process(COMMAND bash "${SIMD_ROOT}/prj/sh/GetVersion.sh" "${SIMD_ROOT}" "${SIMD_INFO}")
	endif()
else()
	add_definitions(-DSIMD_VERSION="unknown")
endif()

string(REGEX REPLACE "(-march=[a-zA-Z0-9-]*)|(-mtune=[a-zA-Z0-9-]*)|(-msse[0-9,\\.]*)|(-mavx[a-z0-9]*)|(-mfma)|(-mamx-[a-z0-9]*)" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")

if(CMAKE_BUILD_TYPE STREQUAL "Release")
    set(COMMON_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++11 -O3")
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
	set(COMMON_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++11 -O3 -g")
elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")
    set(COMMON_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++11 -O0 -g")
else()
    message(FATAL_ERROR "Unknown value of CMAKE_BUILD_TYPE!")
endif()

if((CMAKE_CXX_COMPILER MATCHES "clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
  set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -ferror-limit=${MAX_ERRORS}")
else()
  set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -fmax-errors=${MAX_ERRORS}")
endif()

if(SIMD_HIDE)
  set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -fvisibility=hidden")
endif()

if(SIMD_TEST AND SIMD_OPENCV)
	find_package(OpenCV REQUIRED)
endif()

if(CMAKE_GENERATOR MATCHES "Visual Studio")
	if((CMAKE_GENERATOR_PLATFORM STREQUAL "x64") OR (CMAKE_GENERATOR_PLATFORM STREQUAL "x86"))
		include(x86.cmake)
	elseif((CMAKE_GENERATOR_PLATFORM STREQUAL "ARM") OR (CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64"))
		include(arm.cmake)
	else()
	    message(FATAL_ERROR "Unknown value of CMAKE_GENERATOR_PLATFORM!")
	endif()
else()
	if((CMAKE_SYSTEM_PROCESSOR STREQUAL "i686") OR (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64"))
		include(x86.cmake)
	elseif((CMAKE_SYSTEM_PROCESSOR MATCHES "arm") OR (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64"))
		include(arm.cmake)
	else()
	    message(FATAL_ERROR "Unknown value of CMAKE_SYSTEM_PROCESSOR!")
	endif()
endif()

if(SIMD_PYTHON)
	add_custom_command(TARGET Simd POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy 
		${SIMD_ROOT}/py/SimdPy/Simd.py ${CMAKE_BINARY_DIR})
	if(SIMD_TEST)
		add_custom_command(TARGET Test POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy 
			${SIMD_ROOT}/py/SimdPy/Test.py ${CMAKE_BINARY_DIR})
	endif()
endif()

if(SIMD_INSTALL)
	file(GLOB_RECURSE SIMD_LIB_HPP ${SIMD_ROOT}/src/Simd/Simd*.hpp)
	set_target_properties(Simd PROPERTIES PUBLIC_HEADER "${SIMD_ROOT}/src/Simd/SimdLib.h;${SIMD_LIB_HPP}")
	install(TARGETS Simd EXPORT simdtargets 
		LIBRARY DESTINATION "lib" 
		ARCHIVE DESTINATION "lib" 
		PUBLIC_HEADER DESTINATION "include/Simd")
	install(EXPORT simdtargets DESTINATION share/simd)
endif()

if(SIMD_UNINSTALL)
	add_custom_target("uninstall")
	add_custom_command(TARGET "uninstall" POST_BUILD COMMENT "Uninstall Simd Library..."
		COMMAND cat install_manifest.txt | sudo xargs rm -v
		COMMAND cat install_manifest.txt | xargs -L1 dirname | grep '/[Ss]imd' | uniq | sudo xargs rmdir -v)
endif()
