cmake_minimum_required(VERSION 3.14)
project(dmakit VERSION 4.3.0 LANGUAGES CXX)

# Header-only: link dmakit::dmakit and #include "dmakit/dmakit.hpp".
add_library(dmakit INTERFACE)
add_library(dmakit::dmakit ALIAS dmakit)
target_include_directories(dmakit INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/cpp/include> $<INSTALL_INTERFACE:include>)
target_compile_features(dmakit INTERFACE cxx_std_20)

option(DMAKIT_BUILD_EXAMPLES "Build the examples and the scenario runner" ${PROJECT_IS_TOP_LEVEL})
if(DMAKIT_BUILD_EXAMPLES)
  enable_testing()
  # The warnings are the -W lines of compile_flags.txt (clang-tidy and the tests use them too);
  # -Werror is one of them. Unformatted source does not build: dmakit_format runs first.
  set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS compile_flags.txt)
  file(STRINGS compile_flags.txt dmakit_flags REGEX "^-W")
  if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # warnings only GCC has, as tests/cxx-warnings.mjs
    list(APPEND dmakit_flags -Wuseless-cast -Wduplicated-cond -Wduplicated-branches -Wlogical-op)
  endif()
  find_program(CLANG_FORMAT clang-format)
  if(NOT CLANG_FORMAT)
    message(FATAL_ERROR "clang-format is required to build the examples (set -DDMAKIT_BUILD_EXAMPLES=OFF to skip)")
  endif()
  file(GLOB_RECURSE dmakit_sources CONFIGURE_DEPENDS cpp/*.hpp cpp/*.cpp)
  add_custom_target(dmakit_format ALL COMMAND ${CLANG_FORMAT} --dry-run --Werror ${dmakit_sources}
                    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} VERBATIM)
  foreach(path iommu_fault swiotlb_bounce ppr_overflow ats_pri_pagein pasid_pagein ppr_autoswap vapic_counters dirty_tracking vmm/viommu_nested viommu_hw viommu_hw_edges viommu_hw_callbacks callbacks_reentry table_errors snp_secure_ats deferred_commands)
    get_filename_component(ex ${path} NAME) # an example may sit in a subfolder (vmm/)
    add_executable(${ex} cpp/examples/${path}.cpp)
    target_link_libraries(${ex} PRIVATE dmakit::dmakit)
    target_compile_options(${ex} PRIVATE ${dmakit_flags})
    add_dependencies(${ex} dmakit_format)
    add_test(NAME ${ex} COMMAND ${ex})
  endforeach()
  add_executable(dmakit_script cpp/tools/dmakit_script.cpp)
  target_link_libraries(dmakit_script PRIVATE dmakit::dmakit)
  target_compile_options(dmakit_script PRIVATE ${dmakit_flags})
  add_dependencies(dmakit_script dmakit_format)
endif()

include(GNUInstallDirs)
install(DIRECTORY cpp/include/dmakit DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS dmakit EXPORT dmakitTargets)
install(EXPORT dmakitTargets NAMESPACE dmakit:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/dmakit)
