cmake_minimum_required(VERSION 3.18 FATAL_ERROR)

if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
    set(CMAKE_CUDA_ARCHITECTURES 60 70 75 80 90)
endif()

project(user-material-models LANGUAGES CXX CUDA)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(CMAKE_CUDA_STANDARD 17)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_EXTENSIONS OFF)

find_package(CUDAToolkit REQUIRED)

set(UMAT_BINARY_STEM "IMPETUS example user material")
set(UMAT_OUTPUT_DIR "${CMAKE_BINARY_DIR}/deliverables" CACHE PATH "Directory for compiled example user material libraries")

set(UMAT_MANIFEST_JSON ${CMAKE_CURRENT_SOURCE_DIR}/user-material/manifest.json)
set(UMAT_MANIFEST_GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/tools/embed_umat_manifest.cmake)
set(UMAT_MANIFEST_EMBEDDED_CPP ${CMAKE_CURRENT_BINARY_DIR}/generated/umat_manifest_embedded.cpp)
set(UMAT_DOCUMENTATION_XML "${CMAKE_CURRENT_SOURCE_DIR}/doc/${UMAT_BINARY_STEM}.xml")

add_custom_command(
    OUTPUT ${UMAT_MANIFEST_EMBEDDED_CPP}
    COMMAND "${CMAKE_COMMAND}"
            -DINPUT=${UMAT_MANIFEST_JSON}
            -DOUTPUT=${UMAT_MANIFEST_EMBEDDED_CPP}
            -P ${UMAT_MANIFEST_GENERATOR}
    DEPENDS ${UMAT_MANIFEST_JSON} ${UMAT_MANIFEST_GENERATOR}
    COMMENT "Embedding UMAT manifest JSON"
    VERBATIM
)

file(GLOB CPP_FILES user-material/*.cpp user-material/*.h user-material/*.cu)
set(SOURCES ${CPP_FILES} ${UMAT_MANIFEST_EMBEDDED_CPP})

add_library(user-material-models SHARED ${SOURCES})
target_include_directories(user-material-models PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/user-material
    ${CUDAToolkit_INCLUDE_DIRS}
)

target_link_libraries(user-material-models PRIVATE CUDA::cudart)

set_target_properties(user-material-models PROPERTIES
    OUTPUT_NAME "${UMAT_BINARY_STEM}"
    PREFIX ""
    CUDA_RUNTIME_LIBRARY Shared
    CUDA_SEPARABLE_COMPILATION ON
    CUDA_RESOLVE_DEVICE_SYMBOLS ON
    POSITION_INDEPENDENT_CODE ON
    RUNTIME_OUTPUT_DIRECTORY "${UMAT_OUTPUT_DIR}"
    LIBRARY_OUTPUT_DIRECTORY "${UMAT_OUTPUT_DIR}"
    ARCHIVE_OUTPUT_DIRECTORY "${UMAT_OUTPUT_DIR}/lib"
)

foreach(config Debug Release RelWithDebInfo MinSizeRel)
    string(TOUPPER "${config}" config_upper)
    set_target_properties(user-material-models PROPERTIES
        RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${UMAT_OUTPUT_DIR}/${config}"
        LIBRARY_OUTPUT_DIRECTORY_${config_upper} "${UMAT_OUTPUT_DIR}/${config}"
        ARCHIVE_OUTPUT_DIRECTORY_${config_upper} "${UMAT_OUTPUT_DIR}/${config}/lib"
    )
endforeach()

target_compile_definitions(user-material-models PRIVATE
    _USE_MATH_DEFINES
    $<$<CXX_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS>
    $<$<PLATFORM_ID:Windows>:WIN32;WIN64>
)

add_custom_command(TARGET user-material-models POST_BUILD
    COMMAND "${CMAKE_COMMAND}" -E copy_if_different
            "${UMAT_DOCUMENTATION_XML}"
            "$<TARGET_FILE_DIR:user-material-models>/${UMAT_BINARY_STEM}.xml"
    COMMENT "Copying UMAT XML documentation"
    VERBATIM
)

install(TARGETS user-material-models
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
)

install(FILES "${UMAT_DOCUMENTATION_XML}" DESTINATION bin)

message(STATUS "Building ${UMAT_BINARY_STEM} as a shared library with C++ and CUDA")
