cmake_minimum_required(VERSION 3.15)

project(opynsim VERSION 0.0.6 LANGUAGES CXX C)

option(BUILD_TESTING                          "Build test suites"                                                  ON)
option(OPYN_BUILD_DOCS                        "Build documentation"                                                OFF)
option(OPYN_BUILD_HELLOOSCAR                  "Build hellooscar executable"                                        ON)
option(OPYN_BUILD_OPYNSIM_DEBUGGER            "Build the opynsim_debugger target"                                  OFF)
option(OPYN_BUILD_OSCAR_DEMOS                 "Build demo suite"                                                   ON)
option(OPYN_BUILD_PYTHON_BINDINGS             "Build Python bindings for libopynsim"                               ON)
option(OPYN_BUILD_TESTING                     "Build test suites (OPynSim-specific)"                               ${BUILD_TESTING})
option(OPYN_BUILD_PYTHON_TESTING              "Build python test suites"                                           ${OPYN_BUILD_TESTING})
option(OPYN_EMSCRIPTEN                        "Enable special build parameters for emscripten (emsdk)"             OFF)
option(OPYN_FORCE_ASSERTS_ENABLED             "Enable OSC's runtime assertions - even if building a release build" ON)
option(OPYN_PACKAGE                           "Configure packaging the project's targets"                          ON)
option(OPYN_RUNTIME_PERF_MEASUREMENTS_ENABLED "Enable whether the `OSC_PERF` macro records performance or not"     ON)
option(OPYN_STABLE_ABI                        "Perform a python stable ABI build"                                  ON)
option(OPYN_STRICT_ABI_CHECKS                 "Check OPynSim has specified ABI"                                    ${OPYN_STABLE_ABI})
option(OPYN_USE_STRICT_COMPILER_FLAGS         "Add stricter compilation flags to targets"                          OFF)
set   (OPYN_VENV "" CACHE PATH                "Optional path to a Python virtual environment the build should use")

# Configure Python (if necessary)
if(OPYN_BUILD_PYTHON_BINDINGS OR OPYN_BUILD_DOCS)
    if(OPYN_VENV)
        include(cmake/opynsim_set_python_executable_to_venv.cmake)
        opyn_set_python_executable_to_venv("${OPYN_VENV}")
    endif()

    # Figure out required Python components
    set(OPYN_REQUIRED_PYTHON_COMPONENTS Interpreter Development.Module)
    if(OPYN_STABLE_ABI)
        set(OPYN_MIN_PYTHON_REQUIRED_VERSION 3.12)  # Minimum version for SABI is dictated by nanobind
        list(APPEND OPYN_REQUIRED_PYTHON_COMPONENTS Development.SABIModule)
    else()
        set(OPYN_MIN_PYTHON_REQUIRED_VERSION 3.8)   # Minimum version dictated by Python source code feature usage
    endif()
    if(OPYN_BUILD_OPYNSIM_DEBUGGER)
        list(APPEND OPYN_REQUIRED_PYTHON_COMPONENTS Development.Embed)
    endif()

    # Finally, find a Python distribution that matches the requirements.
    find_package(
        Python ${OPYN_MIN_PYTHON_REQUIRED_VERSION}
        COMPONENTS ${OPYN_REQUIRED_PYTHON_COMPONENTS}
        REQUIRED
    )

    if(OPYN_STRICT_ABI_CHECKS)
        if((NOT Python_VERSION_MAJOR EQUAL 3) OR (NOT Python_VERSION_MINOR EQUAL 12))
            message(FATAL_ERROR "When OPYN_STRICT_ABI_CHECKS is ON, the Python version MUST be 3.12.x (yours is ${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}), so that the resulting ABI is valid for >= 3.12 clients.\nOne way to fix this is to create a 3.12 venv and pass it via OPYN_VENV, or use cmake Python hints like Python_ROOT_DIR\n\nOn Windows, you can even do this by creating the environment with something like `py -3.12 -m venv .venv && call .venv/Scripts/activate.bat && py -3.12 pip install -r requirements/all_requirements.txt`.")
        endif()
    endif()
endif()

if(OPYN_BUILD_TESTING)
    # This has to be done at the top-level, so that `ctest --show-only` works for
    # all test suites. It is how IDEs typically detect tests.
    #
    # `include(CTest)` isn't used because we don't want extra targets (e.g. `Continuous`).
    enable_testing()
endif()

add_subdirectory(liboscar)
if(OPYN_BUILD_OSCAR_DEMOS)
    add_subdirectory(liboscar-demos)
    add_subdirectory(oscar_demo_viewer)
endif()
if(OPYN_BUILD_HELLOOSCAR)
    add_subdirectory(hellooscar)
endif()

add_subdirectory(libosim SYSTEM)  # SYSTEM because it's all third-party code
add_subdirectory(libopynsim)

if(OPYN_BUILD_PYTHON_BINDINGS)
    add_subdirectory(src)
    if(OPYN_BUILD_PYTHON_TESTING)
        add_subdirectory(tests)
    endif()
    if(OPYN_BUILD_OPYNSIM_DEBUGGER)
        add_subdirectory(opynsim_debugger)
    endif()
endif()

if(OPYN_BUILD_DOCS)
    add_subdirectory(docs)
endif()

if(OPYN_PACKAGE)
    add_subdirectory(packaging)
endif()
