2025-08-03 10:07:35 -04:00
|
|
|
cmake_minimum_required(VERSION 3.10)
|
Derive the library version from one place and give the .so a soname
The version was written down twice and agreed with itself by luck.
AKGL_VERSION was hand-maintained in include/akgl/game.h, and nothing
connected it to the build, which had no version at all:
- project() declared no VERSION, so the @PROJECT_VERSION@ substitution
in akgl.pc.in expanded to nothing and every installed akgl.pc shipped
an empty Version field. pkg-config --modversion returned "" and
--atleast-version could not work at all.
- libakgl.so had no VERSION or SOVERSION, so there was no soname and no
symlink chain. A stale libakgl could be paired with new headers
silently, which is the failure libakerror added its own soname to
prevent.
- MY_LIBRARY_VERSION at CMakeLists.txt:288 was never set anywhere. It
built main_lib_dest as "lib/akgl-", and main_lib_dest was then never
read. Dead line, removed.
project(akgl VERSION 0.1.0) is now the only place the number appears. It
drives the generated include/akgl/version.h, the shared library VERSION
and SOVERSION, and the Version field in akgl.pc. Held at 0.1.0 to match
the constant it replaces, so akgl_game_load_versioncmp still compares
savegames against the same value.
include/akgl/version.h is generated by configure_file from version.h.in
and publishes AKGL_VERSION, AKGL_VERSION_MAJOR/MINOR/PATCH and
AKGL_VERSION_AT_LEAST(major, minor, patch). That macro is the point:
libakstdlib could not write that test against libakerror, which
publishes no version macro, and had to feature-test on
AKERR_FIRST_CONSUMER_STATUS instead. game.h now includes the generated
header rather than defining the version itself, so consumers see
AKGL_VERSION exactly where they saw it before.
While the major version is 0 the soname carries major.minor, giving
libakgl.so.0.1. A plain SOVERSION 0 would assert that 0.1.0 and 0.2.0
are ABI-interchangeable, and they are not -- the preceding commit alone
added akgl_error_init. At 1.0.0 the soname becomes the major alone,
matching libakerror.
akgl_version() in src/version.c reports the version of the libakgl that
is actually linked, where AKGL_VERSION reports what the caller compiled
against. Comparing the two is the only way to catch a stale shared
library on the loader path; the macro alone cannot see it. It returns a
string rather than an akerr_ErrorContext * because it cannot fail, for
the same reason akerr_name_for_status does.
Add tests/version.c: the string and the numeric components must describe
one version, the linked library must agree with the headers, and
AKGL_VERSION_AT_LEAST must order correctly at the major, minor and patch
boundaries. Verified out of band that bumping project() to 1.2.3 moves
version.h, akgl.pc and the soname together, and that an install produces
the libakgl.so -> .so.0.1 -> .so.0.1.0 chain with SONAME libakgl.so.0.1.
Also ignore include/akgl/version.h. include/ precedes the build tree on
the include path, so a stray copy there would shadow the generated one
and pin every consumer to whatever version it was generated at.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:36:50 -04:00
|
|
|
# The single source of truth for the library version. It drives the generated
|
|
|
|
|
# include/akgl/version.h, the shared library's VERSION and SOVERSION, and the
|
|
|
|
|
# Version field in akgl.pc. Bump it here and nowhere else.
|
|
|
|
|
project(akgl VERSION 0.1.0 LANGUAGES C)
|
2025-08-03 10:07:35 -04:00
|
|
|
|
2025-08-03 14:06:40 -04:00
|
|
|
include(CTest)
|
2026-07-30 01:25:26 -04:00
|
|
|
option(AKGL_COVERAGE "Instrument libakgl and generate coverage reports with CTest" OFF)
|
|
|
|
|
|
|
|
|
|
if(AKGL_COVERAGE)
|
|
|
|
|
if(NOT CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
|
|
|
|
|
message(FATAL_ERROR "AKGL_COVERAGE requires GCC or Clang")
|
|
|
|
|
endif()
|
|
|
|
|
find_program(GCOVR_EXECUTABLE gcovr REQUIRED)
|
|
|
|
|
endif()
|
2025-08-03 14:06:40 -04:00
|
|
|
|
2026-05-12 21:01:47 -04:00
|
|
|
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
2026-07-29 18:01:05 -04:00
|
|
|
|
|
|
|
|
# Vendored projects own their test suites. Suppress their CTest registration
|
|
|
|
|
# while embedded so the top-level suite contains only targets built here.
|
|
|
|
|
set(AKGL_SUPPRESS_DEPENDENCY_TESTS TRUE)
|
|
|
|
|
function(add_test)
|
|
|
|
|
if(NOT AKGL_SUPPRESS_DEPENDENCY_TESTS)
|
|
|
|
|
_add_test(${ARGV})
|
|
|
|
|
endif()
|
|
|
|
|
endfunction()
|
|
|
|
|
function(set_tests_properties)
|
|
|
|
|
if(NOT AKGL_SUPPRESS_DEPENDENCY_TESTS)
|
|
|
|
|
_set_tests_properties(${ARGV})
|
|
|
|
|
endif()
|
|
|
|
|
endfunction()
|
|
|
|
|
|
|
|
|
|
set(JANSSON_WITHOUT_TESTS ON CACHE BOOL "Do not build vendored Jansson tests" 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)
|
|
|
|
|
|
2026-05-12 16:45:42 -04:00
|
|
|
add_subdirectory(deps/jansson EXCLUDE_FROM_ALL)
|
|
|
|
|
add_subdirectory(deps/libakerror EXCLUDE_FROM_ALL)
|
|
|
|
|
add_subdirectory(deps/libakstdlib EXCLUDE_FROM_ALL)
|
|
|
|
|
add_subdirectory(deps/SDL EXCLUDE_FROM_ALL)
|
|
|
|
|
add_subdirectory(deps/SDL_image EXCLUDE_FROM_ALL)
|
|
|
|
|
add_subdirectory(deps/SDL_mixer EXCLUDE_FROM_ALL)
|
|
|
|
|
add_subdirectory(deps/SDL_ttf EXCLUDE_FROM_ALL)
|
2025-08-03 10:07:35 -04:00
|
|
|
|
Migrate to the libakerror 1.0.0 status registry
libakerror 1.0.0 replaced the consumer-sized status-name array with a
private registry and made status-code ownership explicit and enforced.
AKERR_MAX_ERR_VALUE and __AKERR_ERROR_NAMES are gone, and the registry
entry points raise akerr_ErrorContext * instead of returning int. See
deps/libakerror/UPGRADING.md.
The break was not only source-level. libakgl's codes sat at
AKERR_LAST_ERRNO_VALUE + 18 through + 22, and 1.0.0 claimed exactly
those five offsets for its own AKERR_STATUS_* registry codes, so every
AKGL_ERR_* was aliasing a libakerror status. HANDLE(e,
AKGL_ERR_LOGICINTERRUPT) at physics.c:222 would have swallowed a
foreign-name refusal.
- Move the band to AKERR_FIRST_CONSUMER_STATUS (256) as fixed offsets,
so a libc that grows an errno cannot move the codes, and add
AKGL_ERR_OWNER, AKGL_ERR_LIMIT and AKGL_ERR_COUNT to describe it.
- Reserve the range and register the names through the owned entry
points, PASS-ing each: these are AKERR_NOIGNORE, and the old
akerr_name_for_status calls discarded failure silently.
- Drop the AKERR_MAX_ERR_VALUE=256 compile definition.
- Guard on AKERR_FIRST_CONSUMER_STATUS in include/akgl/error.h, which
now includes <akerror.h> so the guard is reliable. The embedded build
is fine, but the find_package path can pick up a stale installed
header, and 1.0.0 has an soname, so that pairing is an ABI mismatch
rather than a compile problem. Same guard libakstdlib already carries.
Registration also moves out of akgl_heap_init into a new akgl_error_init
in src/error.c. It was in the heap pool's initializer only because that
was the first thing akgl_game_init called, and the upgrade turned five
fire-and-forget name calls into a library-wide ownership claim that can
fail. That placement was hiding a defect: game.c raises AKGL_ERR_SDL
when SDL_CreateMutex fails, five lines before akgl_heap_init ran, so the
earliest error path in the library was guaranteed to print "Unknown
Error". akgl_error_init is now the first statement in akgl_game_init.
Callers that drive subsystems directly must call akgl_error_init first;
it is idempotent, so ordering it precisely is not required. The eleven
test suites that relied on akgl_heap_init to name their statuses now
call it explicitly, or their failure messages would have degraded to
"Unknown Error".
Add tests/error.c: assert every code reads back its registered name,
that the name table and AKGL_ERR_COUNT agree, that a foreign owner is
refused with AKERR_STATUS_NAME_FOREIGN and AKERR_STATUS_RANGE_OVERLAP,
and that repeating the init is a no-op. That last one is a live
constraint, not a triviality -- libakerror treats only an identical
reservation as a repeat, so a subset or superset raises.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:20:28 -04:00
|
|
|
# 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.
|
2026-07-29 18:01:05 -04:00
|
|
|
|
|
|
|
|
set(AKGL_SUPPRESS_DEPENDENCY_TESTS FALSE)
|
|
|
|
|
|
2026-05-12 21:01:47 -04:00
|
|
|
else()
|
|
|
|
|
|
2026-05-12 21:06:29 -04:00
|
|
|
find_package(PkgConfig REQUIRED)
|
|
|
|
|
|
|
|
|
|
if(NOT TARGET SDL3::SDL3)
|
|
|
|
|
find_package(SDL3 REQUIRED)
|
|
|
|
|
endif()
|
|
|
|
|
if(NOT TARGET SDL3_image::SDL3_image)
|
|
|
|
|
find_package(SDL3_image REQUIRED)
|
|
|
|
|
endif()
|
|
|
|
|
if(NOT TARGET SDL3_mixer::SDL3_mixer)
|
|
|
|
|
find_package(SDL3_mixer REQUIRED)
|
|
|
|
|
endif()
|
|
|
|
|
if(NOT TARGET SDL3_ttf::SDL3_ttf)
|
|
|
|
|
find_package(SDL3_ttf REQUIRED)
|
|
|
|
|
endif()
|
Upgrade to libakstdlib 0.1.0
Bump deps/libakstdlib five commits to 95e5002, which versions the library
at 0.1.0 with an soname and a ConfigVersion file, upgrades its own
libakerror to 1.0.0, namespaces its coverage target when embedded, and
raises its libc-wrapper coverage. The public header diff is purely
additive -- nothing removed, no signature changed -- so libakgl's nine
aksl_* call sites needed no edits. What broke was the build.
A default `cmake -S . -B build` stopped configuring:
add_executable cannot create target "test_version" because another
target with the same name already exists. The existing target is an
executable created in source directory ".../deps/libakstdlib"
The versioning commit added tests/test_version.c to libakstdlib.
EXCLUDE_FROM_ALL keeps that target from being built, but
add_subdirectory still creates it, so it collided with the version suite
added in the preceding commit. Build libakgl's test programs as
akgl_test_<name> instead. The CTest names are unchanged -- ctest -R
version still selects it -- and a dependency is now free to ship a test
of any name.
Ask find_package for libakstdlib 0.1 rather than any version. 0.1.0
ships akstdlibConfigVersion.cmake with SameMinorVersion compatibility,
mirroring its libakstdlib.so.0.1 soname, so this accepts any 0.1.x and
refuses 0.2 and 1.0. Unversioned, the non-embedded path would have taken
an ABI-incompatible libakstdlib without complaint.
libakerror is deliberately left unversioned in find_package. It installs
akerrorConfig.cmake and akerrorTargets.cmake but no
akerrorConfigVersion.cmake, so find_package(akerror 1.0) fails against a
correct install rather than a stale one. Its floor stays with the #error
in include/akgl/error.h. Worth fixing upstream.
Verified: clean configure, build and 16/16 ctest; a -DAKGL_COVERAGE=ON
tree configures, builds and passes 18/18, so libakstdlib's embedded
coverage-target rename does not collide here. Against a temp-prefix
install of 95e5002, find_package(akstdlib) accepts 0.1 and 0.1.0 and
refuses 0.2 and 1.0, and find_package(akerror 1.0) fails for the missing
version file as described.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:55:18 -04:00
|
|
|
# No version here: libakerror ships no akerrorConfigVersion.cmake, so asking
|
|
|
|
|
# for one makes find_package reject every install. The floor is enforced by
|
|
|
|
|
# the #error in include/akgl/error.h instead, which feature-tests
|
|
|
|
|
# AKERR_FIRST_CONSUMER_STATUS.
|
2026-05-12 21:06:29 -04:00
|
|
|
if(NOT TARGET akerror::akerror)
|
|
|
|
|
find_package(akerror REQUIRED)
|
|
|
|
|
endif()
|
Upgrade to libakstdlib 0.1.0
Bump deps/libakstdlib five commits to 95e5002, which versions the library
at 0.1.0 with an soname and a ConfigVersion file, upgrades its own
libakerror to 1.0.0, namespaces its coverage target when embedded, and
raises its libc-wrapper coverage. The public header diff is purely
additive -- nothing removed, no signature changed -- so libakgl's nine
aksl_* call sites needed no edits. What broke was the build.
A default `cmake -S . -B build` stopped configuring:
add_executable cannot create target "test_version" because another
target with the same name already exists. The existing target is an
executable created in source directory ".../deps/libakstdlib"
The versioning commit added tests/test_version.c to libakstdlib.
EXCLUDE_FROM_ALL keeps that target from being built, but
add_subdirectory still creates it, so it collided with the version suite
added in the preceding commit. Build libakgl's test programs as
akgl_test_<name> instead. The CTest names are unchanged -- ctest -R
version still selects it -- and a dependency is now free to ship a test
of any name.
Ask find_package for libakstdlib 0.1 rather than any version. 0.1.0
ships akstdlibConfigVersion.cmake with SameMinorVersion compatibility,
mirroring its libakstdlib.so.0.1 soname, so this accepts any 0.1.x and
refuses 0.2 and 1.0. Unversioned, the non-embedded path would have taken
an ABI-incompatible libakstdlib without complaint.
libakerror is deliberately left unversioned in find_package. It installs
akerrorConfig.cmake and akerrorTargets.cmake but no
akerrorConfigVersion.cmake, so find_package(akerror 1.0) fails against a
correct install rather than a stale one. Its floor stays with the #error
in include/akgl/error.h. Worth fixing upstream.
Verified: clean configure, build and 16/16 ctest; a -DAKGL_COVERAGE=ON
tree configures, builds and passes 18/18, so libakstdlib's embedded
coverage-target rename does not collide here. Against a temp-prefix
install of 95e5002, find_package(akstdlib) accepts 0.1 and 0.1.0 and
refuses 0.2 and 1.0, and find_package(akerror 1.0) fails for the missing
version file as described.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:55:18 -04:00
|
|
|
# 0.1 rather than bare: libakstdlib 0.1.0 ships an akstdlibConfigVersion.cmake
|
|
|
|
|
# with SameMinorVersion compatibility, mirroring its soname, so this accepts
|
|
|
|
|
# any 0.1.x and refuses 0.2 and 1.0. Unversioned, this path would silently
|
|
|
|
|
# accept an ABI-incompatible libakstdlib.
|
2026-05-12 21:38:08 -04:00
|
|
|
if(NOT TARGET akstdlib::akstdlib)
|
Upgrade to libakstdlib 0.1.0
Bump deps/libakstdlib five commits to 95e5002, which versions the library
at 0.1.0 with an soname and a ConfigVersion file, upgrades its own
libakerror to 1.0.0, namespaces its coverage target when embedded, and
raises its libc-wrapper coverage. The public header diff is purely
additive -- nothing removed, no signature changed -- so libakgl's nine
aksl_* call sites needed no edits. What broke was the build.
A default `cmake -S . -B build` stopped configuring:
add_executable cannot create target "test_version" because another
target with the same name already exists. The existing target is an
executable created in source directory ".../deps/libakstdlib"
The versioning commit added tests/test_version.c to libakstdlib.
EXCLUDE_FROM_ALL keeps that target from being built, but
add_subdirectory still creates it, so it collided with the version suite
added in the preceding commit. Build libakgl's test programs as
akgl_test_<name> instead. The CTest names are unchanged -- ctest -R
version still selects it -- and a dependency is now free to ship a test
of any name.
Ask find_package for libakstdlib 0.1 rather than any version. 0.1.0
ships akstdlibConfigVersion.cmake with SameMinorVersion compatibility,
mirroring its libakstdlib.so.0.1 soname, so this accepts any 0.1.x and
refuses 0.2 and 1.0. Unversioned, the non-embedded path would have taken
an ABI-incompatible libakstdlib without complaint.
libakerror is deliberately left unversioned in find_package. It installs
akerrorConfig.cmake and akerrorTargets.cmake but no
akerrorConfigVersion.cmake, so find_package(akerror 1.0) fails against a
correct install rather than a stale one. Its floor stays with the #error
in include/akgl/error.h. Worth fixing upstream.
Verified: clean configure, build and 16/16 ctest; a -DAKGL_COVERAGE=ON
tree configures, builds and passes 18/18, so libakstdlib's embedded
coverage-target rename does not collide here. Against a temp-prefix
install of 95e5002, find_package(akstdlib) accepts 0.1 and 0.1.0 and
refuses 0.2 and 1.0, and find_package(akerror 1.0) fails for the missing
version file as described.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:55:18 -04:00
|
|
|
find_package(akstdlib 0.1 REQUIRED)
|
2026-05-12 21:06:29 -04:00
|
|
|
endif()
|
|
|
|
|
if(NOT TARGET jansson::jansson)
|
|
|
|
|
find_package(jansson)
|
|
|
|
|
endif()
|
|
|
|
|
|
2026-05-12 21:01:47 -04:00
|
|
|
endif()
|
|
|
|
|
|
2026-05-07 22:20:10 -04:00
|
|
|
set(GAMECONTROLLERDB_H "include/akgl/SDL_GameControllerDB.h")
|
2026-05-05 20:39:58 -04:00
|
|
|
set(prefix ${CMAKE_INSTALL_PREFIX})
|
|
|
|
|
set(exec_prefix "\${prefix}")
|
|
|
|
|
set(libdir "\${exec_prefix}/lib")
|
|
|
|
|
set(includedir "\${prefix}/include")
|
2026-05-07 22:20:10 -04:00
|
|
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/akgl.pc.in ${CMAKE_CURRENT_BINARY_DIR}/akgl.pc @ONLY)
|
Derive the library version from one place and give the .so a soname
The version was written down twice and agreed with itself by luck.
AKGL_VERSION was hand-maintained in include/akgl/game.h, and nothing
connected it to the build, which had no version at all:
- project() declared no VERSION, so the @PROJECT_VERSION@ substitution
in akgl.pc.in expanded to nothing and every installed akgl.pc shipped
an empty Version field. pkg-config --modversion returned "" and
--atleast-version could not work at all.
- libakgl.so had no VERSION or SOVERSION, so there was no soname and no
symlink chain. A stale libakgl could be paired with new headers
silently, which is the failure libakerror added its own soname to
prevent.
- MY_LIBRARY_VERSION at CMakeLists.txt:288 was never set anywhere. It
built main_lib_dest as "lib/akgl-", and main_lib_dest was then never
read. Dead line, removed.
project(akgl VERSION 0.1.0) is now the only place the number appears. It
drives the generated include/akgl/version.h, the shared library VERSION
and SOVERSION, and the Version field in akgl.pc. Held at 0.1.0 to match
the constant it replaces, so akgl_game_load_versioncmp still compares
savegames against the same value.
include/akgl/version.h is generated by configure_file from version.h.in
and publishes AKGL_VERSION, AKGL_VERSION_MAJOR/MINOR/PATCH and
AKGL_VERSION_AT_LEAST(major, minor, patch). That macro is the point:
libakstdlib could not write that test against libakerror, which
publishes no version macro, and had to feature-test on
AKERR_FIRST_CONSUMER_STATUS instead. game.h now includes the generated
header rather than defining the version itself, so consumers see
AKGL_VERSION exactly where they saw it before.
While the major version is 0 the soname carries major.minor, giving
libakgl.so.0.1. A plain SOVERSION 0 would assert that 0.1.0 and 0.2.0
are ABI-interchangeable, and they are not -- the preceding commit alone
added akgl_error_init. At 1.0.0 the soname becomes the major alone,
matching libakerror.
akgl_version() in src/version.c reports the version of the libakgl that
is actually linked, where AKGL_VERSION reports what the caller compiled
against. Comparing the two is the only way to catch a stale shared
library on the loader path; the macro alone cannot see it. It returns a
string rather than an akerr_ErrorContext * because it cannot fail, for
the same reason akerr_name_for_status does.
Add tests/version.c: the string and the numeric components must describe
one version, the linked library must agree with the headers, and
AKGL_VERSION_AT_LEAST must order correctly at the major, minor and patch
boundaries. Verified out of band that bumping project() to 1.2.3 moves
version.h, akgl.pc and the soname together, and that an install produces
the libakgl.so -> .so.0.1 -> .so.0.1.0 chain with SONAME libakgl.so.0.1.
Also ignore include/akgl/version.h. include/ precedes the build tree on
the include path, so a stray copy there would shadow the generated one
and pin every consumer to whatever version it was generated at.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:36:50 -04:00
|
|
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/akgl/version.h.in
|
|
|
|
|
${CMAKE_CURRENT_BINARY_DIR}/include/akgl/version.h @ONLY)
|
2025-08-09 13:53:37 -04:00
|
|
|
|
2026-07-29 18:01:05 -04:00
|
|
|
# Tests use both relative paths and SDL_GetBasePath(), so stage fixtures beside
|
|
|
|
|
# test executables in every out-of-tree build.
|
|
|
|
|
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tests/assets"
|
|
|
|
|
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
|
|
|
|
|
2025-08-09 13:53:37 -04:00
|
|
|
add_custom_command(
|
|
|
|
|
OUTPUT ${GAMECONTROLLERDB_H}
|
2026-05-12 21:38:08 -04:00
|
|
|
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/mkcontrollermappings.sh ${CMAKE_CURRENT_SOURCE_DIR}
|
2025-08-09 13:53:37 -04:00
|
|
|
COMMENT "Generating controller mappings ..."
|
|
|
|
|
)
|
|
|
|
|
|
2025-08-03 10:07:35 -04:00
|
|
|
# Add include directories
|
|
|
|
|
include_directories(${SDL3_INCLUDE_DIRS})
|
2026-05-07 22:20:10 -04:00
|
|
|
add_library(akgl SHARED
|
2026-05-08 23:15:11 -04:00
|
|
|
deps/semver/semver.c
|
2025-08-03 10:07:35 -04:00
|
|
|
src/actor.c
|
|
|
|
|
src/actor_state_string_names.c
|
2026-05-06 11:12:42 -04:00
|
|
|
src/text.c
|
2025-08-03 10:07:35 -04:00
|
|
|
src/assets.c
|
|
|
|
|
src/character.c
|
|
|
|
|
src/draw.c
|
Migrate to the libakerror 1.0.0 status registry
libakerror 1.0.0 replaced the consumer-sized status-name array with a
private registry and made status-code ownership explicit and enforced.
AKERR_MAX_ERR_VALUE and __AKERR_ERROR_NAMES are gone, and the registry
entry points raise akerr_ErrorContext * instead of returning int. See
deps/libakerror/UPGRADING.md.
The break was not only source-level. libakgl's codes sat at
AKERR_LAST_ERRNO_VALUE + 18 through + 22, and 1.0.0 claimed exactly
those five offsets for its own AKERR_STATUS_* registry codes, so every
AKGL_ERR_* was aliasing a libakerror status. HANDLE(e,
AKGL_ERR_LOGICINTERRUPT) at physics.c:222 would have swallowed a
foreign-name refusal.
- Move the band to AKERR_FIRST_CONSUMER_STATUS (256) as fixed offsets,
so a libc that grows an errno cannot move the codes, and add
AKGL_ERR_OWNER, AKGL_ERR_LIMIT and AKGL_ERR_COUNT to describe it.
- Reserve the range and register the names through the owned entry
points, PASS-ing each: these are AKERR_NOIGNORE, and the old
akerr_name_for_status calls discarded failure silently.
- Drop the AKERR_MAX_ERR_VALUE=256 compile definition.
- Guard on AKERR_FIRST_CONSUMER_STATUS in include/akgl/error.h, which
now includes <akerror.h> so the guard is reliable. The embedded build
is fine, but the find_package path can pick up a stale installed
header, and 1.0.0 has an soname, so that pairing is an ABI mismatch
rather than a compile problem. Same guard libakstdlib already carries.
Registration also moves out of akgl_heap_init into a new akgl_error_init
in src/error.c. It was in the heap pool's initializer only because that
was the first thing akgl_game_init called, and the upgrade turned five
fire-and-forget name calls into a library-wide ownership claim that can
fail. That placement was hiding a defect: game.c raises AKGL_ERR_SDL
when SDL_CreateMutex fails, five lines before akgl_heap_init ran, so the
earliest error path in the library was guaranteed to print "Unknown
Error". akgl_error_init is now the first statement in akgl_game_init.
Callers that drive subsystems directly must call akgl_error_init first;
it is idempotent, so ordering it precisely is not required. The eleven
test suites that relied on akgl_heap_init to name their statuses now
call it explicitly, or their failure messages would have degraded to
"Unknown Error".
Add tests/error.c: assert every code reads back its registered name,
that the name table and AKGL_ERR_COUNT agree, that a foreign owner is
refused with AKERR_STATUS_NAME_FOREIGN and AKERR_STATUS_RANGE_OVERLAP,
and that repeating the init is a no-op. That last one is a live
constraint, not a triviality -- libakerror treats only an identical
reservation as a repeat, so a subset or superset raises.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:20:28 -04:00
|
|
|
src/error.c
|
2025-08-03 10:07:35 -04:00
|
|
|
src/game.c
|
2025-08-03 21:42:12 -04:00
|
|
|
src/controller.c
|
2025-08-03 10:07:35 -04:00
|
|
|
src/heap.c
|
|
|
|
|
src/json_helpers.c
|
|
|
|
|
src/registry.c
|
2026-05-26 11:22:45 -04:00
|
|
|
src/renderer.c
|
|
|
|
|
src/physics.c
|
2025-08-03 10:07:35 -04:00
|
|
|
src/sprite.c
|
|
|
|
|
src/staticstring.c
|
|
|
|
|
src/tilemap.c
|
|
|
|
|
src/util.c
|
Derive the library version from one place and give the .so a soname
The version was written down twice and agreed with itself by luck.
AKGL_VERSION was hand-maintained in include/akgl/game.h, and nothing
connected it to the build, which had no version at all:
- project() declared no VERSION, so the @PROJECT_VERSION@ substitution
in akgl.pc.in expanded to nothing and every installed akgl.pc shipped
an empty Version field. pkg-config --modversion returned "" and
--atleast-version could not work at all.
- libakgl.so had no VERSION or SOVERSION, so there was no soname and no
symlink chain. A stale libakgl could be paired with new headers
silently, which is the failure libakerror added its own soname to
prevent.
- MY_LIBRARY_VERSION at CMakeLists.txt:288 was never set anywhere. It
built main_lib_dest as "lib/akgl-", and main_lib_dest was then never
read. Dead line, removed.
project(akgl VERSION 0.1.0) is now the only place the number appears. It
drives the generated include/akgl/version.h, the shared library VERSION
and SOVERSION, and the Version field in akgl.pc. Held at 0.1.0 to match
the constant it replaces, so akgl_game_load_versioncmp still compares
savegames against the same value.
include/akgl/version.h is generated by configure_file from version.h.in
and publishes AKGL_VERSION, AKGL_VERSION_MAJOR/MINOR/PATCH and
AKGL_VERSION_AT_LEAST(major, minor, patch). That macro is the point:
libakstdlib could not write that test against libakerror, which
publishes no version macro, and had to feature-test on
AKERR_FIRST_CONSUMER_STATUS instead. game.h now includes the generated
header rather than defining the version itself, so consumers see
AKGL_VERSION exactly where they saw it before.
While the major version is 0 the soname carries major.minor, giving
libakgl.so.0.1. A plain SOVERSION 0 would assert that 0.1.0 and 0.2.0
are ABI-interchangeable, and they are not -- the preceding commit alone
added akgl_error_init. At 1.0.0 the soname becomes the major alone,
matching libakerror.
akgl_version() in src/version.c reports the version of the libakgl that
is actually linked, where AKGL_VERSION reports what the caller compiled
against. Comparing the two is the only way to catch a stale shared
library on the loader path; the macro alone cannot see it. It returns a
string rather than an akerr_ErrorContext * because it cannot fail, for
the same reason akerr_name_for_status does.
Add tests/version.c: the string and the numeric components must describe
one version, the linked library must agree with the headers, and
AKGL_VERSION_AT_LEAST must order correctly at the major, minor and patch
boundaries. Verified out of band that bumping project() to 1.2.3 moves
version.h, akgl.pc and the soname together, and that an install produces
the libakgl.so -> .so.0.1 -> .so.0.1.0 chain with SONAME libakgl.so.0.1.
Also ignore include/akgl/version.h. include/ precedes the build tree on
the include path, so a stray copy there would shadow the generated one
and pin every consumer to whatever version it was generated at.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:36:50 -04:00
|
|
|
src/version.c
|
2025-08-09 13:53:37 -04:00
|
|
|
${GAMECONTROLLERDB_H}
|
2025-08-03 10:07:35 -04:00
|
|
|
)
|
|
|
|
|
|
Derive the library version from one place and give the .so a soname
The version was written down twice and agreed with itself by luck.
AKGL_VERSION was hand-maintained in include/akgl/game.h, and nothing
connected it to the build, which had no version at all:
- project() declared no VERSION, so the @PROJECT_VERSION@ substitution
in akgl.pc.in expanded to nothing and every installed akgl.pc shipped
an empty Version field. pkg-config --modversion returned "" and
--atleast-version could not work at all.
- libakgl.so had no VERSION or SOVERSION, so there was no soname and no
symlink chain. A stale libakgl could be paired with new headers
silently, which is the failure libakerror added its own soname to
prevent.
- MY_LIBRARY_VERSION at CMakeLists.txt:288 was never set anywhere. It
built main_lib_dest as "lib/akgl-", and main_lib_dest was then never
read. Dead line, removed.
project(akgl VERSION 0.1.0) is now the only place the number appears. It
drives the generated include/akgl/version.h, the shared library VERSION
and SOVERSION, and the Version field in akgl.pc. Held at 0.1.0 to match
the constant it replaces, so akgl_game_load_versioncmp still compares
savegames against the same value.
include/akgl/version.h is generated by configure_file from version.h.in
and publishes AKGL_VERSION, AKGL_VERSION_MAJOR/MINOR/PATCH and
AKGL_VERSION_AT_LEAST(major, minor, patch). That macro is the point:
libakstdlib could not write that test against libakerror, which
publishes no version macro, and had to feature-test on
AKERR_FIRST_CONSUMER_STATUS instead. game.h now includes the generated
header rather than defining the version itself, so consumers see
AKGL_VERSION exactly where they saw it before.
While the major version is 0 the soname carries major.minor, giving
libakgl.so.0.1. A plain SOVERSION 0 would assert that 0.1.0 and 0.2.0
are ABI-interchangeable, and they are not -- the preceding commit alone
added akgl_error_init. At 1.0.0 the soname becomes the major alone,
matching libakerror.
akgl_version() in src/version.c reports the version of the libakgl that
is actually linked, where AKGL_VERSION reports what the caller compiled
against. Comparing the two is the only way to catch a stale shared
library on the loader path; the macro alone cannot see it. It returns a
string rather than an akerr_ErrorContext * because it cannot fail, for
the same reason akerr_name_for_status does.
Add tests/version.c: the string and the numeric components must describe
one version, the linked library must agree with the headers, and
AKGL_VERSION_AT_LEAST must order correctly at the major, minor and patch
boundaries. Verified out of band that bumping project() to 1.2.3 moves
version.h, akgl.pc and the soname together, and that an install produces
the libakgl.so -> .so.0.1 -> .so.0.1.0 chain with SONAME libakgl.so.0.1.
Also ignore include/akgl/version.h. include/ precedes the build tree on
the include path, so a stray copy there would shadow the generated one
and pin every consumer to whatever version it was generated at.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:36:50 -04:00
|
|
|
# While the major version is 0 the ABI is not stable across minor releases, so
|
|
|
|
|
# the soname carries major.minor -- libakgl.so.0.1. A plain SOVERSION 0 would
|
|
|
|
|
# claim 0.1.0 and 0.2.0 are interchangeable, which is exactly the silent
|
|
|
|
|
# mispairing the soname is here to prevent. At 1.0.0 this becomes the major
|
|
|
|
|
# alone, matching libakerror.
|
|
|
|
|
if(PROJECT_VERSION_MAJOR EQUAL 0)
|
|
|
|
|
set(AKGL_SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
|
|
|
|
else()
|
|
|
|
|
set(AKGL_SOVERSION "${PROJECT_VERSION_MAJOR}")
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
set_target_properties(akgl PROPERTIES
|
|
|
|
|
VERSION ${PROJECT_VERSION}
|
|
|
|
|
SOVERSION ${AKGL_SOVERSION}
|
|
|
|
|
)
|
|
|
|
|
|
2026-05-12 21:38:08 -04:00
|
|
|
add_library(akgl::akgl ALIAS akgl)
|
2025-08-09 13:53:37 -04:00
|
|
|
|
2025-08-04 21:37:36 -04:00
|
|
|
add_executable(charviewer util/charviewer.c)
|
Upgrade to libakstdlib 0.1.0
Bump deps/libakstdlib five commits to 95e5002, which versions the library
at 0.1.0 with an soname and a ConfigVersion file, upgrades its own
libakerror to 1.0.0, namespaces its coverage target when embedded, and
raises its libc-wrapper coverage. The public header diff is purely
additive -- nothing removed, no signature changed -- so libakgl's nine
aksl_* call sites needed no edits. What broke was the build.
A default `cmake -S . -B build` stopped configuring:
add_executable cannot create target "test_version" because another
target with the same name already exists. The existing target is an
executable created in source directory ".../deps/libakstdlib"
The versioning commit added tests/test_version.c to libakstdlib.
EXCLUDE_FROM_ALL keeps that target from being built, but
add_subdirectory still creates it, so it collided with the version suite
added in the preceding commit. Build libakgl's test programs as
akgl_test_<name> instead. The CTest names are unchanged -- ctest -R
version still selects it -- and a dependency is now free to ship a test
of any name.
Ask find_package for libakstdlib 0.1 rather than any version. 0.1.0
ships akstdlibConfigVersion.cmake with SameMinorVersion compatibility,
mirroring its libakstdlib.so.0.1 soname, so this accepts any 0.1.x and
refuses 0.2 and 1.0. Unversioned, the non-embedded path would have taken
an ABI-incompatible libakstdlib without complaint.
libakerror is deliberately left unversioned in find_package. It installs
akerrorConfig.cmake and akerrorTargets.cmake but no
akerrorConfigVersion.cmake, so find_package(akerror 1.0) fails against a
correct install rather than a stale one. Its floor stays with the #error
in include/akgl/error.h. Worth fixing upstream.
Verified: clean configure, build and 16/16 ctest; a -DAKGL_COVERAGE=ON
tree configures, builds and passes 18/18, so libakstdlib's embedded
coverage-target rename does not collide here. Against a temp-prefix
install of 95e5002, find_package(akstdlib) accepts 0.1 and 0.1.0 and
refuses 0.2 and 1.0, and find_package(akerror 1.0) fails for the missing
version file as described.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:55:18 -04:00
|
|
|
add_executable(akgl_test_semver_unit deps/semver/semver_unit.c)
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
|
|
|
|
|
# Every suite here is a standalone C program named tests/<name>.c, built as
|
Upgrade to libakstdlib 0.1.0
Bump deps/libakstdlib five commits to 95e5002, which versions the library
at 0.1.0 with an soname and a ConfigVersion file, upgrades its own
libakerror to 1.0.0, namespaces its coverage target when embedded, and
raises its libc-wrapper coverage. The public header diff is purely
additive -- nothing removed, no signature changed -- so libakgl's nine
aksl_* call sites needed no edits. What broke was the build.
A default `cmake -S . -B build` stopped configuring:
add_executable cannot create target "test_version" because another
target with the same name already exists. The existing target is an
executable created in source directory ".../deps/libakstdlib"
The versioning commit added tests/test_version.c to libakstdlib.
EXCLUDE_FROM_ALL keeps that target from being built, but
add_subdirectory still creates it, so it collided with the version suite
added in the preceding commit. Build libakgl's test programs as
akgl_test_<name> instead. The CTest names are unchanged -- ctest -R
version still selects it -- and a dependency is now free to ship a test
of any name.
Ask find_package for libakstdlib 0.1 rather than any version. 0.1.0
ships akstdlibConfigVersion.cmake with SameMinorVersion compatibility,
mirroring its libakstdlib.so.0.1 soname, so this accepts any 0.1.x and
refuses 0.2 and 1.0. Unversioned, the non-embedded path would have taken
an ABI-incompatible libakstdlib without complaint.
libakerror is deliberately left unversioned in find_package. It installs
akerrorConfig.cmake and akerrorTargets.cmake but no
akerrorConfigVersion.cmake, so find_package(akerror 1.0) fails against a
correct install rather than a stale one. Its floor stays with the #error
in include/akgl/error.h. Worth fixing upstream.
Verified: clean configure, build and 16/16 ctest; a -DAKGL_COVERAGE=ON
tree configures, builds and passes 18/18, so libakstdlib's embedded
coverage-target rename does not collide here. Against a temp-prefix
install of 95e5002, find_package(akstdlib) accepts 0.1 and 0.1.0 and
refuses 0.2 and 1.0, and find_package(akerror 1.0) fails for the missing
version file as described.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:55:18 -04:00
|
|
|
# akgl_test_<name> and registered with CTest under <name>.
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
set(AKGL_TEST_SUITES
|
|
|
|
|
actor
|
|
|
|
|
bitmasks
|
|
|
|
|
character
|
2026-07-30 02:08:38 -04:00
|
|
|
controller
|
Migrate to the libakerror 1.0.0 status registry
libakerror 1.0.0 replaced the consumer-sized status-name array with a
private registry and made status-code ownership explicit and enforced.
AKERR_MAX_ERR_VALUE and __AKERR_ERROR_NAMES are gone, and the registry
entry points raise akerr_ErrorContext * instead of returning int. See
deps/libakerror/UPGRADING.md.
The break was not only source-level. libakgl's codes sat at
AKERR_LAST_ERRNO_VALUE + 18 through + 22, and 1.0.0 claimed exactly
those five offsets for its own AKERR_STATUS_* registry codes, so every
AKGL_ERR_* was aliasing a libakerror status. HANDLE(e,
AKGL_ERR_LOGICINTERRUPT) at physics.c:222 would have swallowed a
foreign-name refusal.
- Move the band to AKERR_FIRST_CONSUMER_STATUS (256) as fixed offsets,
so a libc that grows an errno cannot move the codes, and add
AKGL_ERR_OWNER, AKGL_ERR_LIMIT and AKGL_ERR_COUNT to describe it.
- Reserve the range and register the names through the owned entry
points, PASS-ing each: these are AKERR_NOIGNORE, and the old
akerr_name_for_status calls discarded failure silently.
- Drop the AKERR_MAX_ERR_VALUE=256 compile definition.
- Guard on AKERR_FIRST_CONSUMER_STATUS in include/akgl/error.h, which
now includes <akerror.h> so the guard is reliable. The embedded build
is fine, but the find_package path can pick up a stale installed
header, and 1.0.0 has an soname, so that pairing is an ABI mismatch
rather than a compile problem. Same guard libakstdlib already carries.
Registration also moves out of akgl_heap_init into a new akgl_error_init
in src/error.c. It was in the heap pool's initializer only because that
was the first thing akgl_game_init called, and the upgrade turned five
fire-and-forget name calls into a library-wide ownership claim that can
fail. That placement was hiding a defect: game.c raises AKGL_ERR_SDL
when SDL_CreateMutex fails, five lines before akgl_heap_init ran, so the
earliest error path in the library was guaranteed to print "Unknown
Error". akgl_error_init is now the first statement in akgl_game_init.
Callers that drive subsystems directly must call akgl_error_init first;
it is idempotent, so ordering it precisely is not required. The eleven
test suites that relied on akgl_heap_init to name their statuses now
call it explicitly, or their failure messages would have degraded to
"Unknown Error".
Add tests/error.c: assert every code reads back its registered name,
that the name table and AKGL_ERR_COUNT agree, that a foreign owner is
refused with AKERR_STATUS_NAME_FOREIGN and AKERR_STATUS_RANGE_OVERLAP,
and that repeating the init is a no-op. That last one is a live
constraint, not a triviality -- libakerror treats only an identical
reservation as a repeat, so a subset or superset raises.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:20:28 -04:00
|
|
|
error
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
game
|
|
|
|
|
heap
|
|
|
|
|
json_helpers
|
|
|
|
|
physics
|
|
|
|
|
registry
|
|
|
|
|
sprite
|
|
|
|
|
staticstring
|
2026-07-31 06:55:25 -04:00
|
|
|
text
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
tilemap
|
|
|
|
|
util
|
Derive the library version from one place and give the .so a soname
The version was written down twice and agreed with itself by luck.
AKGL_VERSION was hand-maintained in include/akgl/game.h, and nothing
connected it to the build, which had no version at all:
- project() declared no VERSION, so the @PROJECT_VERSION@ substitution
in akgl.pc.in expanded to nothing and every installed akgl.pc shipped
an empty Version field. pkg-config --modversion returned "" and
--atleast-version could not work at all.
- libakgl.so had no VERSION or SOVERSION, so there was no soname and no
symlink chain. A stale libakgl could be paired with new headers
silently, which is the failure libakerror added its own soname to
prevent.
- MY_LIBRARY_VERSION at CMakeLists.txt:288 was never set anywhere. It
built main_lib_dest as "lib/akgl-", and main_lib_dest was then never
read. Dead line, removed.
project(akgl VERSION 0.1.0) is now the only place the number appears. It
drives the generated include/akgl/version.h, the shared library VERSION
and SOVERSION, and the Version field in akgl.pc. Held at 0.1.0 to match
the constant it replaces, so akgl_game_load_versioncmp still compares
savegames against the same value.
include/akgl/version.h is generated by configure_file from version.h.in
and publishes AKGL_VERSION, AKGL_VERSION_MAJOR/MINOR/PATCH and
AKGL_VERSION_AT_LEAST(major, minor, patch). That macro is the point:
libakstdlib could not write that test against libakerror, which
publishes no version macro, and had to feature-test on
AKERR_FIRST_CONSUMER_STATUS instead. game.h now includes the generated
header rather than defining the version itself, so consumers see
AKGL_VERSION exactly where they saw it before.
While the major version is 0 the soname carries major.minor, giving
libakgl.so.0.1. A plain SOVERSION 0 would assert that 0.1.0 and 0.2.0
are ABI-interchangeable, and they are not -- the preceding commit alone
added akgl_error_init. At 1.0.0 the soname becomes the major alone,
matching libakerror.
akgl_version() in src/version.c reports the version of the libakgl that
is actually linked, where AKGL_VERSION reports what the caller compiled
against. Comparing the two is the only way to catch a stale shared
library on the loader path; the macro alone cannot see it. It returns a
string rather than an akerr_ErrorContext * because it cannot fail, for
the same reason akerr_name_for_status does.
Add tests/version.c: the string and the numeric components must describe
one version, the linked library must agree with the headers, and
AKGL_VERSION_AT_LEAST must order correctly at the major, minor and patch
boundaries. Verified out of band that bumping project() to 1.2.3 moves
version.h, akgl.pc and the soname together, and that an install produces
the libakgl.so -> .so.0.1 -> .so.0.1.0 chain with SONAME libakgl.so.0.1.
Also ignore include/akgl/version.h. include/ precedes the build tree on
the include path, so a stray copy there would shadow the generated one
and pin every consumer to whatever version it was generated at.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:36:50 -04:00
|
|
|
version
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
)
|
|
|
|
|
|
Upgrade to libakstdlib 0.1.0
Bump deps/libakstdlib five commits to 95e5002, which versions the library
at 0.1.0 with an soname and a ConfigVersion file, upgrades its own
libakerror to 1.0.0, namespaces its coverage target when embedded, and
raises its libc-wrapper coverage. The public header diff is purely
additive -- nothing removed, no signature changed -- so libakgl's nine
aksl_* call sites needed no edits. What broke was the build.
A default `cmake -S . -B build` stopped configuring:
add_executable cannot create target "test_version" because another
target with the same name already exists. The existing target is an
executable created in source directory ".../deps/libakstdlib"
The versioning commit added tests/test_version.c to libakstdlib.
EXCLUDE_FROM_ALL keeps that target from being built, but
add_subdirectory still creates it, so it collided with the version suite
added in the preceding commit. Build libakgl's test programs as
akgl_test_<name> instead. The CTest names are unchanged -- ctest -R
version still selects it -- and a dependency is now free to ship a test
of any name.
Ask find_package for libakstdlib 0.1 rather than any version. 0.1.0
ships akstdlibConfigVersion.cmake with SameMinorVersion compatibility,
mirroring its libakstdlib.so.0.1 soname, so this accepts any 0.1.x and
refuses 0.2 and 1.0. Unversioned, the non-embedded path would have taken
an ABI-incompatible libakstdlib without complaint.
libakerror is deliberately left unversioned in find_package. It installs
akerrorConfig.cmake and akerrorTargets.cmake but no
akerrorConfigVersion.cmake, so find_package(akerror 1.0) fails against a
correct install rather than a stale one. Its floor stays with the #error
in include/akgl/error.h. Worth fixing upstream.
Verified: clean configure, build and 16/16 ctest; a -DAKGL_COVERAGE=ON
tree configures, builds and passes 18/18, so libakstdlib's embedded
coverage-target rename does not collide here. Against a temp-prefix
install of 95e5002, find_package(akstdlib) accepts 0.1 and 0.1.0 and
refuses 0.2 and 1.0, and find_package(akerror 1.0) fails for the missing
version file as described.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:55:18 -04:00
|
|
|
# The executables carry an akgl_ prefix but the CTest names do not: a vendored
|
|
|
|
|
# dependency is free to ship its own tests/version.c, and libakstdlib now does.
|
|
|
|
|
# Its target is created by add_subdirectory even though EXCLUDE_FROM_ALL keeps
|
|
|
|
|
# it from being built, so an unprefixed test_version here is a configure error.
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
foreach(suite IN LISTS AKGL_TEST_SUITES)
|
Upgrade to libakstdlib 0.1.0
Bump deps/libakstdlib five commits to 95e5002, which versions the library
at 0.1.0 with an soname and a ConfigVersion file, upgrades its own
libakerror to 1.0.0, namespaces its coverage target when embedded, and
raises its libc-wrapper coverage. The public header diff is purely
additive -- nothing removed, no signature changed -- so libakgl's nine
aksl_* call sites needed no edits. What broke was the build.
A default `cmake -S . -B build` stopped configuring:
add_executable cannot create target "test_version" because another
target with the same name already exists. The existing target is an
executable created in source directory ".../deps/libakstdlib"
The versioning commit added tests/test_version.c to libakstdlib.
EXCLUDE_FROM_ALL keeps that target from being built, but
add_subdirectory still creates it, so it collided with the version suite
added in the preceding commit. Build libakgl's test programs as
akgl_test_<name> instead. The CTest names are unchanged -- ctest -R
version still selects it -- and a dependency is now free to ship a test
of any name.
Ask find_package for libakstdlib 0.1 rather than any version. 0.1.0
ships akstdlibConfigVersion.cmake with SameMinorVersion compatibility,
mirroring its libakstdlib.so.0.1 soname, so this accepts any 0.1.x and
refuses 0.2 and 1.0. Unversioned, the non-embedded path would have taken
an ABI-incompatible libakstdlib without complaint.
libakerror is deliberately left unversioned in find_package. It installs
akerrorConfig.cmake and akerrorTargets.cmake but no
akerrorConfigVersion.cmake, so find_package(akerror 1.0) fails against a
correct install rather than a stale one. Its floor stays with the #error
in include/akgl/error.h. Worth fixing upstream.
Verified: clean configure, build and 16/16 ctest; a -DAKGL_COVERAGE=ON
tree configures, builds and passes 18/18, so libakstdlib's embedded
coverage-target rename does not collide here. Against a temp-prefix
install of 95e5002, find_package(akstdlib) accepts 0.1 and 0.1.0 and
refuses 0.2 and 1.0, and find_package(akerror 1.0) fails for the missing
version file as described.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:55:18 -04:00
|
|
|
add_executable(akgl_test_${suite} tests/${suite}.c)
|
|
|
|
|
add_test(NAME ${suite} COMMAND akgl_test_${suite})
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
endforeach()
|
|
|
|
|
|
Upgrade to libakstdlib 0.1.0
Bump deps/libakstdlib five commits to 95e5002, which versions the library
at 0.1.0 with an soname and a ConfigVersion file, upgrades its own
libakerror to 1.0.0, namespaces its coverage target when embedded, and
raises its libc-wrapper coverage. The public header diff is purely
additive -- nothing removed, no signature changed -- so libakgl's nine
aksl_* call sites needed no edits. What broke was the build.
A default `cmake -S . -B build` stopped configuring:
add_executable cannot create target "test_version" because another
target with the same name already exists. The existing target is an
executable created in source directory ".../deps/libakstdlib"
The versioning commit added tests/test_version.c to libakstdlib.
EXCLUDE_FROM_ALL keeps that target from being built, but
add_subdirectory still creates it, so it collided with the version suite
added in the preceding commit. Build libakgl's test programs as
akgl_test_<name> instead. The CTest names are unchanged -- ctest -R
version still selects it -- and a dependency is now free to ship a test
of any name.
Ask find_package for libakstdlib 0.1 rather than any version. 0.1.0
ships akstdlibConfigVersion.cmake with SameMinorVersion compatibility,
mirroring its libakstdlib.so.0.1 soname, so this accepts any 0.1.x and
refuses 0.2 and 1.0. Unversioned, the non-embedded path would have taken
an ABI-incompatible libakstdlib without complaint.
libakerror is deliberately left unversioned in find_package. It installs
akerrorConfig.cmake and akerrorTargets.cmake but no
akerrorConfigVersion.cmake, so find_package(akerror 1.0) fails against a
correct install rather than a stale one. Its floor stays with the #error
in include/akgl/error.h. Worth fixing upstream.
Verified: clean configure, build and 16/16 ctest; a -DAKGL_COVERAGE=ON
tree configures, builds and passes 18/18, so libakstdlib's embedded
coverage-target rename does not collide here. Against a temp-prefix
install of 95e5002, find_package(akstdlib) accepts 0.1 and 0.1.0 and
refuses 0.2 and 1.0, and find_package(akerror 1.0) fails for the missing
version file as described.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:55:18 -04:00
|
|
|
add_test(NAME semver_unit COMMAND akgl_test_semver_unit)
|
2025-08-03 10:07:35 -04:00
|
|
|
|
2026-07-29 18:01:05 -04:00
|
|
|
set_tests_properties(
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
${AKGL_TEST_SUITES} semver_unit
|
2026-07-29 18:42:09 -04:00
|
|
|
PROPERTIES WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" TIMEOUT 30
|
2026-07-29 18:01:05 -04:00
|
|
|
)
|
|
|
|
|
|
2025-08-03 10:07:35 -04:00
|
|
|
# Specify include directories for the library's headers (if applicable)
|
2026-05-07 22:20:10 -04:00
|
|
|
target_include_directories(akgl PUBLIC
|
2026-05-08 23:15:11 -04:00
|
|
|
include/
|
|
|
|
|
deps/semver/
|
Derive the library version from one place and give the .so a soname
The version was written down twice and agreed with itself by luck.
AKGL_VERSION was hand-maintained in include/akgl/game.h, and nothing
connected it to the build, which had no version at all:
- project() declared no VERSION, so the @PROJECT_VERSION@ substitution
in akgl.pc.in expanded to nothing and every installed akgl.pc shipped
an empty Version field. pkg-config --modversion returned "" and
--atleast-version could not work at all.
- libakgl.so had no VERSION or SOVERSION, so there was no soname and no
symlink chain. A stale libakgl could be paired with new headers
silently, which is the failure libakerror added its own soname to
prevent.
- MY_LIBRARY_VERSION at CMakeLists.txt:288 was never set anywhere. It
built main_lib_dest as "lib/akgl-", and main_lib_dest was then never
read. Dead line, removed.
project(akgl VERSION 0.1.0) is now the only place the number appears. It
drives the generated include/akgl/version.h, the shared library VERSION
and SOVERSION, and the Version field in akgl.pc. Held at 0.1.0 to match
the constant it replaces, so akgl_game_load_versioncmp still compares
savegames against the same value.
include/akgl/version.h is generated by configure_file from version.h.in
and publishes AKGL_VERSION, AKGL_VERSION_MAJOR/MINOR/PATCH and
AKGL_VERSION_AT_LEAST(major, minor, patch). That macro is the point:
libakstdlib could not write that test against libakerror, which
publishes no version macro, and had to feature-test on
AKERR_FIRST_CONSUMER_STATUS instead. game.h now includes the generated
header rather than defining the version itself, so consumers see
AKGL_VERSION exactly where they saw it before.
While the major version is 0 the soname carries major.minor, giving
libakgl.so.0.1. A plain SOVERSION 0 would assert that 0.1.0 and 0.2.0
are ABI-interchangeable, and they are not -- the preceding commit alone
added akgl_error_init. At 1.0.0 the soname becomes the major alone,
matching libakerror.
akgl_version() in src/version.c reports the version of the libakgl that
is actually linked, where AKGL_VERSION reports what the caller compiled
against. Comparing the two is the only way to catch a stale shared
library on the loader path; the macro alone cannot see it. It returns a
string rather than an akerr_ErrorContext * because it cannot fail, for
the same reason akerr_name_for_status does.
Add tests/version.c: the string and the numeric components must describe
one version, the linked library must agree with the headers, and
AKGL_VERSION_AT_LEAST must order correctly at the major, minor and patch
boundaries. Verified out of band that bumping project() to 1.2.3 moves
version.h, akgl.pc and the soname together, and that an install produces
the libakgl.so -> .so.0.1 -> .so.0.1.0 chain with SONAME libakgl.so.0.1.
Also ignore include/akgl/version.h. include/ precedes the build tree on
the include path, so a stray copy there would shadow the generated one
and pin every consumer to whatever version it was generated at.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:36:50 -04:00
|
|
|
# akgl/version.h is generated by configure_file, so it lives in the build tree
|
|
|
|
|
# rather than beside the headers it is included from.
|
|
|
|
|
${CMAKE_CURRENT_BINARY_DIR}/include/
|
2025-08-03 10:07:35 -04:00
|
|
|
)
|
|
|
|
|
|
2026-07-30 01:25:26 -04:00
|
|
|
if(AKGL_COVERAGE)
|
|
|
|
|
target_compile_options(akgl PRIVATE --coverage -O0 -g)
|
|
|
|
|
target_link_options(akgl PRIVATE --coverage)
|
|
|
|
|
|
|
|
|
|
set(AKGL_COVERAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}/coverage")
|
|
|
|
|
file(MAKE_DIRECTORY "${AKGL_COVERAGE_DIR}")
|
|
|
|
|
|
|
|
|
|
add_test(
|
|
|
|
|
NAME coverage_reset
|
|
|
|
|
COMMAND ${GCOVR_EXECUTABLE}
|
|
|
|
|
--root "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
|
|
|
--object-directory "${CMAKE_CURRENT_BINARY_DIR}"
|
|
|
|
|
--delete
|
|
|
|
|
)
|
|
|
|
|
set_tests_properties(coverage_reset PROPERTIES FIXTURES_SETUP akgl_coverage)
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
# Any suite missing from this list runs outside the fixture and has its
|
|
|
|
|
# counters discarded by coverage_reset.
|
2026-07-30 01:25:26 -04:00
|
|
|
set_tests_properties(
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
${AKGL_TEST_SUITES} semver_unit
|
2026-07-30 01:25:26 -04:00
|
|
|
PROPERTIES FIXTURES_REQUIRED akgl_coverage
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
add_test(
|
|
|
|
|
NAME coverage_report
|
|
|
|
|
COMMAND ${GCOVR_EXECUTABLE}
|
|
|
|
|
--root "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
|
|
|
--object-directory "${CMAKE_CURRENT_BINARY_DIR}"
|
|
|
|
|
--filter "${CMAKE_CURRENT_SOURCE_DIR}/src/"
|
|
|
|
|
--xml-pretty
|
|
|
|
|
--xml "${AKGL_COVERAGE_DIR}/coverage.xml"
|
|
|
|
|
--html-details "${AKGL_COVERAGE_DIR}/index.html"
|
|
|
|
|
)
|
|
|
|
|
set_tests_properties(
|
|
|
|
|
coverage_report
|
|
|
|
|
PROPERTIES
|
|
|
|
|
FIXTURES_CLEANUP akgl_coverage
|
|
|
|
|
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
|
|
|
|
)
|
|
|
|
|
endif()
|
|
|
|
|
|
2026-05-07 22:20:10 -04:00
|
|
|
target_link_libraries(akgl
|
2026-05-03 23:57:55 -04:00
|
|
|
PUBLIC
|
|
|
|
|
SDL3::SDL3
|
|
|
|
|
SDL3_image::SDL3_image
|
|
|
|
|
SDL3_mixer::SDL3_mixer
|
2026-05-06 11:12:42 -04:00
|
|
|
SDL3_ttf::SDL3_ttf
|
2026-05-10 00:03:45 -04:00
|
|
|
akstdlib::akstdlib
|
2026-05-12 16:45:42 -04:00
|
|
|
akerror::akerror
|
|
|
|
|
jansson::jansson
|
2026-05-03 23:57:55 -04:00
|
|
|
)
|
|
|
|
|
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
foreach(suite IN LISTS AKGL_TEST_SUITES)
|
Upgrade to libakstdlib 0.1.0
Bump deps/libakstdlib five commits to 95e5002, which versions the library
at 0.1.0 with an soname and a ConfigVersion file, upgrades its own
libakerror to 1.0.0, namespaces its coverage target when embedded, and
raises its libc-wrapper coverage. The public header diff is purely
additive -- nothing removed, no signature changed -- so libakgl's nine
aksl_* call sites needed no edits. What broke was the build.
A default `cmake -S . -B build` stopped configuring:
add_executable cannot create target "test_version" because another
target with the same name already exists. The existing target is an
executable created in source directory ".../deps/libakstdlib"
The versioning commit added tests/test_version.c to libakstdlib.
EXCLUDE_FROM_ALL keeps that target from being built, but
add_subdirectory still creates it, so it collided with the version suite
added in the preceding commit. Build libakgl's test programs as
akgl_test_<name> instead. The CTest names are unchanged -- ctest -R
version still selects it -- and a dependency is now free to ship a test
of any name.
Ask find_package for libakstdlib 0.1 rather than any version. 0.1.0
ships akstdlibConfigVersion.cmake with SameMinorVersion compatibility,
mirroring its libakstdlib.so.0.1 soname, so this accepts any 0.1.x and
refuses 0.2 and 1.0. Unversioned, the non-embedded path would have taken
an ABI-incompatible libakstdlib without complaint.
libakerror is deliberately left unversioned in find_package. It installs
akerrorConfig.cmake and akerrorTargets.cmake but no
akerrorConfigVersion.cmake, so find_package(akerror 1.0) fails against a
correct install rather than a stale one. Its floor stays with the #error
in include/akgl/error.h. Worth fixing upstream.
Verified: clean configure, build and 16/16 ctest; a -DAKGL_COVERAGE=ON
tree configures, builds and passes 18/18, so libakstdlib's embedded
coverage-target rename does not collide here. Against a temp-prefix
install of 95e5002, find_package(akstdlib) accepts 0.1 and 0.1.0 and
refuses 0.2 and 1.0, and find_package(akerror 1.0) fails for the missing
version file as described.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:55:18 -04:00
|
|
|
target_link_libraries(akgl_test_${suite} PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer jansson::jansson -lm)
|
|
|
|
|
target_include_directories(akgl_test_${suite} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/tests")
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
endforeach()
|
2025-08-03 10:07:35 -04:00
|
|
|
|
2026-05-12 16:45:42 -04:00
|
|
|
target_link_libraries(charviewer PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer jansson::jansson -lm)
|
2025-08-04 21:37:36 -04:00
|
|
|
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
# When the vendored SDL satellite libraries are built in-tree they land in per-
|
|
|
|
|
# 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".
|
|
|
|
|
# Bake those directories into the build-tree RPATH. Installed builds resolve the
|
|
|
|
|
# same libraries through find_package and need no help.
|
|
|
|
|
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
|
|
|
|
set(AKGL_VENDORED_RPATH
|
|
|
|
|
"$<TARGET_FILE_DIR:SDL3::SDL3>"
|
|
|
|
|
"$<TARGET_FILE_DIR:SDL3_image::SDL3_image>"
|
|
|
|
|
"$<TARGET_FILE_DIR:SDL3_ttf::SDL3_ttf>"
|
|
|
|
|
"$<TARGET_FILE_DIR:SDL3_mixer::SDL3_mixer>"
|
|
|
|
|
"$<TARGET_FILE_DIR:akerror::akerror>"
|
|
|
|
|
"$<TARGET_FILE_DIR:akstdlib::akstdlib>"
|
|
|
|
|
)
|
|
|
|
|
foreach(suite IN LISTS AKGL_TEST_SUITES)
|
Upgrade to libakstdlib 0.1.0
Bump deps/libakstdlib five commits to 95e5002, which versions the library
at 0.1.0 with an soname and a ConfigVersion file, upgrades its own
libakerror to 1.0.0, namespaces its coverage target when embedded, and
raises its libc-wrapper coverage. The public header diff is purely
additive -- nothing removed, no signature changed -- so libakgl's nine
aksl_* call sites needed no edits. What broke was the build.
A default `cmake -S . -B build` stopped configuring:
add_executable cannot create target "test_version" because another
target with the same name already exists. The existing target is an
executable created in source directory ".../deps/libakstdlib"
The versioning commit added tests/test_version.c to libakstdlib.
EXCLUDE_FROM_ALL keeps that target from being built, but
add_subdirectory still creates it, so it collided with the version suite
added in the preceding commit. Build libakgl's test programs as
akgl_test_<name> instead. The CTest names are unchanged -- ctest -R
version still selects it -- and a dependency is now free to ship a test
of any name.
Ask find_package for libakstdlib 0.1 rather than any version. 0.1.0
ships akstdlibConfigVersion.cmake with SameMinorVersion compatibility,
mirroring its libakstdlib.so.0.1 soname, so this accepts any 0.1.x and
refuses 0.2 and 1.0. Unversioned, the non-embedded path would have taken
an ABI-incompatible libakstdlib without complaint.
libakerror is deliberately left unversioned in find_package. It installs
akerrorConfig.cmake and akerrorTargets.cmake but no
akerrorConfigVersion.cmake, so find_package(akerror 1.0) fails against a
correct install rather than a stale one. Its floor stays with the #error
in include/akgl/error.h. Worth fixing upstream.
Verified: clean configure, build and 16/16 ctest; a -DAKGL_COVERAGE=ON
tree configures, builds and passes 18/18, so libakstdlib's embedded
coverage-target rename does not collide here. Against a temp-prefix
install of 95e5002, find_package(akstdlib) accepts 0.1 and 0.1.0 and
refuses 0.2 and 1.0, and find_package(akerror 1.0) fails for the missing
version file as described.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:55:18 -04:00
|
|
|
set_target_properties(akgl_test_${suite} PROPERTIES BUILD_RPATH "${AKGL_VENDORED_RPATH}")
|
Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an
extension to the actor suite, and register every suite through a single
CMake list so a new test file cannot be left out of the coverage fixture.
Give the test targets a build-tree RPATH and prepend the build tree to
LD_LIBRARY_PATH for CTest, so a developer with a previously installed
libakgl.so exercises the library that was just compiled.
Fix six defects the new tests exposed:
- akgl_physics_simulate read self->gravity_time before its NULL check, so a
NULL backend crashed instead of reporting AKERR_NULLPOINTER.
- akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose
inside the PROCESS switch. An ordinary save never flushed or closed its
stream and produced an empty file.
- akgl_game_save_actors wrote each name table terminator from the address of
a single char, emitting stack contents into the save file and a sentinel
the loader could not recognize.
- akgl_game_load_objectnamemap used CATCH directly inside while(1), where the
break leaves the loop rather than propagating, so a truncated name table
loaded as a successful game.
- akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no
NULL check, unlike their left and right counterparts.
- akgl_actor_logic_movement checked actor twice instead of checking
actor->basechar before dereferencing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:03:21 -04:00
|
|
|
endforeach()
|
|
|
|
|
set_target_properties(charviewer akgl PROPERTIES BUILD_RPATH "${AKGL_VENDORED_RPATH}")
|
|
|
|
|
|
|
|
|
|
# RPATH alone is not enough: LD_LIBRARY_PATH is searched first, so a developer
|
|
|
|
|
# who has previously run rebuild.sh has an installed libakgl.so ahead of the
|
|
|
|
|
# one under test. Prepend the build tree for the CTest run so the suite always
|
|
|
|
|
# exercises what was just compiled.
|
|
|
|
|
set(AKGL_TEST_LIBPATH
|
|
|
|
|
"${CMAKE_CURRENT_BINARY_DIR}"
|
|
|
|
|
"${CMAKE_CURRENT_BINARY_DIR}/deps/SDL"
|
|
|
|
|
"${CMAKE_CURRENT_BINARY_DIR}/deps/SDL_image"
|
|
|
|
|
"${CMAKE_CURRENT_BINARY_DIR}/deps/SDL_ttf"
|
|
|
|
|
"${CMAKE_CURRENT_BINARY_DIR}/deps/SDL_mixer"
|
|
|
|
|
"${CMAKE_CURRENT_BINARY_DIR}/deps/libakerror"
|
|
|
|
|
"${CMAKE_CURRENT_BINARY_DIR}/deps/libakstdlib"
|
|
|
|
|
)
|
|
|
|
|
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22")
|
|
|
|
|
set(AKGL_TEST_ENV_MOD "")
|
|
|
|
|
foreach(dir IN LISTS AKGL_TEST_LIBPATH)
|
|
|
|
|
list(APPEND AKGL_TEST_ENV_MOD "LD_LIBRARY_PATH=path_list_prepend:${dir}")
|
|
|
|
|
endforeach()
|
|
|
|
|
set_tests_properties(
|
|
|
|
|
${AKGL_TEST_SUITES}
|
|
|
|
|
PROPERTIES ENVIRONMENT_MODIFICATION "${AKGL_TEST_ENV_MOD}"
|
|
|
|
|
)
|
|
|
|
|
else()
|
|
|
|
|
string(REPLACE ";" ":" AKGL_TEST_LIBPATH_JOINED "${AKGL_TEST_LIBPATH}")
|
|
|
|
|
set_tests_properties(
|
|
|
|
|
${AKGL_TEST_SUITES}
|
|
|
|
|
PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${AKGL_TEST_LIBPATH_JOINED}:$ENV{LD_LIBRARY_PATH}"
|
|
|
|
|
)
|
|
|
|
|
endif()
|
|
|
|
|
endif()
|
|
|
|
|
|
2026-07-29 18:42:09 -04:00
|
|
|
# Mutation testing copies the repository to scratch space, applies one small
|
|
|
|
|
# source change at a time, and verifies that the passing tests detect it. The
|
|
|
|
|
# intentionally failing character test is excluded by the harness.
|
|
|
|
|
find_package(Python3 COMPONENTS Interpreter)
|
|
|
|
|
if(Python3_FOUND)
|
|
|
|
|
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
|
|
|
|
set(AKGL_MUTATION_TARGET mutation)
|
|
|
|
|
else()
|
|
|
|
|
set(AKGL_MUTATION_TARGET akgl_mutation)
|
|
|
|
|
endif()
|
|
|
|
|
add_custom_target(${AKGL_MUTATION_TARGET}
|
|
|
|
|
COMMAND ${Python3_EXECUTABLE}
|
|
|
|
|
${CMAKE_CURRENT_SOURCE_DIR}/scripts/mutation_test.py
|
|
|
|
|
--source-root ${CMAKE_CURRENT_SOURCE_DIR}
|
|
|
|
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
|
|
|
|
USES_TERMINAL
|
|
|
|
|
COMMENT "Running mutation tests (breaks a scratch copy, expects tests to fail)"
|
|
|
|
|
)
|
|
|
|
|
endif()
|
|
|
|
|
|
2026-05-07 22:20:10 -04:00
|
|
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/akgl.pc DESTINATION "lib/pkgconfig/")
|
Derive the library version from one place and give the .so a soname
The version was written down twice and agreed with itself by luck.
AKGL_VERSION was hand-maintained in include/akgl/game.h, and nothing
connected it to the build, which had no version at all:
- project() declared no VERSION, so the @PROJECT_VERSION@ substitution
in akgl.pc.in expanded to nothing and every installed akgl.pc shipped
an empty Version field. pkg-config --modversion returned "" and
--atleast-version could not work at all.
- libakgl.so had no VERSION or SOVERSION, so there was no soname and no
symlink chain. A stale libakgl could be paired with new headers
silently, which is the failure libakerror added its own soname to
prevent.
- MY_LIBRARY_VERSION at CMakeLists.txt:288 was never set anywhere. It
built main_lib_dest as "lib/akgl-", and main_lib_dest was then never
read. Dead line, removed.
project(akgl VERSION 0.1.0) is now the only place the number appears. It
drives the generated include/akgl/version.h, the shared library VERSION
and SOVERSION, and the Version field in akgl.pc. Held at 0.1.0 to match
the constant it replaces, so akgl_game_load_versioncmp still compares
savegames against the same value.
include/akgl/version.h is generated by configure_file from version.h.in
and publishes AKGL_VERSION, AKGL_VERSION_MAJOR/MINOR/PATCH and
AKGL_VERSION_AT_LEAST(major, minor, patch). That macro is the point:
libakstdlib could not write that test against libakerror, which
publishes no version macro, and had to feature-test on
AKERR_FIRST_CONSUMER_STATUS instead. game.h now includes the generated
header rather than defining the version itself, so consumers see
AKGL_VERSION exactly where they saw it before.
While the major version is 0 the soname carries major.minor, giving
libakgl.so.0.1. A plain SOVERSION 0 would assert that 0.1.0 and 0.2.0
are ABI-interchangeable, and they are not -- the preceding commit alone
added akgl_error_init. At 1.0.0 the soname becomes the major alone,
matching libakerror.
akgl_version() in src/version.c reports the version of the libakgl that
is actually linked, where AKGL_VERSION reports what the caller compiled
against. Comparing the two is the only way to catch a stale shared
library on the loader path; the macro alone cannot see it. It returns a
string rather than an akerr_ErrorContext * because it cannot fail, for
the same reason akerr_name_for_status does.
Add tests/version.c: the string and the numeric components must describe
one version, the linked library must agree with the headers, and
AKGL_VERSION_AT_LEAST must order correctly at the major, minor and patch
boundaries. Verified out of band that bumping project() to 1.2.3 moves
version.h, akgl.pc and the soname together, and that an install produces
the libakgl.so -> .so.0.1 -> .so.0.1.0 chain with SONAME libakgl.so.0.1.
Also ignore include/akgl/version.h. include/ precedes the build tree on
the include path, so a stray copy there would shadow the generated one
and pin every consumer to whatever version it was generated at.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:36:50 -04:00
|
|
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/akgl/version.h DESTINATION "include/akgl/")
|
2026-05-07 22:20:10 -04:00
|
|
|
install(TARGETS akgl DESTINATION "lib/")
|
2026-05-08 23:15:11 -04:00
|
|
|
install(FILES "deps/semver/semver.h" DESTINATION "include/")
|
2026-05-07 22:20:10 -04:00
|
|
|
install(FILES "include/akgl/actor.h" DESTINATION "include/akgl/")
|
2026-05-08 22:01:56 -04:00
|
|
|
install(FILES "include/akgl/types.h" DESTINATION "include/akgl/")
|
2026-05-07 22:20:10 -04:00
|
|
|
install(FILES "include/akgl/text.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/assets.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/character.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/error.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/draw.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/game.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/controller.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/heap.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/iterator.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/json_helpers.h" DESTINATION "include/akgl/")
|
2026-05-26 11:22:45 -04:00
|
|
|
install(FILES "include/akgl/renderer.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/physics.h" DESTINATION "include/akgl/")
|
2026-05-07 22:20:10 -04:00
|
|
|
install(FILES "include/akgl/registry.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/sprite.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/staticstring.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/tilemap.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES "include/akgl/util.h" DESTINATION "include/akgl/")
|
|
|
|
|
install(FILES ${GAMECONTROLLERDB_H} DESTINATION "include/akgl/")
|