diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b3dc80..1d8947a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,17 @@ option(AKBASIC_SANITIZE "Build with ASan + UBSan" OFF # calls. Note libakstdlib carries the same shadow but only arms it when *it* is # top-level, so it does nothing for us -- this one has to wrap all three. # +# set_property(TEST ...) has to be shadowed alongside them, and shadowed *only* +# in its TEST form. libakgl 0.9.0 moved eight of these calls off +# set_tests_properties because that command parses its arguments as name/value +# pairs and so splits a semicolon-separated list; set_property does not, and is +# the correct fix. But with add_test() suppressed the tests it names do not +# exist, and set_property errors out on an unknown test name where +# set_tests_properties was silent -- eight hard configure failures. Every other +# form (GLOBAL, DIRECTORY, TARGET, SOURCE, INSTALL, CACHE) has to pass straight +# through: the dependencies set target and directory properties that their own +# builds depend on. +# # libakerror additionally namespaces its `mutation` target when embedded but not # its `coverage` target (deps/libakerror/CMakeLists.txt:194 vs :172), so a # coverage build collides on the `coverage` target and fails to configure at all. @@ -69,6 +80,12 @@ function(set_tests_properties) endif() endfunction() +function(set_property _scope) + if(NOT AKBASIC_SUPPRESS_ADD_TEST OR NOT _scope STREQUAL "TEST") + _set_property(${ARGV}) + endif() +endfunction() + function(add_custom_target _name) if(AKBASIC_SUPPRESS_ADD_TEST AND _name STREQUAL "coverage") _add_custom_target(akerror_coverage ${ARGN}) diff --git a/MAINTENANCE.md b/MAINTENANCE.md index c1769a7..ab1d195 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.8.0 | `libakgl.so.0.8` | **`MAJOR.MINOR` while major is 0** | `AKGL_VERSION*`, `akgl_version()`, `AKGL_VERSION_AT_LEAST()` | +| `deps/libakgl` | 0.9.0 | `libakgl.so.0.9` | **`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 @@ -217,6 +217,17 @@ scopes. We shadow `add_test()` and `set_tests_properties()` for the duration of `add_subdirectory()` calls. `libakstdlib` carries the same shadow but only arms it when *it* is top-level, so it does nothing for us — ours has to wrap all three. +`set_property(TEST ...)` has to be shadowed alongside them, and **only in its `TEST` form**. +`libakgl` 0.9.0 moved eight of these calls off `set_tests_properties`, correctly: that command +parses its arguments as name/value pairs, so a semicolon-separated value is split and every +element after the first is consumed as a bogus property name — which silently reduced its +`LD_LIBRARY_PATH` prepend list to one directory. `set_property` does not split. But with +`add_test()` suppressed the tests those calls name do not exist, and `set_property` **errors** +on an unknown test name where `set_tests_properties` was silent, so pulling 0.9.0 in turned +eight quiet no-ops into eight hard configure failures. Every other form — `GLOBAL`, +`DIRECTORY`, `TARGET`, `SOURCE`, `INSTALL`, `CACHE` — must pass straight through; the +dependencies set target and directory properties their own builds depend on. + **Only one project in a tree may shadow `add_test()`, and this is that project.** CMake exposes an overridden command as `_name` and chains exactly one level: a second override rebinds `_add_test` to the first override and the builtin becomes unreachable to everyone, so @@ -503,8 +514,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 – 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 | +| `"libakgl"` | 256 – 262 | reserved by `akgl_error_init()`; `AKGL_ERR_BASE` … `AKGL_ERR_LIMIT - 1`, seven codes. Was five until 0.8.0 added `AKGL_ERR_COLLISION` and 0.9.0 added `AKGL_ERR_UI` | +| *(free)* | 263 – 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 da495df..6dce36a 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.8.0 — **optional**, only for +* [libakgl](https://source.starfort.tech/andrew/libakgl) 0.9.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/TODO.md b/TODO.md index b43062b..544101c 100644 --- a/TODO.md +++ b/TODO.md @@ -3292,7 +3292,8 @@ reduced against `build/basic`, the stdio build, unless it says otherwise. design decision about what a frame owns rather than a patch -- which is why this is a filed item and not a fix. - Nothing in libakgl 0.8.0 supplies it. There is no render-to-texture layer and no persistent + Nothing in libakgl 0.9.0 supplies it either -- 0.9.0 is the UI subsystem, and its arena draws + inside the frame like everything else. There is no render-to-texture layer and no persistent surface in `include/akgl/renderer.h`; `frame_start` clears the target, which is the opposite. If the answer turns out to want one, it is a §7 filing against `libakgl` rather than something to build here. diff --git a/deps/libakgl b/deps/libakgl index 149bee0..bbb7b8f 160000 --- a/deps/libakgl +++ b/deps/libakgl @@ -1 +1 @@ -Subproject commit 149bee0c993496f931c9d2cb06a27b1a0dcf209a +Subproject commit bbb7b8f494d7784f88e33280f2ea740e3608204f diff --git a/docs/15-error-codes.md b/docs/15-error-codes.md index 85b261e..990c96a 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 261 and an +the code comes back up with it. In the SDL build, `libakgl` owns 256 to 262 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 af1cb1d..dbfd930 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-261 + * Each initializer calls akgl_error_init() first. It reserves libakgl's 256-262 * 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 @@ -70,9 +70,27 @@ * `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. + * from five codes to six with `AKGL_ERR_COLLISION`, taking it to 256 to 261 -- + * 0.9.0 moved it again, below. `MAINTENANCE.md`'s coordinated range map and + * `docs/15-error-codes.md` both carry the current band. + * + * **0.9.0 is the first one that is additive on its face**, and the floor moves + * anyway. It is the `akgl_ui` subsystem -- a vendored clay, an arena, menus, + * HUDs and dialogs -- reached entirely through a new `akgl/ui.h` this target + * does not include, plus three new entry points in `akgl/draw.h` + * (`akgl_draw_filled_rounded_rect`, `akgl_draw_arc`, `akgl_draw_set_clip`). + * Every header this target actually compiles against -- `actor.h`, `sprite.h`, + * `renderer.h`, `text.h`, `registry.h`, `heap.h` -- is byte-identical to 0.8.0, + * so unlike 0.8.0 there is no `sizeof` to get wrong. The status band grew again + * regardless: `AKGL_ERR_UI` makes seven codes and libakgl now owns 256 to 262. + * + * It also collided with the build rather than the code. 0.9.0 moved eight test + * property calls from `set_tests_properties` to `set_property(TEST ...)`, which + * errors on a test name that does not exist where the old command was silent -- + * and this repository suppresses `add_test()` while it pulls its dependencies + * in, so those names do not exist. Eight configure failures, fixed by shadowing + * `set_property` in its `TEST` form too; `MAINTENANCE.md`'s embedding section + * carries the detail. * * 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 @@ -86,8 +104,8 @@ * at link time, because a missing symbol names a function and this names the * release. */ -#if !AKGL_VERSION_AT_LEAST(0, 8, 0) -#error "akbasic's libakgl adaptors require libakgl 0.8.0 or later" +#if !AKGL_VERSION_AT_LEAST(0, 9, 0) +#error "akbasic's libakgl adaptors require libakgl 0.9.0 or later" #endif #include diff --git a/include/akbasic/error.h b/include/akbasic/error.h index eb3ec2d..2dc42d0 100644 --- a/include/akbasic/error.h +++ b/include/akbasic/error.h @@ -51,8 +51,9 @@ /* * libakerror reserves 0-255 for the host's errno values and its own AKERR_* - * 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 + * codes. libakgl claims 256-262 -- five codes until 0.8.0 added + * AKGL_ERR_COLLISION and 0.9.0 added AKGL_ERR_UI, seven since. akbasic claims + * 512-767, leaving 263-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.