diff --git a/MAINTENANCE.md b/MAINTENANCE.md index 059160c..418e576 100644 --- a/MAINTENANCE.md +++ b/MAINTENANCE.md @@ -166,7 +166,7 @@ a mixed build leaks pool slots or frees one twice rather than failing to link. |---|---|---|---|---| | `deps/libakerror` | 2.0.1 | `libakerror.so.2` | major only | **none** — no version macro; `include/akbasic/error.h` feature-tests `AKERR_THREAD_SAFE` and `AKERR_EXIT_STATUS_UNREPRESENTABLE` instead | | `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.7.0 | `libakgl.so.0.7` | **`MAJOR.MINOR` while major is 0** | `AKGL_VERSION*`, `akgl_version()`, `AKGL_VERSION_AT_LEAST()` | +| `deps/libakgl` | 0.8.0 | `libakgl.so.0.8` | **`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 @@ -479,8 +479,8 @@ not need a second reservation: |---|---|---| | `"libakerror"` | 0 – 255 | reserved by `akerr_init()`; do not touch | | *(none)* | — | `libakstdlib` deliberately reserves nothing and defines no codes of its own — it raises `AKERR_*` and propagates `errno`, both inside the reserved band. Its `tests/test_status_registry.c` pins that as a contract, so nobody has to coordinate with it | -| `"libakgl"` | 256 – 260 | reserved by `akgl_error_init()`; `AKGL_ERR_BASE` … `AKGL_ERR_LIMIT - 1`, five codes | -| *(free)* | 261 – 511 | headroom for `libakgl` to grow into; do not claim it | +| `"libakgl"` | 256 – 261 | reserved by `akgl_error_init()`; `AKGL_ERR_BASE` … `AKGL_ERR_LIMIT - 1`, six codes. Was five until 0.8.0 added `AKGL_ERR_COLLISION` | +| *(free)* | 262 – 511 | headroom for `libakgl` to grow into; do not claim it | | `"akbasic"` | 512 – 767 | ours; `AKBASIC_ERR_BASE` is 512 | Values 0–255 are the host errno space plus the `AKERR_*` codes. Consumers allocate from diff --git a/README.md b/README.md index 68fd897..da495df 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ nothing to install first. * [libakstdlib](https://source.starfort.tech/andrew/libakstdlib) 0.2.0 — libc wrappers that report through `libakerror`. String-to-number conversion goes straight to it, which is why `VAL("garbage")` is an error rather than a silent `0`. -* [libakgl](https://source.starfort.tech/andrew/libakgl) 0.7.0 — **optional**, only for +* [libakgl](https://source.starfort.tech/andrew/libakgl) 0.8.0 — **optional**, only for `-DAKBASIC_WITH_AKGL=ON`. Pulls in SDL3. Its soname carries `MAJOR.MINOR` while the major is 0, so rebuild rather than relink. * [basicinterpret](https://source.starfort.tech/andrew/basicinterpret) — the Go original. diff --git a/deps/libakgl b/deps/libakgl index e4aa6a5..149bee0 160000 --- a/deps/libakgl +++ b/deps/libakgl @@ -1 +1 @@ -Subproject commit e4aa6a50847a12c22544acf0b3b2953f5128c6af +Subproject commit 149bee0c993496f931c9d2cb06a27b1a0dcf209a diff --git a/docs/15-error-codes.md b/docs/15-error-codes.md index 11067e9..85b261e 100644 --- a/docs/15-error-codes.md +++ b/docs/15-error-codes.md @@ -123,7 +123,7 @@ just above the `errno` range, and they surface when something fails below the la rather than in it — `SCRATCH` on a file that will not delete gives its `Input Output Error`, and `VAL` of text that is not a number gives its `Value Error` rather than the interpreter's 517, because the conversion happens in `libakstdlib` and -the code comes back up with it. In the SDL build, `libakgl` owns 256 to 260 and an +the code comes back up with it. In the SDL build, `libakgl` owns 256 to 261 and an `SDL Error` can reach `ER#` if the renderer itself refuses. **Do not hardcode those numbers.** `libakerror`'s codes are defined as offsets from diff --git a/include/akbasic/akgl.h b/include/akbasic/akgl.h index 9011db9..03eb68a 100644 --- a/include/akbasic/akgl.h +++ b/include/akbasic/akgl.h @@ -12,7 +12,7 @@ * of these takes something the host already created and draws or plays through * it. None of them creates a device, and none of them pumps events. * - * Each initializer calls akgl_error_init() first. It reserves libakgl's 256-260 + * Each initializer calls akgl_error_init() first. It reserves libakgl's 256-261 * status band and names every AKGL_ERR_* code; akgl_game_init() calls it as its * first statement, but a program driving subsystems directly -- which is exactly * what an embedded interpreter does -- never goes through akgl_game_init() and @@ -56,6 +56,23 @@ * own suites needed -- the same defect `include/akbasic/error.h` guards for this * band, fixed at the source rather than worked around twice. * + * **0.8.0 broke nothing here either**, and is the largest of the three: a whole + * collision subsystem -- shapes, pooled proxies, a pluggable broad phase, a + * narrowphase answering with a contact -- none of which this target called on the + * day the floor moved. It is compatible by luck rather than by design, which is + * the argument for moving the floor rather than deciding for ourselves that a + * minor release was really compatible. + * + * Two things about it a reader here has to know. `akgl_Actor` grew fields, so + * its `sizeof` changed and a translation unit compiled against a 0.7 `actor.h` + * writes `renderfunc` and `actorData` at the wrong offsets -- and + * `src/sprite_akgl.c` writes exactly those two. The symptom is a jump through a + * garbage pointer on the first frame, which is precisely the case this guard + * exists to turn into a compile error. And libakgl's reserved status band grew + * from five codes to six with `AKGL_ERR_COLLISION`, so it now owns 256 to 261; + * `MAINTENANCE.md`'s coordinated range map and `docs/15-error-codes.md` both say + * so. + * * The soname carries MAJOR.MINOR while the major is 0, so 0.5, 0.6 and 0.7 are * different ABIs *by declaration* -- libakgl's versioning policy says a 0.x minor * bump may break, and the soname is built to match. The floor moves with every @@ -68,8 +85,8 @@ * at link time, because a missing symbol names a function and this names the * release. */ -#if !AKGL_VERSION_AT_LEAST(0, 7, 0) -#error "akbasic's libakgl adaptors require libakgl 0.7.0 or later" +#if !AKGL_VERSION_AT_LEAST(0, 8, 0) +#error "akbasic's libakgl adaptors require libakgl 0.8.0 or later" #endif #include diff --git a/include/akbasic/error.h b/include/akbasic/error.h index 1b417f3..eb3ec2d 100644 --- a/include/akbasic/error.h +++ b/include/akbasic/error.h @@ -51,11 +51,17 @@ /* * libakerror reserves 0-255 for the host's errno values and its own AKERR_* - * codes. libakgl claims 256-260. akbasic claims 512-767, leaving 261-511 as + * codes. libakgl claims 256-261 -- five codes until 0.8.0 added + * AKGL_ERR_COLLISION, six since. akbasic claims 512-767, leaving 262-511 as * headroom for libakgl to grow into -- see MAINTENANCE.md for the coordinated * range map, which is the only coordination there is: libakerror can enumerate * its consumers no better than we can. * + * **That growth is why the map is worth keeping current.** Nothing enforces the + * boundary between two libraries' bands at compile time; the first anyone would + * know of an overlap is a status printing under the wrong owner's name in a + * stack trace, which is a bad way to find out. + * * These are absolute constants, never offsets from AKERR_LAST_ERRNO_VALUE, so a * libc that grows an errno cannot move them. An enum rather than a chain of * #defines so the values stay compile-time integer constants -- HANDLE expands