fix(ios): restore backend ABI parity, and gate it in CI - #108
Merged
Conversation
Seven entry points were implemented on AppKit, GTK4 and Win32 but not on UIKit: app_quit, set_width / set_height, get_width / get_height, the two borrowed-pixel blit variants, and modifiers. An iOS app calling any of them would have failed at link. Nothing caught it, and that is the more important half. The iOS phase compiles the backend and links it against a stub, which proves that what it REFERENCES resolves and says nothing about what it omits; the Win32 lane only cross-compiles. A missing entry point is invisible to every phase because nothing in CI calls it. All seven are implemented. Two are documented no-ops with a stated reason rather than a silent gap: iOS has no programmatic quit, since terminating your own app is grounds for App Store rejection, and modifiers is always 0 because a touch carries none and UIKit has no pollable global modifier state (a hardware keyboard's modifiers arrive attached to the key event, which is a different question from what is held right now). get_width / get_height round the frame's EDGES rather than its size, so iOS carries the same tiling guarantee the other backends got in #101. tests/scripts/check_backend_parity.py holds the line: every function declared in aether_ui_backend.h must be defined in the shared sources or on all four backends. It distinguishes a definition from a declaration by scanning from the name to whichever of `;` or `{` comes first, not by a single regex, because a regex lets one match swallow a later one: the first version of this check reported Win32 as missing notify_impl, which it defines. Verified both ways, by removing the four size functions again and confirming the gate fails. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What I found
While checking whether #22's UIKit backend was actually complete, I compared the
ABI in
aether_ui_backend.hagainst what each backend defines. Seven entrypoints were on AppKit, GTK4 and Win32 but not on UIKit:
An iOS app calling any of them fails at link.
Why nothing caught it
This is the part worth fixing properly. Phase 1e compiles the UIKit backend and
links it against
tests/ios/link_stub.c, which proves that everything itreferences resolves. It says nothing about what it omits. The Win32 lane
only cross-compiles. So a missing entry point is invisible to every phase in
CI, because nothing in CI calls it.
The fix
All seven implemented. Two are documented no-ops with a stated reason, which
is different from a gap:
app_quitdoes nothing on iOS. Terminating your own app is grounds forApp Store rejection; the platform expects the user to leave via the home
gesture. A cross-platform app with a Quit item now links and no-ops rather
than failing to build for iOS.
modifiersreturns 0. A touch carries no modifiers, and UIKit has nopollable global modifier state. A hardware keyboard's modifiers arrive
attached to the key event (
UIKey.modifierFlags), which is a differentquestion from "what is held right now".
get_width/get_heightround the frame's edges rather than its size, soiOS carries the same tiling guarantee the other three backends got in #101.
The gate
tests/scripts/check_backend_parity.py, wired in as phase 1c2: every functiondeclared in
aether_ui_backend.hmust be defined either in the shared sources(
aether_ui_system_extras.cand friends, which every backend links) or on allfour backends.
It distinguishes a definition from a declaration by scanning from the name to
whichever of
;or{comes first, rather than with one regex. That matters:my first attempt used a single pattern and reported Win32 as missing
notify_impl, which Win32 defines at line 9779. A non-greedy match startingearlier had swallowed it. A checker that under-reports is worse than none.
Verification
it report all four and exit 1.
aeb .all.aebuilds clean on AppKit, zero warnings.only CommandLineTools), so phase 1e's
-Wall -Werrorsimulator build is thecompile check. The additions mirror the AppKit implementations and the file's
existing idioms (
static const charassociation keys,objc_setAssociatedObject).On #22
With this merged, every item in #22's work list is implemented and the ABI is
complete on UIKit. Its stated prerequisite, aether-lang-dev/aether#1385 (the
iOS
--emit=libtarget), is still open and is the remaining blocker foractually shipping an app, so I have left #22 open rather than closing it from
here.
🤖 Generated with Claude Code