set(CMAKE_SUPPRESS_REGENERATION true)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

if(MSVC)
    set(SANDBOX_WITH_EDIT_AND_CONTINUE ON CACHE BOOL "Use Program Database for Edit & Continue")
    set(SANDBOX_WITH_SECURE_COMPILER FALSE CACHE BOOL "Enable compiler-generated security checks")

    set(fastLink)
    if(NOT MSVC_VERSION LESS 1900)
        set(fastLink ":FASTLINK")
    endif()
    set(CMAKE_EXE_LINKER_FLAGS "/ignore:4221")
    # Some libraries can cause the linker to enable LTCG, so force it off. Especially important for Edit & Continue.
    set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/INCREMENTAL /DEBUG${fastLink} /LTCG:OFF")
    set(CMAKE_EXE_LINKER_FLAGS_RELWITHASSERTS "/INCREMENTAL:NO /DEBUG")
    set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/INCREMENTAL:NO /DEBUG")
    set(CMAKE_STATIC_LINKER_FLAGS "/ignore:4221")
    set(CMAKE_STATIC_LINKER_FLAGS_DEBUG "")
    set(CMAKE_STATIC_LINKER_FLAGS_RELWITHASSERTS "")
    set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "")
    set(CMAKE_SHARED_LINKER_FLAGS "/ignore:4221")
    set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "/INCREMENTAL /DEBUG${fastLink}")
    set(CMAKE_SHARED_LINKER_FLAGS_RELWITHASSERTS "/INCREMENTAL:NO /DEBUG")
    set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "/INCREMENTAL:NO /DEBUG")
    set(CMAKE_C_FLAGS "/DWIN32 /D_WINDOWS /W3 /permissive- /MP")
    set(CMAKE_C_FLAGS_DEBUG "/D_DEBUG /MTd /Zi /Od /Ob0 /RTC1 -DPLY_WITH_ASSERTS=1")
    set(CMAKE_C_FLAGS_RELWITHASSERTS "/DNDEBUG /MT /Zi /O2 /Ob1 /Oi -DPLY_WITH_ASSERTS=1")
    set(CMAKE_C_FLAGS_RELWITHDEBINFO "/DNDEBUG /MT /Zi /O2 /Ob1 /Oi")
    set(CMAKE_CXX_FLAGS "/DWIN32 /D_WINDOWS /W3 /permissive- /MP")
    if (CMAKE_GENERATOR_PLATFORM STREQUAL "Win32")
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:SSE2")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:SSE2")
    endif()
    set(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MTd /Zi /Od /Ob0 /RTC1 -DPLY_WITH_ASSERTS=1")
    set(CMAKE_CXX_FLAGS_RELWITHASSERTS "/DNDEBUG /MT /Zi /O2 /Ob1 /Oi -DPLY_WITH_ASSERTS=1")
    set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/DNDEBUG /MT /Zi /O2 /Ob1 /Oi")
    if(SANDBOX_WITH_EDIT_AND_CONTINUE)
        string(REPLACE "/Zi" "/ZI" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
        string(REPLACE "/Zi" "/ZI" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
        set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /EDITANDCONTINUE /SAFESEH:NO")
        set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /EDITANDCONTINUE /SAFESEH:NO")
    endif()
    if(NOT SANDBOX_WITH_SECURE_COMPILER)
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /GS- /D_CRT_SECURE_NO_WARNINGS=1")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GS- /D_CRT_SECURE_NO_WARNINGS=1")
    endif()
else()
    set(SANDBOX_ENABLE_CPP11 TRUE CACHE BOOL "Enable C++11 compiler support")    
    set(CMAKE_C_FLAGS "-g -Wall -fno-stack-protector -Wno-invalid-offsetof")
    set(CMAKE_CXX_FLAGS "-g -Wall -fno-stack-protector -Wno-invalid-offsetof")
    if(SANDBOX_ENABLE_CPP11)
        if(MINGW)
            set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14")
        else()
            set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
        endif()
    endif()
    if(NOT CYGWIN)   # Don't specify -pthread on Cygwin
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
    endif()
    if(APPLE)
        set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -undefined dynamic_lookup")
    endif()
    set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DPLY_WITH_ASSERTS=1")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DPLY_WITH_ASSERTS=1")
    set(CMAKE_C_FLAGS_RELWITHASSERTS "${CMAKE_C_FLAGS_RELWITHDEBINFO} -DPLY_WITH_ASSERTS=1")
    set(CMAKE_CXX_FLAGS_RELWITHASSERTS "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DPLY_WITH_ASSERTS=1")
    set(CMAKE_EXE_LINKER_FLAGS_RELWITHASSERTS "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
endif()
# Release is identical to RelWithDebInfo
# Recommendation is to delete Release configuration and stick with RelWithDebInfo
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO}")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")

macro(AddDLLCopyStep TARGET_NAME)
    foreach(DLL ${ARGN})
        add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND
            ${CMAKE_COMMAND} -E copy_if_different ${DLL} $<TARGET_FILE_DIR:${TARGET_NAME}>)
    endforeach()
endmacro()

macro(SetSourceFolders varName root)
    set(OBJECTIVE_C_EXTENSIONS .m .mm)
    foreach(relFile ${ARGN})
        set(absFile "${root}/${relFile}")
        list(APPEND "${varName}" "${absFile}")
        get_filename_component(folder "${relFile}" PATH)
        string(REPLACE / \\ folder "${folder}")
        source_group("${folder}" FILES "${absFile}")
        # Exclude objective-C files on all Unix-like platforms except MacOS, such as Linux:
        if(UNIX AND NOT APPLE)
            get_filename_component(fileExt "${absFile}" EXT)
            if(fileExt IN_LIST OBJECTIVE_C_EXTENSIONS)
                set_source_files_properties("${absFile}" PROPERTIES HEADER_FILE_ONLY TRUE)
            endif()
        endif()
    endforeach()
endmacro()

macro(SetNonParticipatingFiles varName root)
    foreach(relFile ${ARGN})
        set(absFile "${root}/${relFile}")
        get_filename_component(fileExt "${absFile}" EXT)
        # Skip natvis files on platforms that don't support them.
        if(fileExt STREQUAL ".natvis")
            if (NOT MSVC)
                continue()
            endif()
        endif()

        list(APPEND "${varName}" "${absFile}")
        get_filename_component(folder "${relFile}" PATH)
        string(REPLACE / \\ folder "${folder}")
        source_group("${folder}" FILES "${absFile}")

        # Make sure c/cpp files are not compiled.
        set(CPP_EXTENSIONS .c .cpp)
        if(NOT fileExt STREQUAL ".natvis")
            set_source_files_properties("${absFile}" PROPERTIES HEADER_FILE_ONLY TRUE)
        endif()
    endforeach()
endmacro()

macro(SetPrecompiledHeader targetName sourceListVarName generatorSource pchHeader pchFile)
    if(MSVC)
        foreach(absFile ${${sourceListVarName}})
            if(absFile STREQUAL "${generatorSource}")
                set(thisFileCompileFlags "/Yc\"${pchHeader}\" /Fp\"${pchFile}\"")
            else()
                set(thisFileCompileFlags "/Yu\"${pchHeader}\" /Fp\"${pchFile}\"")
            endif()
            # Use a CMake generator expression so that the source file's compile flags only apply
            # when used by the specified target.
            set_property(SOURCE "${absFile}" APPEND_STRING PROPERTY COMPILE_FLAGS
                "$<$<STREQUAL:$<TARGET_PROPERTY:NAME>,${targetName}>:${thisFileCompileFlags} >")
        endforeach()
    endif()
endmacro()

macro(EnableCppExceptions targetName enabled)
    if(MSVC)
        if(${enabled})
            target_compile_options(${targetName} PRIVATE /EHsc)
        else()
            target_compile_definitions(${targetName} PRIVATE _HAS_EXCEPTIONS=0)
        endif()
    else()
        if(NOT ${enabled})
            target_compile_options(${targetName} PRIVATE -fno-exceptions)
        endif()
    endif()
endmacro()

function(DisableSafeSEH targetName)
    get_property(props TARGET ${targetName} PROPERTY LINK_FLAGS)
    set(props "${props} /SAFESEH:NO")
    set_property(TARGET ${targetName} PROPERTY LINK_FLAGS "${props}")
endfunction()

if(WIN32)
    set(PLY_RUNTIME_DEPENDENCIES "ws2_32.lib")
elseif(APPLE)
    find_library(CORESERVICES_FRAMEWORK CoreServices)
    set(PLY_RUNTIME_DEPENDENCIES ${CORESERVICES_FRAMEWORK})
elseif(UNIX)
    set(PLY_RUNTIME_DEPENDENCIES "-ldl")
endif()
