cmake_minimum_required(VERSION 3.16)

project(ikv VERSION 0.1.0 LANGUAGES C)

include(CMakePackageConfigHelpers)
include(GNUInstallDirs)

option(IKV_BUILD_DEMOS "Build demo executables" ON)
option(IKV_BUILD_TESTS "Build unit tests" OFF)
option(IKV_INSTALL "Install library and CMake package files" ON)

set(IKV_PUBLIC_HEADERS
    include/ikv.h
)

set(IKV_SOURCES
    src/ikv.c
    src/loaders/ikv1.c
    src/loaders/ikv2.c
)

add_library(ikv_obj OBJECT ${IKV_SOURCES})
target_include_directories(ikv_obj
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
    PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_compile_features(ikv_obj PUBLIC c_std_99)
set_target_properties(ikv_obj PROPERTIES
    POSITION_INDEPENDENT_CODE ON
)


# Enable optimization and extra warnings for GNU/Clang compilers
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
    add_compile_options(-O2 -Wall -Wextra -Wpedantic)
endif()

#add_compile_options
add_library(ikv STATIC)
add_library(ikv::ikv ALIAS ikv)
target_sources(ikv PRIVATE $<TARGET_OBJECTS:ikv_obj>)
target_include_directories(ikv
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_compile_features(ikv PUBLIC c_std_99)
set_target_properties(ikv PROPERTIES
    OUTPUT_NAME ikv
    PUBLIC_HEADER "${IKV_PUBLIC_HEADERS}"
)

if(IKV_BUILD_DEMOS)
    add_executable(ikv_demo demo/main.c)
    target_link_libraries(ikv_demo PRIVATE ikv)

    add_executable(ikv_unit_test demo/unit_test.c)
    target_link_libraries(ikv_unit_test PRIVATE ikv)
endif()

if(IKV_BUILD_TESTS)
    enable_testing()

    add_executable(ikv_tests
        demo/unit_test.c
        ${IKV_SOURCES}
    )
    target_compile_definitions(ikv_tests PRIVATE IKV_TESTING)
    target_include_directories(ikv_tests
        PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/include
            ${CMAKE_CURRENT_SOURCE_DIR}/src
    )
    target_compile_features(ikv_tests PRIVATE c_std_99)

    file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/demo/unit_test.c" IKV_TEST_CASE_ROWS
        REGEX "^    \\{\"[^\"]+\", test_[^}]+\\},?$"
    )

    foreach(IKV_TEST_CASE_ROW IN LISTS IKV_TEST_CASE_ROWS)
        string(REGEX REPLACE "^    \\{\"([^\"]+)\", test_[^}]+\\},?$" "\\1" IKV_TEST_CASE_NAME "${IKV_TEST_CASE_ROW}")
        string(MAKE_C_IDENTIFIER "${IKV_TEST_CASE_NAME}" IKV_TEST_CASE_ID)
        add_test(
            NAME "ikv_tests.${IKV_TEST_CASE_ID}"
            COMMAND ikv_tests --case "${IKV_TEST_CASE_NAME}"
        )
    endforeach()
endif()

if(IKV_INSTALL)
    install(
        TARGETS ikv
        EXPORT ikvTargets
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
        PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
    )

    install(
        EXPORT ikvTargets
        FILE ikvTargets.cmake
        NAMESPACE ikv::
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ikv
    )

    write_basic_package_version_file(
        "${CMAKE_CURRENT_BINARY_DIR}/ikvConfigVersion.cmake"
        VERSION ${PROJECT_VERSION}
        COMPATIBILITY SameMajorVersion
    )

    configure_package_config_file(
        "${CMAKE_CURRENT_SOURCE_DIR}/cmake/ikvConfig.cmake.in"
        "${CMAKE_CURRENT_BINARY_DIR}/ikvConfig.cmake"
        INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ikv"
    )

    install(
        FILES
            "${CMAKE_CURRENT_BINARY_DIR}/ikvConfig.cmake"
            "${CMAKE_CURRENT_BINARY_DIR}/ikvConfigVersion.cmake"
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ikv
    )
endif()
