# Link-discipline guard for the (largely header-only) SDK. Every public
# header -- SDK, ABI, and value -- is included from three translation
# units: main.cc and app.cc, compiled into an executable shaped like a
# linked application, and lib.cc, compiled into a shared library (a second
# DSO -- the shape an installed node .so will have). A definition that sits
# in a header without `inline` is
# emitted as a strong symbol into every translation unit; the main.cc/
# app.cc pair shares one link unit, so the duplicate fails the
# executable's link. (Between the executable and the shared library the
# dynamic linker would interpose silently, which is why the executable
# itself must hold two of the translation units.) The lint targets compile
# the headers but never link them, so this target is the only automated
# check for that bug class. The executable also runs as a test: both DSOs
# execute a small reactor program, verifying that two copies of the inline
# SDK code coexist in one process.

set(LINK_TEST_SOURCES
  "${CMAKE_CURRENT_SOURCE_DIR}/lib.cc"
  "${CMAKE_CURRENT_SOURCE_DIR}/app.cc"
  "${CMAKE_CURRENT_SOURCE_DIR}/main.cc"
  PARENT_SCOPE
)

if(XRONOS_SDK_BUILD_TESTS)
  # Generate include_all.hh with an #include line for every public header,
  # so that new headers are covered automatically.
  set(_include_all_lines "")
  foreach(_root IN ITEMS
    "${CMAKE_CURRENT_SOURCE_DIR}/../include"
    "${XRONOS_ABI_INCLUDE_DIR}"
    "${XRONOS_VALUE_INCLUDE_DIR}"
  )
    file(GLOB_RECURSE _headers CONFIGURE_DEPENDS "${_root}/xronos/*.hh")
    foreach(_header IN LISTS _headers)
      file(RELATIVE_PATH _relative "${_root}" "${_header}")
      string(APPEND _include_all_lines "#include \"${_relative}\"\n")
    endforeach()
  endforeach()
  file(CONFIGURE
    OUTPUT include_all.hh
    CONTENT "// Generated by link-test/CMakeLists.txt: every public SDK header.\n${_include_all_lines}"
  )

  add_library(xronos-sdk-link-test-lib SHARED lib.cc)
  add_executable(xronos-sdk-link-test main.cc app.cc)
  foreach(_target IN ITEMS xronos-sdk-link-test-lib xronos-sdk-link-test)
    target_include_directories(${_target} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
    target_link_libraries(${_target} PRIVATE xronos::xronos-sdk)
    target_compile_options(${_target} PRIVATE -Wall $<$<BOOL:${XRONOS_STRICT_WARNINGS}>:-Wextra -pedantic -Werror>)
  endforeach()
  target_link_libraries(xronos-sdk-link-test PRIVATE xronos-sdk-link-test-lib)
  if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
    # A declaration in a header whose definition is missing entirely would
    # otherwise only surface when the library is dlopened; fail the build instead.
    target_link_options(xronos-sdk-link-test-lib PRIVATE -Wl,--no-undefined)
  endif()

  add_test(NAME xronos-sdk-link-test COMMAND xronos-sdk-link-test)
endif()
