cmake_minimum_required(VERSION 3.18)
project(moira_native LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Python3 COMPONENTS Interpreter Development.Module REQUIRED)
find_package(pybind11 CONFIG QUIET)

if(NOT pybind11_FOUND)
    execute_process(
        COMMAND "${Python3_EXECUTABLE}" -c "import pybind11; print(pybind11.get_cmake_dir())"
        RESULT_VARIABLE MOIRA_PYBIND11_DIR_RESULT
        OUTPUT_VARIABLE MOIRA_PYBIND11_DIR
        ERROR_QUIET
        OUTPUT_STRIP_TRAILING_WHITESPACE
    )

    if(MOIRA_PYBIND11_DIR_RESULT EQUAL 0 AND MOIRA_PYBIND11_DIR)
        list(PREPEND CMAKE_PREFIX_PATH "${MOIRA_PYBIND11_DIR}")
    endif()

    find_package(pybind11 CONFIG REQUIRED)
endif()

pybind11_add_module(_moira_native
    src/native/bindings/moira_native.cpp
    src/native/src/cpu_features.cpp
    src/native/src/lola.cpp
    src/native/src/nutation.cpp
)

# Keep the extension baseline portable and compile the AVX2 kernel as one
# separately dispatched translation unit.  This avoids making AVX2 a wheel-wide
# CPU requirement while still admitting it on capable x86 hosts.
include(CheckCXXCompilerFlag)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64|amd64|x86_64|X86_64|i[3-6]86)$")
    if(MSVC)
        set(MOIRA_AVX2_FLAG "/arch:AVX2")
    else()
        set(MOIRA_AVX2_FLAG "-mavx2")
    endif()
    check_cxx_compiler_flag("${MOIRA_AVX2_FLAG}" MOIRA_HAS_AVX2_COMPILE_FLAG)
    if(MOIRA_HAS_AVX2_COMPILE_FLAG)
        target_sources(_moira_native PRIVATE src/native/src/interpolation_avx2.cpp)
        set_source_files_properties(
            src/native/src/interpolation_avx2.cpp
            PROPERTIES COMPILE_OPTIONS "${MOIRA_AVX2_FLAG}"
        )
        target_compile_definitions(_moira_native PRIVATE MOIRA_NATIVE_AVX2_COMPILED=1)
    endif()
endif()

target_include_directories(_moira_native PRIVATE src/native/include)

set_target_properties(_moira_native PROPERTIES
    OUTPUT_NAME "_moira_native"
    CXX_VISIBILITY_PRESET hidden
    VISIBILITY_INLINES_HIDDEN ON
)

if(MOIRA_EXTENSION_FULL_OUTPUT_PATH)
    get_filename_component(MOIRA_EXTENSION_OUTPUT_DIR "${MOIRA_EXTENSION_FULL_OUTPUT_PATH}" DIRECTORY)

    set_target_properties(_moira_native PROPERTIES
        LIBRARY_OUTPUT_DIRECTORY "${MOIRA_EXTENSION_OUTPUT_DIR}"
        RUNTIME_OUTPUT_DIRECTORY "${MOIRA_EXTENSION_OUTPUT_DIR}"
        ARCHIVE_OUTPUT_DIRECTORY "${MOIRA_EXTENSION_OUTPUT_DIR}"
        LIBRARY_OUTPUT_DIRECTORY_RELEASE "${MOIRA_EXTENSION_OUTPUT_DIR}"
        RUNTIME_OUTPUT_DIRECTORY_RELEASE "${MOIRA_EXTENSION_OUTPUT_DIR}"
        ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${MOIRA_EXTENSION_OUTPUT_DIR}"
        LIBRARY_OUTPUT_DIRECTORY_DEBUG "${MOIRA_EXTENSION_OUTPUT_DIR}"
        RUNTIME_OUTPUT_DIRECTORY_DEBUG "${MOIRA_EXTENSION_OUTPUT_DIR}"
        ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${MOIRA_EXTENSION_OUTPUT_DIR}"
    )
endif()

find_package(OpenMP QUIET)
if(OpenMP_CXX_FOUND)
    target_link_libraries(_moira_native PRIVATE OpenMP::OpenMP_CXX)
endif()

install(TARGETS _moira_native LIBRARY DESTINATION moira RUNTIME DESTINATION moira)
