Avoids Clang module conflicts when a NEON/SIMD-gated system header (e.g. Graphene's graphene_simd4f_t backend) is reachable from two different .systemLibrary modules on aarch64 Linux: one pulls in the real _Builtin_intrinsics.arm.acle module, the other re-parses the same header textually, and Clang rejects the resulting conflicting uint32_t/__fsid_t redeclarations. __GI_SCANNER__ is the escape hatch these libraries already ship for exactly this class of consumer (a declaration-only binding generator, same as gobject-introspection's own scanner).
E6: remove build-tool plugin (architecturally incompatible with the
monorepo-only CLI); rewrite the command plugin as a thin pass-through to
swift-gtk-gen.
E7: add swift-format as a dependency, format generated output in-process
before writeIfChanged, re-enable swift format lint --strict in
compile-gate.sh. CamelCase renderer identifiers (enum/bitfield cases,
signal trampoline names, _sgtk_* helpers, __result/__ptr temporaries,
hardcoded G_TYPE_* GValue constants) and drop generated block comments to
reach zero lint findings across all 6 tiers.
Relaxes the generated-filename PascalCase validator's uppercase-run cap
(>3 -> >4) so legitimate acronym type names (PluginAPIFlags, AuthNTLM)
stop crashing generation.
Fixes four compounding cross-module correctness bugs the larger tier-6
GIR set exposed at scale:
- The duplicate-of-dependency drop only checked simple-name collision,
wrongly dropping genuinely distinct C types that merely share a
post-namespace-stripping Swift name (Gst.Object/GstObject vs
GObject.Object/GObject, plus three tier-4/5 cases: Gdk.AppLaunchContext,
Gdk.Gravity, Gdk.Rectangle). Now also requires matching cType.
- Qualifying a cross-module reference as "GObject.X" broke wherever a
raw C struct also named GObject was in scope (every C target's import),
since Swift resolved the module name to the shadowing struct. GObject's
Support.swift now exports collision-free GLibObject/GLibValueArray
aliases used instead.
- Missing `override` keyword: added ancestor-method-selector detection
(name + parameter labels, same-module only, since none of these members
are open) so a subclass narrowing an ancestor's return type compiles.
- The pre-existing cross-module inherited-member dedup pass keyed
ancestors by bare Swift name; its cycle guard falsely self-terminated
once two classes shared a name, missing real inherited members (e.g.
GstObject's own ref()/unref() were never recognized as duplicating
GObject.Object's, producing an illegal redeclaration). Rewired to walk
by unambiguous GIR name via new ClassPlan.girName/parentGIRName fields.
Also fixes bitfield/enum-typed global constants (wraps the raw literal
in Type(rawValue:)) and a void-returning ref function
(gst_atomic_queue_ref, unlike GstBuffer/GObject's T*-returning
convention) via new RecordPlan.copyReturnsVoid.
Adds tier-6 smoke tests (Gst/Soup/Adw version calls against the real
linked libraries) and refreshes the tier-4/5 skip baselines for the
duplicate-detection fix's legitimate coverage growth. Zero skip-baseline
drift on tiers 1-6; 220/220 unit tests and all tier smoke suites pass.
Generates Gdk and Gsk wrappers (330/417 and 140/183 callables), with runtime smoke tests linked against real libgtk-4. Also fixes a latent cross-module dropped-type reference bug, corrects the init(takingOwnership:) doc for no-free records, restores a precise filename safety check, and adds unit test coverage for four previously compile-gate-only branches.
Root causes fixed, all in TypeMapper.swift / TypeRegistry.swift /
Planner.swift / PlanRenderer.swift / BindingPlan.swift / IRModel.swift /
XMLParser.swift:
- Global (cross-module) inherited-member post-pass in planModules
replaces the old in-module-only version, dropping properties/methods
redeclared by an ancestor in a DIFFERENT module (e.g.
Pango.Coverage.ref()/unref() vs. GObject.Object)
- transfer-ownership="none" GObject-class returns now route through
init(retaining:) instead of adopting a borrowed pointer as owned
- Non-GObject fundamental root classes (GParamSpec) capture their GIR
glib:ref-func/glib:unref-func instead of hardcoding g_object_ref
- Interface conformance clauses annotate each interface with @MainActor
to satisfy isolated-conformance checking across module boundaries
- Scalar marshalOut (.direct/.numericCast) returned through a pointer
C type with no <array> length now skips instead of misreading a raw
buffer pointer as its pointee value
- Property/method Swift-name collisions on the same class are resolved
by dropping the property (e.g. Pango.FontFamily.isVariable)
- MultiPackageAnalyzer only walks includes for configured packages
- No unconditional Foundation import (collided with Gio.InputStream)
- gdk_pixbuf_non_anim_new added to knownMissingCFunctions (GIR-declared,
not exported through the public umbrella header)
Smoke tests: smoke/tier3/PixbufSmoke.swift (Pixbuf construction +
dimension round-trip against real libgdk_pixbuf) and
smoke/tier3/PangoSmoke.swift (findBaseDir against real libpango,
Latin vs. Hebrew script direction).
208 unit tests pass (+14: InheritedMemberTests + E2 sections in
PropertyGenerationTests/RendererCallableTests/others). compile-gate.sh
1, 2, and 3 all PASS. smoke-test.sh 3 passes 21/21 (18 tier-1 base +
1 GdkPixbuf + 2 Pango).
Destroy-notify ABI fixed to GClosureNotify's real 2-arg signature and
wired into every connect method (was leaking every _ClosureBox, and
UB on non-x86_64 with the wrong arg count). Trampolines restore
MainActor isolation via assumeIsolated, with narrowly-scoped
nonisolated(unsafe) shadow copies to satisfy Swift 6's sending
checker. Interface-signal rendering implemented and unit-tested.
Dead code removed (SignalHandlePlan), destroyTrampoline made
non-optional, D7 deferral documented in-code. CoverageStats gained
boundCallbacks/boundSignals counters. Added SignalGenerationTests,
InterfaceSignalGenerationTests, and CallbackGenerationTests (12 new
tests, 187/187 total). Fixed the dead nonDetailedSignal smoke test to
actually mutate a property and assert the closure fired.
Callback-param planner-side binding (D4.3) stays disabled: enabling
it trips a genuine Swift compiler crash on g_qsort_with_data's
GCompareDataFunc parameter. The renderer-side box setup/release logic
is implemented and unit-tested by constructing plans directly,
bypassing the blocked planner path.
Verified: swift test (187/187), compile-gate.sh 1 --fresh (PASS),
smoke-test.sh --fresh (18/18).
Properties render as Swift computed `var`s. Each accessor is planned
independently as either a delegation to the GIR getter=/setter= method
or the uniform GValue machinery (g_object_get_property/_set_property).
Delegation is preferred and inherits the method's nullability and
ownership (e.g. Binding.source becomes Object? because get_source is
nullable, where the GValue path produced a trap-prone non-optional
Object). It is chosen only when it yields one consistent Swift type;
otherwise both accessors fall back to GValue. GValue is also the
fallback for pure-GObject properties with no dedicated C accessor.
Enum/flags GValue getters bridge gint/guint to the Swift raw value via
numericCast; a bare cast would fail to compile on any enum-bearing tier.
Construct-only properties render read-only. Interface properties become
{ get } / { get set } requirements. GObject's fundamental G_TYPE_*
constants are emitted into its support file.
Adds 17 PropertyGenerationTests (incl. 5 delegation cases) and 2 runtime
smoke tests exercising a GValue round-trip and delegated getFlags() /
nullable getSource() off a real GBinding.
GIR caller-allocates out-params (char *outbuf, gunichar *result) require
the caller to allocate and size the buffer, unlike callee-allocates T**
out-params where the callee fills in the pointee. The out-param
marshalling declared a single Swift scalar and passed its address, which
is correct only for the callee-allocates shape; for caller-allocates, C
wrote buffer payload past the one-element slot (g_unichar_fully_decompose)
or the payload was reinterpreted as a pointer and dereferenced
(g_unichar_to_utf8, segfault). GIR carries no buffer-size field, so these
are now skipped rather than generated. The guard also reclassifies
time_val_from_iso8601/signal_query/type_query from plainRecord to the
accurate caller-allocates reason.
Boxed records (C4): resolve each record's copy/free function from the GIR
copy-function/free-function attribute, else its own ref/copy and unref/free
method, and render init(retaining:) plus an isolated deinit. The deinit is
isolated because the package's default MainActor isolation makes accessing the
non-Sendable pointer from a nonisolated deinit a hard error. The registry uses
the same resolution so transfer=none returns copy instead of adopting a
borrowed pointer. This supersedes the earlier deferral: the hypothesised
OpaquePointer/Sendable barriers either did not hold or were solvable.
Interfaces (C5): plan each interface method through planMethod and render it as
a protocol requirement (no body); the conforming class supplies the C call.