cmake_minimum_required(VERSION 3.16)
project(vmsig C)

set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)               # epoll/eventfd/timerfd/clock_gettime: gnu ext
option(VMSIG_LTO "Enable LTO" OFF)

# Link the real sibling libraries (their .a, built with -fPIC). By default the spine
# builds against headers only: the SI calls are hidden behind these flags, and the
# stub mode proves the seam without a real VM.
option(VMSIG_WITH_VMIE  "Link real vmie (libvmie.a, PIC) for armed memctx" OFF)
option(VMSIG_WITH_VMCTL "Link real vmctl (libvmctl.a, PIC) for armed input" OFF)

# ---- Sibling library sources (set these to your local checkouts) ------------
# Only needed for the armed builds below; the default stub build needs neither.
set(LIBVMIE_PATH  "" CACHE PATH "Path to the vmie library sources (for VMSIG_WITH_VMIE)")
set(LIBVMCTL_PATH "" CACHE PATH "Path to the vmctl library sources (for VMSIG_WITH_VMCTL)")

find_package(Threads REQUIRED)

# ---- signaling library ------------------------------------------------------
add_library(vmsig SHARED
        src/core/core.c
        src/core/linux/loop.c
        src/ctx/ctx.c
        src/adapter/linux/worker.c
        src/adapter/memctx/memctx.c
        src/adapter/input/input.c
        src/adapter/vmhost/vmhost.c
        src/control/inproc.c
        src/control/socket.c)

target_include_directories(vmsig
        PUBLIC  ${CMAKE_CURRENT_SOURCE_DIR}/include
        PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/core/include
                ${CMAKE_CURRENT_SOURCE_DIR}/src/ctx/include
                ${CMAKE_CURRENT_SOURCE_DIR}/src/adapter/include
                ${CMAKE_CURRENT_SOURCE_DIR}/src/adapter/memctx/include
                ${CMAKE_CURRENT_SOURCE_DIR}/src/adapter/input/include
                ${CMAKE_CURRENT_SOURCE_DIR}/src/adapter/vmhost/include)

target_link_libraries(vmsig PRIVATE Threads::Threads)

# armed: the real vmie as a pre-built PIC .a (IMPORTED) — headers and symbols.
if(VMSIG_WITH_VMIE)
    add_library(vmie STATIC IMPORTED)
    set_target_properties(vmie PROPERTIES
            IMPORTED_LOCATION             ${LIBVMIE_PATH}/.build/libvmie.a
            INTERFACE_INCLUDE_DIRECTORIES ${LIBVMIE_PATH}/include)
    target_link_libraries(vmsig PRIVATE vmie)
    target_compile_definitions(vmsig PRIVATE VMSIG_WITH_VMIE)
endif()

# armed: the real vmctl as a pre-built PIC .a (IMPORTED).
if(VMSIG_WITH_VMCTL)
    add_library(vmctl STATIC IMPORTED)
    set_target_properties(vmctl PROPERTIES
            IMPORTED_LOCATION             ${LIBVMCTL_PATH}/.build/libvmctl.a
            INTERFACE_INCLUDE_DIRECTORIES ${LIBVMCTL_PATH}/include)
    target_link_libraries(vmsig PRIVATE vmctl)
    target_compile_definitions(vmsig PRIVATE VMSIG_WITH_VMCTL)
endif()

target_compile_options(vmsig PRIVATE -O2 -Wall -Wextra)
if(VMSIG_LTO)
    target_compile_options(vmsig PRIVATE -flto)
    target_link_options(vmsig PRIVATE -flto)
endif()

# ---- demonstrator on top of the library (like vmie_cli / vmctl) -------------
add_executable(vmsig_cli src/cli.c)
target_link_libraries(vmsig_cli PRIVATE vmsig)
target_compile_options(vmsig_cli PRIVATE -Wall -Wextra)

# ---- transfer-context tests (ctest) -----------------------------------------
enable_testing()
add_executable(vmsig_test src/test/test_ctx.c)
target_link_libraries(vmsig_test PRIVATE vmsig)
target_compile_options(vmsig_test PRIVATE -Wall -Wextra)
add_test(NAME ctx COMMAND vmsig_test)

add_executable(vmsig_sectest src/test/test_sec.c)
target_link_libraries(vmsig_sectest PRIVATE vmsig)
target_compile_options(vmsig_sectest PRIVATE -Wall -Wextra)
add_test(NAME sec COMMAND vmsig_sectest)

add_executable(vmsig_socktest src/test/test_sock.c)
target_link_libraries(vmsig_socktest PRIVATE vmsig Threads::Threads)
target_compile_options(vmsig_socktest PRIVATE -Wall -Wextra)
add_test(NAME sock COMMAND vmsig_socktest)

add_executable(vmsig_mvmtest src/test/test_mvm.c)
target_link_libraries(vmsig_mvmtest PRIVATE vmsig)
target_compile_options(vmsig_mvmtest PRIVATE -Wall -Wextra)
add_test(NAME mvm COMMAND vmsig_mvmtest)

add_executable(vmsig_authztest src/test/test_authz.c)
target_link_libraries(vmsig_authztest PRIVATE vmsig)
target_compile_options(vmsig_authztest PRIVATE -Wall -Wextra)
add_test(NAME authz COMMAND vmsig_authztest)

add_executable(vmsig_memctxtest src/test/test_memctx.c)
target_link_libraries(vmsig_memctxtest PRIVATE vmsig Threads::Threads)
target_include_directories(vmsig_memctxtest PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src/core/include)
target_compile_options(vmsig_memctxtest PRIVATE -Wall -Wextra)
add_test(NAME memctx COMMAND vmsig_memctxtest)

add_executable(vmsig_vmhosttest src/test/test_vmhost.c)
target_link_libraries(vmsig_vmhosttest PRIVATE vmsig Threads::Threads)
target_include_directories(vmsig_vmhosttest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/adapter/vmhost/include)
target_compile_options(vmsig_vmhosttest PRIVATE -Wall -Wextra)
add_test(NAME vmhost COMMAND vmsig_vmhosttest)

add_executable(vmsig_leasetest src/test/test_lease.c)
target_link_libraries(vmsig_leasetest PRIVATE vmsig Threads::Threads)
target_include_directories(vmsig_leasetest PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src/core/include
        ${CMAKE_CURRENT_SOURCE_DIR}/src/ctx/include)
target_compile_options(vmsig_leasetest PRIVATE -Wall -Wextra)
add_test(NAME lease COMMAND vmsig_leasetest)

add_executable(vmsig_inputobstest src/test/test_inputobs.c)
target_link_libraries(vmsig_inputobstest PRIVATE vmsig Threads::Threads)
target_compile_options(vmsig_inputobstest PRIVATE -Wall -Wextra)
add_test(NAME inputobs COMMAND vmsig_inputobstest)

add_executable(vmsig_memwritetest src/test/test_memwrite.c)
target_link_libraries(vmsig_memwritetest PRIVATE vmsig Threads::Threads)
target_include_directories(vmsig_memwritetest PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src/adapter/memctx/include)
target_compile_options(vmsig_memwritetest PRIVATE -Wall -Wextra)
add_test(NAME memwrite COMMAND vmsig_memwritetest)

# the demonstrator doubles as an end-to-end seam test (self-terminates rc=0)
add_test(NAME cli COMMAND vmsig_cli)
