
#
# This source file is part of appleseed.
# Visit https://appleseedhq.net/ for additional information and resources.
#
# This software is released under the MIT license.
#
# Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
# Copyright (c) 2014-2018 Francois Beaune, The appleseedhq Organization
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#


#--------------------------------------------------------------------------------------------------
# Microsoft Visual Studio on Windows.
#--------------------------------------------------------------------------------------------------

set (platform "win-vs")


#--------------------------------------------------------------------------------------------------
# Preprocessor definitions.
#--------------------------------------------------------------------------------------------------

# Definitions common to all configurations.
set (preprocessor_definitions_common
    WIN32
    _CRT_SECURE_NO_WARNINGS
    _SCL_SECURE_NO_WARNINGS
    _USRDLL
    _WINDOWS
    XERCES_STATIC_LIBRARY                   # link statically against Xerces-C
    BOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE  # turn off "Boost.Config is older than your compiler version" warnings
)
if (USE_STATIC_BOOST)
    set (preprocessor_definitions_common
        ${preprocessor_definitions_common}
        BOOST_PYTHON_STATIC_LIB             # link statically against Boost.Python
    )
else ()
    set (preprocessor_definitions_common
        ${preprocessor_definitions_common}
        BOOST_ALL_DYN_LINK                  # link dynamically
    )
endif ()
if (NOT USE_STATIC_EXR)
    set (preprocessor_definitions_common
        ${preprocessor_definitions_common}
        OPENEXR_DLL                         # we need to set this pre-processor for OpenEXR to link correctly when the lib is dynamic
    )
endif ()

# Release configuration.
set (preprocessor_definitions_release
    _SECURE_SCL=0
)


#--------------------------------------------------------------------------------------------------
# Compilation/linking flags.
#--------------------------------------------------------------------------------------------------

# Flags common to all configurations.
set (c_compiler_flags_common
    /MP                                     # Multi-processor Compilation
    /GF                                     # Enable String Pooling
)
set (cxx_compiler_flags_common
    /wd4068                                 # Disable warning C4068: unknown pragma
    /wd4091                                 # Disable warning C4091: 'typedef' : ignored on left of X when no variable is declared
    /wd4290                                 # Disable warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
    /wd4345                                 # Disable warning C4345: behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized
    /wd4355                                 # Disable warning C4355: 'this' : used in base member initializer list
    /wd4503                                 # Disable warning C4503: decorated name length exceeded, name was truncated
)
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
    set (c_compiler_flags_common
        ${c_compiler_flags_common}
        /bigobj                             # Increase Number of Sections in .Obj file
    )
endif ()
set (shared_lib_linker_flags_common
    ${exe_linker_flags_common}
)

# Debug configuration.
set (c_compiler_flags_debug
    ${c_compiler_flags_debug}
    /WX                                     # Treat Warnings As Errors
    /MDd                                    # set Runtime Library to Multi-threaded Debug DLL
)
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
    set (c_compiler_flags_debug
        ${c_compiler_flags_debug}
        /Zi                                 # set Debug Information Format to Program Database
    )
else ()
    set (c_compiler_flags_debug
        ${c_compiler_flags_debug}
        /ZI                                 # set Debug Information Format to Program Database for Edit & Continue
    )
endif ()

# Release configuration.
set (c_compiler_flags_release
    /WX                                     # Treat Warnings As Errors
    /Zi                                     # set Debug Information Format to Program Database
    /O2                                     # Maximum Optimization (Favor Speed)
    /Ob2                                    # set Inline Function Expansion to Any Suitable
    /Oi                                     # Enable Intrinsic Functions
    /Ot                                     # Favor Fast Code
    /Oy                                     # Omit Frame Pointers
    /MD                                     # set Runtime Library to Multi-threaded DLL
    /GS-                                    # set Buffer Security Check to No
)
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
    set (c_compiler_flags_release
        ${c_compiler_flags_release}
        /fp:fast                            # set Floating Point Model to Fast, in 32-bit builds only because of a bug in VS 2010-2013:
    )                                       # http://stackoverflow.com/questions/15786606/vc-optimisations-break-comparisons-with-nan
    if (USE_SSE)
        set (c_compiler_flags_release
            ${c_compiler_flags_release}
            /arch:SSE2                      # Streaming SIMD Extensions 2 (always enabled in 64-bit builds)
        )
    endif ()
endif ()
if (USE_AVX)
    set (c_compiler_flags_release
        ${c_compiler_flags_release}
        /arch:AVX                           # Advanced Vector Extensions
    )
endif ()
if (USE_AVX2)
    set (c_compiler_flags_release
        ${c_compiler_flags_release}
        /arch:AVX2                          # Advanced Vector Extensions 2
    )
endif ()
set (exe_linker_flags_release
    /DEBUG                                  # Generate Debug Info
    /OPT:REF                                # Eliminate Unreferenced Data
    /OPT:ICF                                # Remove Redundant COMDATs
)
set (shared_lib_linker_flags_release
    ${exe_linker_flags_release}
)

# Ship configuration.
set (c_compiler_flags_ship
    /WX-                                    # Disable Treat Warnings As Errors
    /GL                                     # Enable link-time code generation
)
set (exe_linker_flags_ship
    /DEBUG:NONE                             # Undo 'Generate Debug Info' set in Release configuration
    /LTCG                                   # Use Link Time Code Generation
    /INCREMENTAL:NO                         # Disable Incremental Linking
)
set (shared_lib_linker_flags_ship
    ${exe_linker_flags_ship}
)
set (static_lib_linker_flags_ship
    /LTCG                                   # Use Link Time Code Generation
)

# Profile configuration.
set (c_compiler_flags_profile
    /WX-                                    # Disable Treat Warnings As Errors
    /GL                                     # Enable link-time code generation
)
set (exe_linker_flags_profile
    /DEBUG                                  # Generate Debug Info
    /LTCG                                   # Use Link Time Code Generation
    /INCREMENTAL:NO                         # Disable Incremental Linking
)
set (shared_lib_linker_flags_profile
    ${exe_linker_flags_profile}
)
set (static_lib_linker_flags_profile
    /LTCG                                   # Use Link Time Code Generation
)


#--------------------------------------------------------------------------------------------------
# Libraries.
#--------------------------------------------------------------------------------------------------

macro (link_against_platform target)
endmacro ()

macro (link_against_embree target)
    if (USE_FIND_PACKAGE_FOR_EMBREE)
        target_link_libraries (${target} ${EMBREE_LIBRARIES})
    else ()
        target_link_libraries (${target}
            # Order matters here.
            # See appleseed-deps\src\embree\readme.pdf, section 3.3 CMake Configuration for details.
            debug       ${APPLESEED_DEPS_STAGE_DIR}/embree-debug/lib/lexers.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/embree-debug/lib/math.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/embree-debug/lib/simd.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/embree-debug/lib/sys.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/embree-debug/lib/tasking.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/embree-debug/lib/embree3.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/embree-debug/lib/embree_sse42.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/embree-debug/lib/embree_avx.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/embree-debug/lib/embree_avx2.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/embree-release/lib/lexers.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/embree-release/lib/math.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/embree-release/lib/simd.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/embree-release/lib/sys.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/embree-release/lib/tasking.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/embree-release/lib/embree3.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/embree-release/lib/embree_sse42.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/embree-release/lib/embree_avx.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/embree-release/lib/embree_avx2.lib
        )
    endif ()
endmacro ()

macro (link_against_lz4 target)
    if (USE_FIND_PACKAGE_FOR_LZ4)
        target_link_libraries (${target} ${LZ4_LIBRARY})
    else ()
        target_link_libraries (${target}
            debug       ${APPLESEED_DEPS_STAGE_DIR}/lz4-debug/lib/lz4.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/lz4-release/lib/lz4.lib
        )
    endif ()
endmacro ()

macro (link_against_ocio target)
    if (USE_FIND_PACKAGE_FOR_OCIO)
        target_link_libraries (${target}
            ${OPENCOLORIO_LIBRARIES}
        )
    else ()
        target_link_libraries (${target}
            debug       ${APPLESEED_DEPS_STAGE_DIR}/ocio-debug/lib/OpenColorIO.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/ocio-debug/lib/libyaml-cppmdd.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/ocio-debug/lib/tinyxml.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/ocio-release/lib/OpenColorIO.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/ocio-release/lib/libyaml-cppmd.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/ocio-release/lib/tinyxml.lib
        )
    endif ()
endmacro ()

macro (link_against_oiio target)
    if (USE_FIND_PACKAGE_FOR_OIIO)
        target_link_libraries (${target}
            ${LIBJPEG_LIBRARY}
            ${LIBTIFF_LIBRARY}
            ${OPENIMAGEIO_LIBRARIES}
            ${PNG_LIBRARIES}
        )
    else ()
        target_link_libraries (${target}
            debug       ${APPLESEED_DEPS_STAGE_DIR}/libjpeg-turbo-debug/lib/jpeg-static.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/libpng-debug/lib/libpng16_staticd.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/libtiff-debug/lib/libtiff.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/oiio-debug/lib/OpenImageIO.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/oiio-debug/lib/OpenImageIO_Util.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/libjpeg-turbo-release/lib/jpeg-static.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/libpng-release/lib/libpng16_static.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/libtiff-release/lib/libtiff.lib
            optimized   $<IF:$<OR:$<CONFIG:Profile>,$<CONFIG:Ship>>,${APPLESEED_DEPS_STAGE_DIR}/oiio-ship/lib/OpenImageIO.lib,${APPLESEED_DEPS_STAGE_DIR}/oiio-release/lib/OpenImageIO.lib>
            optimized   $<IF:$<OR:$<CONFIG:Profile>,$<CONFIG:Ship>>,${APPLESEED_DEPS_STAGE_DIR}/oiio-ship/lib/OpenImageIO_Util.lib,${APPLESEED_DEPS_STAGE_DIR}/oiio-release/lib/OpenImageIO_Util.lib>
        )
    endif ()
endmacro ()

macro (link_against_openexr target)
    if (USE_FIND_PACKAGE_FOR_EXR)
        target_link_libraries (${target}
            ${IMATH_LIBRARIES}
            ${OPENEXR_LIBRARIES}
        )
    else ()
        target_link_libraries (${target}
            debug       ${APPLESEED_DEPS_STAGE_DIR}/ilmbase-debug/lib/Half.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/ilmbase-debug/lib/Iex-2_2.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/ilmbase-debug/lib/IlmThread-2_2.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/ilmbase-debug/lib/Imath-2_2.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/openexr-debug/lib/IlmImf-2_2.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/ilmbase-release/lib/Half.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/ilmbase-release/lib/Iex-2_2.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/ilmbase-release/lib/IlmThread-2_2.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/ilmbase-release/lib/Imath-2_2.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/openexr-release/lib/IlmImf-2_2.lib
        )
    endif ()
endmacro ()

macro (link_against_osl target)
    set (LLVM_LIBS
        LLVMAggressiveInstCombine LLVMAnalysis LLVMAsmParser LLVMAsmPrinter LLVMBinaryFormat LLVMBitReader
        LLVMBitWriter LLVMCodeGen LLVMCore LLVMCoroutines LLVMCoverage LLVMDebugInfoCodeView LLVMDebugInfoDWARF
        LLVMDebugInfoMSF LLVMDebugInfoPDB LLVMDemangle LLVMDlltoolDriver LLVMExecutionEngine LLVMFuzzMutate
        LLVMGlobalISel LLVMInstCombine LLVMInstrumentation LLVMInterpreter LLVMipo LLVMIRReader LLVMLibDriver
        LLVMLineEditor LLVMLinker LLVMLTO LLVMMC LLVMMCA LLVMMCDisassembler LLVMMCJIT LLVMMCParser LLVMMIRParser
        LLVMObjCARCOpts LLVMObject LLVMObjectYAML LLVMOption LLVMOptRemarks LLVMOrcJIT LLVMPasses LLVMProfileData
        LLVMRuntimeDyld LLVMScalarOpts LLVMSelectionDAG LLVMSupport LLVMSymbolize LLVMTableGen LLVMTarget
        LLVMTextAPI LLVMTransformUtils LLVMVectorize LLVMWindowsManifest LLVMX86AsmParser LLVMX86AsmPrinter
        LLVMX86CodeGen LLVMX86Desc LLVMX86Disassembler LLVMX86Info LLVMX86Utils LLVMXRay
    )

    if (USE_FIND_PACKAGE_FOR_OSL)
        target_link_libraries (${target}
            ${OSL_COMP_LIBRARY}
            ${OSL_EXEC_LIBRARY}
            ${OSL_NOISE_LIBRARY}
            ${OSL_QUERY_LIBRARY}
        )
        foreach (lib ${LLVM_LIBS})
            target_link_libraries (${target} "${LLVM_LIBS_DIR}/${lib}.lib")
        endforeach ()
    else ()
        target_link_libraries (${target}
            debug       ${APPLESEED_DEPS_STAGE_DIR}/osl-debug/lib/oslcomp.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/osl-debug/lib/oslexec.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/osl-debug/lib/oslnoise.lib
            debug       ${APPLESEED_DEPS_STAGE_DIR}/osl-debug/lib/oslquery.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/osl-release/lib/oslcomp.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/osl-release/lib/oslexec.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/osl-release/lib/oslnoise.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/osl-release/lib/oslquery.lib
        )
        foreach (lib ${LLVM_LIBS})
            target_link_libraries (${target}
                debug       ${APPLESEED_DEPS_STAGE_DIR}/llvm-debug/lib/${lib}.lib
                optimized   ${APPLESEED_DEPS_STAGE_DIR}/llvm-release/lib/${lib}.lib
            )
        endforeach ()
    endif ()
endmacro ()

macro (link_against_xercesc target)
    if (USE_FIND_PACKAGE_FOR_XERCES)
        target_link_libraries (${target} ${XERCES_LIBRARIES})
    else ()
        target_link_libraries (${target}
            debug       ${APPLESEED_DEPS_STAGE_DIR}/xerces-c-debug/lib/xerces-c_3D.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/xerces-c-release/lib/xerces-c_3.lib
        )
    endif ()
endmacro ()

macro (link_against_zlib target)
    if (USE_FIND_PACKAGE_FOR_ZLIB)
        target_link_libraries (${target} ${ZLIB_LIBRARIES})
    else ()
        target_link_libraries (${target}
            debug       ${APPLESEED_DEPS_STAGE_DIR}/zlib-debug/lib/zlibstaticd.lib
            optimized   ${APPLESEED_DEPS_STAGE_DIR}/zlib-release/lib/zlibstatic.lib
        )
    endif ()
endmacro ()


#--------------------------------------------------------------------------------------------------
# Copy a target binary to the sandbox.
#--------------------------------------------------------------------------------------------------

macro (get_sandbox_bin_path path)
    slashes_to_backslashes (${path} ${PROJECT_SOURCE_DIR})
    set (${path} ${${path}}\\sandbox\\bin\\vc$(PlatformToolsetVersion)\\$(ConfigurationName))
endmacro ()

macro (get_sandbox_lib_path path)
    slashes_to_backslashes (${path} ${PROJECT_SOURCE_DIR})
    set (${path} ${${path}}\\sandbox\\lib\\vc$(PlatformToolsetVersion)\\$(ConfigurationName))
endmacro ()

macro (get_sandbox_py_path path)
    get_sandbox_lib_path (${path})
    set (${path} ${${path}}\\python)
endmacro ()

macro (get_relative_path_from_module_name path name)
    string (REPLACE "." "\\" ${path} ${name})
endmacro ()

macro (add_copy_target_exe_to_sandbox_command target)
    get_sandbox_bin_path (bin_path)

    # Copy the .exe and the PDB file (except in Ship configuration).
    add_custom_command (TARGET ${target} POST_BUILD
        COMMAND if not exist "${bin_path}" mkdir "${bin_path}"
        COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${target}> "${bin_path}"
        COMMAND if not $<CONFIG> == "Ship" ${CMAKE_COMMAND} -E copy "$<TARGET_PDB_FILE:${target}>" "${bin_path}"
    )
endmacro ()

macro (add_copy_target_lib_to_sandbox_command target)
    # Copy the DLL and the PDB file (except in Ship configuration).
    get_sandbox_bin_path (bin_path)
    add_custom_command (TARGET ${target} POST_BUILD
        COMMAND if not exist "${bin_path}" mkdir "${bin_path}"
        COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${target}> "${bin_path}"
        COMMAND if not $<CONFIG> == "Ship" ${CMAKE_COMMAND} -E copy "$<TARGET_PDB_FILE:${target}>" "${bin_path}"
    )

    # Copy the import library.
    get_sandbox_lib_path (lib_path)
    add_custom_command (TARGET ${target} POST_BUILD
        COMMAND if not exist "${lib_path}" mkdir "${lib_path}"
        COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_LINKER_FILE:${target}>" "${lib_path}"
    )
endmacro ()

macro (add_copy_target_to_sandbox_py_module_command target module_name)
    get_sandbox_py_path (py_path)
    get_relative_path_from_module_name (relative_module_path ${module_name})
    set (module_path "${py_path}\\${relative_module_path}")

    add_custom_command (TARGET ${target} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E make_directory "${module_path}"
        COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${target}> "${module_path}"
    )
endmacro ()

macro (add_copy_py_file_to_sandbox_py_module_command py_src module_name)
    get_sandbox_py_path (py_path)
    get_relative_path_from_module_name (relative_module_path ${module_name})
    set (module_path "${py_path}\\${relative_module_path}")

    add_custom_command (TARGET appleseed.python.copy_py_files POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E make_directory "${module_path}"
        COMMAND ${CMAKE_COMMAND} -E copy "${py_src}" "${module_path}"
    )
endmacro ()

macro (add_copy_dir_to_sandbox_py_module_command py_dir module_name)
    get_sandbox_py_path (py_path)
    get_relative_path_from_module_name (relative_module_path ${module_name})
    set (module_path "${py_path}\\${relative_module_path}")

    add_custom_command (TARGET appleseed.python.copy_py_files POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E make_directory "${module_path}"
        COMMAND ${CMAKE_COMMAND} -E copy_directory "${py_dir}" "${module_path}"
    )
endmacro ()

macro (add_copy_studio_py_file_to_sandbox_py_module_command py_src module_name)
    get_sandbox_py_path (py_path)
    get_relative_path_from_module_name (relative_module_path ${module_name})
    set (module_path "${py_path}\\${relative_module_path}")

    add_custom_command (TARGET appleseed.studio.copy_py_files POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E make_directory "${module_path}"
        COMMAND ${CMAKE_COMMAND} -E copy "${py_src}" "${module_path}"
    )
endmacro ()
