Add the vendored dependencies whether or not libakgl is top-level

Embedded with add_subdirectory(), the deps/ submodules a recursive clone
just checked out were ignored and find_package(SDL3 REQUIRED) ran instead,
so configure failed on a machine with nothing installed. Each dependency is
now added by akgl_add_vendored_dependency(), which skips it when the target
is already declared or the submodule is missing; the find_package lookups
run afterwards for whatever is left. The CTest suppression moves with them
and is lifted before this project registers its own suites.

Two consequences of the move: pkg-config is only looked for when something
has to come from the system, and the build-tree RPATH keys on whether
anything was vendored rather than on being the top-level project, so an
embedded build's tests can find the satellite libraries too.

Verified by configuring and building a consumer that embeds this repository
with CMAKE_DISABLE_FIND_PACKAGE_* set for all seven dependencies.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-31 12:51:46 -04:00
parent 54df954ed6
commit 18399f2726

View File

@@ -14,10 +14,10 @@ if(AKGL_COVERAGE)
find_program(GCOVR_EXECUTABLE gcovr REQUIRED) find_program(GCOVR_EXECUTABLE gcovr REQUIRED)
endif() endif()
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) # Vendored projects own their test suites. Suppress their CTest registration so
# the suite that runs contains only the targets built here. The override is
# Vendored projects own their test suites. Suppress their CTest registration # lifted again below, before this project registers its own tests, so an
# while embedded so the top-level suite contains only targets built here. # embedding consumer's add_test() still reaches CTest.
set(AKGL_SUPPRESS_DEPENDENCY_TESTS TRUE) set(AKGL_SUPPRESS_DEPENDENCY_TESTS TRUE)
function(add_test) function(add_test)
if(NOT AKGL_SUPPRESS_DEPENDENCY_TESTS) if(NOT AKGL_SUPPRESS_DEPENDENCY_TESTS)
@@ -34,53 +34,79 @@ set(JANSSON_WITHOUT_TESTS ON CACHE BOOL "Do not build vendored Jansson tests" FO
set(JANSSON_EXAMPLES OFF CACHE BOOL "Do not build vendored Jansson examples" FORCE) set(JANSSON_EXAMPLES OFF CACHE BOOL "Do not build vendored Jansson examples" FORCE)
set(JANSSON_BUILD_DOCS OFF CACHE BOOL "Do not build vendored Jansson docs" FORCE) set(JANSSON_BUILD_DOCS OFF CACHE BOOL "Do not build vendored Jansson docs" FORCE)
add_subdirectory(deps/jansson EXCLUDE_FROM_ALL) # Add one vendored dependency, if nobody has already declared it and the
add_subdirectory(deps/libakerror EXCLUDE_FROM_ALL) # submodule is actually checked out.
add_subdirectory(deps/libakstdlib EXCLUDE_FROM_ALL) #
add_subdirectory(deps/SDL EXCLUDE_FROM_ALL) # A macro rather than a function on purpose: add_subdirectory() inside a
add_subdirectory(deps/SDL_image EXCLUDE_FROM_ALL) # function runs with that function's variable scope, so every cache-ish variable
add_subdirectory(deps/SDL_mixer EXCLUDE_FROM_ALL) # these projects set for their own subdirectories would be discarded on return.
add_subdirectory(deps/SDL_ttf EXCLUDE_FROM_ALL) macro(akgl_add_vendored_dependency target dir)
if(NOT TARGET ${target})
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${dir}/CMakeLists.txt")
add_subdirectory(${dir} EXCLUDE_FROM_ALL)
set(AKGL_VENDORED_DEPENDENCIES TRUE)
endif()
endif()
endmacro()
# Added on both paths, not just when this is the top-level project. Embedded
# with add_subdirectory(), the submodules under deps/ are sitting right there --
# the recursive clone the consumer just did put them there -- and refusing to
# configure until SDL3 is installed system-wide is a failure with its own answer
# three directories away. if(NOT TARGET ...) means a consumer that has already
# declared one of these wins; the EXISTS check means a checkout without
# submodules falls through to find_package below.
akgl_add_vendored_dependency(jansson::jansson deps/jansson)
akgl_add_vendored_dependency(akerror::akerror deps/libakerror)
akgl_add_vendored_dependency(akstdlib::akstdlib deps/libakstdlib)
akgl_add_vendored_dependency(SDL3::SDL3 deps/SDL)
akgl_add_vendored_dependency(SDL3_image::SDL3_image deps/SDL_image)
akgl_add_vendored_dependency(SDL3_mixer::SDL3_mixer deps/SDL_mixer)
akgl_add_vendored_dependency(SDL3_ttf::SDL3_ttf deps/SDL_ttf)
# libakerror 1.0.0 sizes its own status-name registry; consumers no longer do. # libakerror 1.0.0 sizes its own status-name registry; consumers no longer do.
# libakgl claims its status codes at runtime in akgl_heap_init() instead. # libakgl claims its status codes at runtime in akgl_heap_init() instead.
set(AKGL_SUPPRESS_DEPENDENCY_TESTS FALSE) set(AKGL_SUPPRESS_DEPENDENCY_TESTS FALSE)
else() # Anything the vendored block did not supply has to come from the system.
if(NOT (TARGET SDL3::SDL3 AND TARGET SDL3_image::SDL3_image AND
TARGET SDL3_mixer::SDL3_mixer AND TARGET SDL3_ttf::SDL3_ttf AND
TARGET akerror::akerror AND TARGET akstdlib::akstdlib AND
TARGET jansson::jansson))
# Only needed to locate installed copies; a fully vendored build does not
# require pkg-config to be present at all.
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
endif()
if(NOT TARGET SDL3::SDL3) if(NOT TARGET SDL3::SDL3)
find_package(SDL3 REQUIRED) find_package(SDL3 REQUIRED)
endif() endif()
if(NOT TARGET SDL3_image::SDL3_image) if(NOT TARGET SDL3_image::SDL3_image)
find_package(SDL3_image REQUIRED) find_package(SDL3_image REQUIRED)
endif() endif()
if(NOT TARGET SDL3_mixer::SDL3_mixer) if(NOT TARGET SDL3_mixer::SDL3_mixer)
find_package(SDL3_mixer REQUIRED) find_package(SDL3_mixer REQUIRED)
endif() endif()
if(NOT TARGET SDL3_ttf::SDL3_ttf) if(NOT TARGET SDL3_ttf::SDL3_ttf)
find_package(SDL3_ttf REQUIRED) find_package(SDL3_ttf REQUIRED)
endif() endif()
# No version here: libakerror ships no akerrorConfigVersion.cmake, so asking # No version here: libakerror ships no akerrorConfigVersion.cmake, so asking
# for one makes find_package reject every install. The floor is enforced by # for one makes find_package reject every install. The floor is enforced by
# the #error in include/akgl/error.h instead, which feature-tests # the #error in include/akgl/error.h instead, which feature-tests
# AKERR_FIRST_CONSUMER_STATUS. # AKERR_FIRST_CONSUMER_STATUS.
if(NOT TARGET akerror::akerror) if(NOT TARGET akerror::akerror)
find_package(akerror REQUIRED) find_package(akerror REQUIRED)
endif() endif()
# 0.2 rather than bare: libakstdlib 0.2.0 ships an akstdlibConfigVersion.cmake # 0.2 rather than bare: libakstdlib 0.2.0 ships an akstdlibConfigVersion.cmake
# with SameMinorVersion compatibility, mirroring its soname, so this accepts # with SameMinorVersion compatibility, mirroring its soname, so this accepts
# any 0.2.x and refuses 0.3 and 1.0. Unversioned, this path would silently # any 0.2.x and refuses 0.3 and 1.0. Unversioned, this path would silently
# accept an ABI-incompatible libakstdlib. # accept an ABI-incompatible libakstdlib.
if(NOT TARGET akstdlib::akstdlib) if(NOT TARGET akstdlib::akstdlib)
find_package(akstdlib 0.2 REQUIRED) find_package(akstdlib 0.2 REQUIRED)
endif() endif()
if(NOT TARGET jansson::jansson) if(NOT TARGET jansson::jansson)
find_package(jansson) find_package(jansson)
endif()
endif() endif()
set(GAMECONTROLLERDB_H "include/akgl/SDL_GameControllerDB.h") set(GAMECONTROLLERDB_H "include/akgl/SDL_GameControllerDB.h")
@@ -261,8 +287,9 @@ target_link_libraries(charviewer PRIVATE akstdlib::akstdlib akerror::akerror akg
# project subdirectories that are not on the loader's default search path, so a # project subdirectories that are not on the loader's default search path, so a
# freshly built test aborts before main() with "cannot open shared object file". # freshly built test aborts before main() with "cannot open shared object file".
# Bake those directories into the build-tree RPATH. Installed builds resolve the # Bake those directories into the build-tree RPATH. Installed builds resolve the
# same libraries through find_package and need no help. # same libraries through find_package and need no help, so this keys on whether
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) # anything was actually vendored rather than on being the top-level project.
if(AKGL_VENDORED_DEPENDENCIES)
set(AKGL_VENDORED_RPATH set(AKGL_VENDORED_RPATH
"$<TARGET_FILE_DIR:SDL3::SDL3>" "$<TARGET_FILE_DIR:SDL3::SDL3>"
"$<TARGET_FILE_DIR:SDL3_image::SDL3_image>" "$<TARGET_FILE_DIR:SDL3_image::SDL3_image>"