cmake_minimum_required(VERSION 3.18)
project(maxwell_core LANGUAGES CXX CUDA)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Find Python and Pybind11
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)

execute_process(
    COMMAND ${Python3_EXECUTABLE} -m pybind11 --includes
    OUTPUT_VARIABLE PYBIND11_INCLUDES
    OUTPUT_STRIP_TRAILING_WHITESPACE
)

string(REPLACE "-I" "" PYBIND11_INCLUDES "${PYBIND11_INCLUDES}")
string(REPLACE " " ";" PYBIND11_INCLUDES "${PYBIND11_INCLUDES}")

set(SRC_FILES
    src/maxwell_wrapper.cpp
)

add_library(maxwell_core SHARED ${SRC_FILES} src/cuda/maxwell_cuda.cu)

target_include_directories(maxwell_core PRIVATE 
    ${CMAKE_CURRENT_SOURCE_DIR}/src
    ${PYBIND11_INCLUDES}
)

find_package(CUDAToolkit REQUIRED)

set(CMAKE_CUDA_ARCHITECTURES "native" "61" "75" "86")

set_target_properties(maxwell_core PROPERTIES
    CUDA_SEPARABLE_COMPILATION ON
    PREFIX ""
    SUFFIX ".${Python3_SOABI}.pyd"
)

target_compile_definitions(maxwell_core PRIVATE MAXWELL_CUDA)

target_compile_options(maxwell_core PRIVATE 
    $<$<COMPILE_LANGUAGE:CUDA>:-O3>
    $<$<COMPILE_LANGUAGE:CUDA>:--use_fast_math>
    $<$<COMPILE_LANGUAGE:CUDA>:-Xptxas=-v>
    $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>:/arch:AVX2>
)

find_package(OpenMP COMPONENTS CXX REQUIRED)
target_link_libraries(maxwell_core PRIVATE OpenMP::OpenMP_CXX)

target_link_libraries(maxwell_core PRIVATE CUDA::cudart_static Python3::Module)

# Remove explicit output name to let CMake handle it based on target name?
# Or keep it but ensure setup.py expects it.
# setup.py expects 'oxs.maxwell_core'.
# This means it expects 'maxwell_core.pyd' inside 'oxs/' package.
set_target_properties(maxwell_core PROPERTIES
    OUTPUT_NAME "maxwell_core"
)
