cmake_minimum_required(VERSION 3.18)
project(cudaslicer LANGUAGES C CXX CUDA)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_STANDARD 14)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)

# Cross-platform compiler settings
if(MSVC)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /O2 /W3 /MP")
    set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -O3 --use_fast_math -Xcompiler=/MD,/W3")
else()
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall -pthread -fPIC")
    set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -O3 --use_fast_math -Xcompiler -fPIC,-Wall")
endif()

# Set broad CUDA GPU architecture support (Turing, Ampere, Ada Lovelace, Hopper/Blackwell)
if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
    set(CMAKE_CUDA_ARCHITECTURES "75;80;86;89")
endif()

include_directories(
    ${CMAKE_CURRENT_SOURCE_DIR}/include
    ${CMAKE_CURRENT_SOURCE_DIR}/src
    ${CUDA_INCLUDE_DIRS}
)

# -----------------------------------------------------------------------------
# 1. Standalone C/C++ Shared Library (libcudaslicer_offset.so / cudaslicer_offset.dll)
# -----------------------------------------------------------------------------
add_library(cudaslicer_offset SHARED
    src/gpu_offset.cu
    src/cpu_offset.cpp
)
set_target_properties(cudaslicer_offset PROPERTIES
    OUTPUT_NAME "cudaslicer_offset"
    CUDA_SEPARABLE_COMPILATION OFF
)
target_compile_definitions(cudaslicer_offset PRIVATE GPU_OFFSET_EXPORTS)
target_link_libraries(cudaslicer_offset PUBLIC cudart)

# -----------------------------------------------------------------------------
# 2. Standalone C/C++ Static Library
# -----------------------------------------------------------------------------
add_library(cudaslicer_offset_static STATIC
    src/gpu_offset.cu
    src/cpu_offset.cpp
)
set_target_properties(cudaslicer_offset_static PROPERTIES
    OUTPUT_NAME "cudaslicer_offset"
    CUDA_SEPARABLE_COMPILATION OFF
)
target_link_libraries(cudaslicer_offset_static PUBLIC cudart)

# -----------------------------------------------------------------------------
# 3. C++ Benchmark Binary
# -----------------------------------------------------------------------------
add_executable(gpu_slicer_c_bench
    src/main_bench.cpp
    src/stl_slicer.cpp
)
target_link_libraries(gpu_slicer_c_bench PRIVATE cudaslicer_offset cudart)
if(UNIX)
    target_link_libraries(gpu_slicer_c_bench PRIVATE pthread)
endif()

# -----------------------------------------------------------------------------
# 4. Pybind11 Python Native Extension (_cudaslicer_backend)
# -----------------------------------------------------------------------------
if(NOT DEFINED Python3_EXECUTABLE)
    find_program(Python3_EXECUTABLE NAMES python3 python)
endif()
find_package(Python3 COMPONENTS Interpreter REQUIRED)
execute_process(
    COMMAND "${Python3_EXECUTABLE}" -c "import sysconfig; print(sysconfig.get_path('include'))"
    OUTPUT_VARIABLE _python3_include_dir
    OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
    COMMAND "${Python3_EXECUTABLE}" -c "import pybind11; print(pybind11.get_include())"
    OUTPUT_VARIABLE _pybind11_include_dir
    OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
    COMMAND "${Python3_EXECUTABLE}" -c "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX') or '.so')"
    OUTPUT_VARIABLE _ext_suffix
    OUTPUT_STRIP_TRAILING_WHITESPACE
)

add_library(_cudaslicer_backend MODULE
    python/cudaslicer/bindings.cpp
)
set_target_properties(_cudaslicer_backend PROPERTIES
    PREFIX ""
    SUFFIX "${_ext_suffix}"
)
target_include_directories(_cudaslicer_backend PRIVATE "${_python3_include_dir}" "${_pybind11_include_dir}")
target_link_libraries(_cudaslicer_backend PRIVATE cudaslicer_offset_static cudart)

# -----------------------------------------------------------------------------
# Output Directories
# -----------------------------------------------------------------------------
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
    set_target_properties(cudaslicer_offset PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib")
    set_target_properties(cudaslicer_offset_static PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib")
    set_target_properties(gpu_slicer_c_bench PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")
    set_target_properties(_cudaslicer_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/python/cudaslicer")
endif()
