diff --git a/CLAUDE.md b/CLAUDE.md index 00ab5c4..c8ad573 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -81,13 +81,20 @@ that repo is next touched. See the error-code section below for a live collision | Submodule | Version | soname | ABI rule | Version API | |---|---|---|---|---| | `deps/libakerror` | 1.0.0 | `libakerror.so.1` | major only | **none** — no version macro, no `ConfigVersion` file | -| `deps/libakstdlib` | 0.1.0 | `libakstdlib.so.0.1` | **`MAJOR.MINOR` while major is 0** | `AKSL_VERSION_*`, `aksl_version()`, `AKSL_VERSION_CHECK()` | -| `deps/libakgl` | 0.1.0 | `libakgl.so.0.1` | **`MAJOR.MINOR` while major is 0** | `AKGL_VERSION*`, `akgl_version()`, `AKGL_VERSION_AT_LEAST()` | +| `deps/libakstdlib` | 0.2.0 | `libakstdlib.so.0.2` | **`MAJOR.MINOR` while major is 0** | `AKSL_VERSION_*`, `aksl_version()`, `AKSL_VERSION_CHECK()` | +| `deps/libakgl` | 0.2.0 | `libakgl.so.0.2` | **`MAJOR.MINOR` while major is 0** | `AKGL_VERSION*`, `akgl_version()`, `AKGL_VERSION_AT_LEAST()` | For both 0.x libraries the soname carries `MAJOR.MINOR` deliberately: 0.1 and 0.2 are *different* -ABIs, and both become major-only at 1.0. Do not read `0.1 → 0.2` as a compatible bump. +ABIs, and both become major-only at 1.0. Do not read `0.1 → 0.2` as a compatible bump — and both +libraries have now actually made that jump, so anything built against the 0.1 headers must be +rebuilt rather than relinked. -`libakstdlib` 0.1.0 added a version API worth using. `akstdlib.h` now pulls in +**The two moved together and had to.** `libakgl` 0.2.0 consumes the `libakstdlib` 0.2.0 API, so a +tree that pins `libakstdlib` at 0.1.0 and adds `libakgl` by `add_subdirectory()` compiles +0.2.0-era code against 0.1.0 headers and fails on `aksl_fwrite`, `aksl_fread` and +`aksl_realpath`. Bump them as a pair. + +`libakstdlib` 0.1.0 added a version API worth using, and it still applies at 0.2.0. `akstdlib.h` now pulls in ``, which is **generated into the build tree** by CMake and installed beside `akstdlib.h` — so link `akstdlib::akstdlib` and let the target carry its include directories; hand-adding `deps/libakstdlib/include` to an include path gets you a missing-header error. It defines @@ -100,7 +107,7 @@ notices. It is a macro on purpose: it must expand at your call site to capture y `libakgl` 0.1.0 followed the same pattern one commit later, for the same reason: it had `AKGL_VERSION` hand-maintained in `game.h` and no `VERSION` on `project()` at all, so `akgl.pc` shipped an empty -`Version:` and the `.so` had no soname. Now `project(akgl VERSION 0.1.0)` is the single source and +`Version:` and the `.so` had no soname. Now `project(akgl VERSION 0.2.0)` is the single source and drives the generated `include/akgl/version.h` — which is `.gitignore`d, because `include/` precedes the build tree on the include path and a stray copy there would shadow the generated one and pin every consumer. It publishes `AKGL_VERSION_AT_LEAST(major, minor, patch)`, the compile-time test @@ -268,11 +275,17 @@ defect-free. When a known-failing test starts passing, CTest reports "unexpected cue to move it into `AKSL_TESTS` along with the fix. `libakerror` has the same split (`AKERR_TESTS` / `AKERR_WILL_FAIL_TESTS`). -That split is not academic for `libakstdlib`: `deps/libakstdlib/TODO.md` §2.1 lists six **confirmed** -defects, four with a known-failing test apiece. Several are in functions this port would otherwise -reach for by default — the `aksl_ato*` family cannot report a conversion failure at all, and the -linked-list functions truncate. **Read §2.1 before calling anything in `akstdlib.h` for the first -time**; `TODO.md` §1.9 in this repo records which calls are cleared for use here and which are not. +That split *used* to be load-bearing for `libakstdlib`, and no longer is: 0.2.0 fixed all six of the +confirmed defects its `TODO.md` §2.1 listed, folded the four known-failing tests back into the +suites for the things they test, and left `AKSL_KNOWN_FAILING_TESTS` empty. The `aksl_ato*` family +now raises `AKERR_VALUE` on no digits or trailing junk and `ERANGE` on overflow, the linked-list +functions no longer truncate, `AKERR_ITERATOR_BREAK` stops a tree traversal, and `aksl_realpath` no +longer reads uninitialised memory. + +`TODO.md` §1.9 in this repo is still the place to check before reaching into `akstdlib.h`, but it +is now a record of what changed rather than a list of bans. One caveat survives the upgrade: +`aksl_strhash_djb2` still sign-extends `char`, so a high-bit byte hashes differently from the +`unsigned char` answer — see §1.3, which explains why the symbol tables cannot reach it. The branch-coverage gate there was re-ratcheted 45 → 40 after the 1.0.0 bump, because the new `PREPARE_ERROR`/`FAIL_*` macros expand to more branches per call site — that is a denominator change, not a regression, and the same effect will show up in this repo's numbers. @@ -349,7 +362,7 @@ are used, so a later addition does not need a second reservation: | `"akbasic"` | 512 – 767 | ours; `AKBASIC_ERR_BASE` is 512 | **Every owner reserves at init, and each does it in its own initializer.** `akerr_init()` claims -0–255 for itself. `akgl_error_init()` (`deps/libakgl/src/error.c`, new in libakgl 0.1.0) claims +0–255 for itself. `akgl_error_init()` (`deps/libakgl/src/error.c`) claims `AKGL_ERR_BASE` = `AKERR_FIRST_CONSUMER_STATUS` = 256 through `AKGL_ERR_LIMIT - 1` = 260 and names all five codes. `libakstdlib` claims nothing. `akbasic_init()` claims 512–767.