Skip to content

Commit 4f22071

Browse files
ctatenextpointer
andauthored
Keep the WebView stub compile silent and support GLib 2.72 (#152)
* Remove the informational pragma from both WebView stub paths - zig renders every clang diagnostic of a failing C compile as error:, so the note masqueraded as the build-killer whenever a real error joined it - the stub branches keep their explanatory comments; the misconfigured web-build #error stays - build graphs (build/app.zig and the ejected template) document why the expected state is silent: runtime WebViewNotFound is the teaching channel Co-authored-by: nextpointer <110530249+nextpointer@users.noreply.github.com> * Compile the GTK host against GLib 2.72 - G_APPLICATION_DEFAULT_FLAGS is GLib 2.74+; the host's GTK floor is 4.10, whose own GLib floor is 2.72 - distros backporting GTK 4.10 onto a 2.72 base (Ubuntu 22.04 derivatives) now compile canvas apps out of the box Co-authored-by: nextpointer <110530249+nextpointer@users.noreply.github.com> * Pin diagnostic-free stub compiles in both canvas-smoke CI lanes - zig cc passthrough is the one channel where C warnings reach stderr, so each lane compiles its stub host and asserts zero diagnostics - fails on the old pragma, passes after its removal; the webkit-less build + ELF audit receipts already live in these lanes - changelog fragment for the user-visible fix Co-authored-by: nextpointer <110530249+nextpointer@users.noreply.github.com> * Run the stub diagnostic receipts against a cold zig cache - on a cache hit zig cc replays nothing, stderr included, so a restored cache would hide the exact diagnostics the steps pin against - throwaway ZIG_GLOBAL/LOCAL_CACHE_DIR per step keeps every run cold Co-authored-by: nextpointer <110530249+nextpointer@users.noreply.github.com> * Print the captured compiler output when a stub receipt compile fails - Actions runs steps under bash -e, so a nonzero command substitution killed the step at the assignment and swallowed the forensics the step captured; the || arm keeps errexit out of the capture. Co-authored-by: nextpointer <110530249+nextpointer@users.noreply.github.com> * Pin the GLib 2.72 fallback with an error-set receipt on stock 22.04 - No stock image pairs old glib with GTK 4.10, so the receipt asserts the error set: GTK-age failures only, never a glib symbol - a future 2.74+ symbol without a fallback trips it. Co-authored-by: nextpointer <110530249+nextpointer@users.noreply.github.com> * Whitelist GTK-age diagnostic shapes in the GLib 2.72 receipt - The prefix blacklist missed non-undeclared shapes (unknown glib type names); the whitelist rejects everything that is not a GTK-age root or its cascades, with the cascade rationale in the script. Co-authored-by: nextpointer <110530249+nextpointer@users.noreply.github.com> * Demand positive evidence from the GLib 2.72 receipt - Unlocated error shapes (driver/invocation failures) reject instead of sailing past the located-diagnostic parser, and fewer than five GTK-age roots means the compile proved nothing. - Renamed to the allowlist vocabulary. Co-authored-by: nextpointer <110530249+nextpointer@users.noreply.github.com> * Narrow the conversion cascade to its signature and document the lattice - Int-to-pointer lines only pass when converting from 'int' (the undeclared-function-returns-int shape); the docstring now records why cascade allowances are sound: full-GTK lanes compile the same file, so only the old-glib delta reaches this filter, and glib regressions always reject at their root. Co-authored-by: nextpointer <110530249+nextpointer@users.noreply.github.com> --------- Co-authored-by: nextpointer <110530249+nextpointer@users.noreply.github.com>
1 parent e590910 commit 4f22071

7 files changed

Lines changed: 216 additions & 5 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/usr/bin/env python3
2+
"""The GLib 2.72 receipt's error-set allowlist.
3+
4+
Compiling gtk_host.c on stock ubuntu 22.04 (GLib 2.72, GTK 4.6) cannot
5+
succeed: the toolkit's GTK floor is 4.10, so GTK-age failures are the
6+
expected steady state. What this receipt pins is that NOTHING ELSE
7+
fails - a glib/gio symbol needing 2.74+ without a version-checked
8+
fallback shows up here as a diagnostic outside the allowlist below.
9+
10+
The allowlist is by diagnostic SHAPE, not symbol prefix:
11+
- undeclared gtk_/GTK_ functions are the GTK-age roots;
12+
- undeclared plain (non-glib-namespaced) identifiers are their
13+
cascades (locals whose declaring line failed);
14+
- int-conversion lines are cascades of undeclared functions returning
15+
int, and incidentally name glib types (GListModel), so a prefix
16+
denylist would false-positive on them.
17+
Everything else fails the step: unknown type name 'G...', undeclared
18+
g_/G_ symbols, missing members, any located shape not seen before,
19+
and any error line WITHOUT a file:line:col location (driver failures
20+
like "error: Unknown Clang option" never classify as diagnostics, so
21+
they must reject rather than sail through an empty error set).
22+
23+
The receipt also demands positive evidence it ran: at least
24+
MIN_GTK_ROOTS allowlisted GTK-age root diagnostics. A compile that
25+
produced no classifiable error set (wrong file, broken include path,
26+
invocation failure) proves nothing and must fail loudly - the clean
27+
run produces ~21 roots, so the floor sits far below real variance
28+
while catching "nothing actually compiled".
29+
30+
Why the cascade allowances are sound despite looking broad: this
31+
receipt is one lane in a lattice, not the sole guard on gtk_host.c.
32+
Every full-GTK lane (linux-webkitgtk, the canvas smokes, macOS)
33+
compiles the same file cleanly, so a typo'd local or an independent
34+
conversion bug is a red build elsewhere before it ever reaches this
35+
filter - the only errors unique to this lane are the old-glib delta.
36+
And within that delta, regressions always announce themselves through
37+
a REJECTED root before their cascades matter: a missing glib function
38+
is "call to undeclared function 'g_...'" (only gtk_/GTK_ roots are
39+
allowed), a missing glib type/macro is an unknown-type-name or
40+
undeclared-G_-identifier line - all rejected. The cascades allowed
41+
below can only follow roots this filter already failed the step for,
42+
or GTK-age roots it exists to permit.
43+
"""
44+
import re
45+
import sys
46+
47+
MIN_GTK_ROOTS = 5
48+
49+
located = re.compile(r"^[^:\n]+:\d+:\d+: error: (.*)")
50+
rejected = []
51+
gtk_roots = 0
52+
for line in sys.stdin:
53+
if "error:" not in line:
54+
continue
55+
m = located.match(line)
56+
if not m:
57+
rejected.append(line.rstrip() + " [unlocated error shape - driver or invocation failure]")
58+
continue
59+
msg = m.group(1)
60+
if re.match(r"call to undeclared function '(gtk_|GTK_)", msg):
61+
gtk_roots += 1
62+
continue
63+
if re.match(r"use of undeclared identifier '(?!g_|G_|G[A-Z])", msg):
64+
continue
65+
if "incompatible integer to pointer conversion" in msg and "from 'int'" in msg:
66+
# Only the cascade signature: an undeclared function defaults to
67+
# returning int, so its assignment lines convert FROM 'int'.
68+
# Conversions from any other type are not that cascade - reject.
69+
continue
70+
rejected.append(line.rstrip())
71+
72+
if rejected:
73+
print("non-GTK-age diagnostics against GLib 2.72 - the pre-2.74 fallback story regressed:")
74+
print("\n".join(rejected))
75+
sys.exit(1)
76+
if gtk_roots < MIN_GTK_ROOTS:
77+
print(
78+
f"only {gtk_roots} GTK-age root diagnostics (need >= {MIN_GTK_ROOTS}) - "
79+
"the compile did not exercise the old-GTK error set, so this receipt proved nothing"
80+
)
81+
sys.exit(1)
82+
print(f"fallback receipt ok: every error is GTK-age by shape ({gtk_roots} roots)")

.github/workflows/ci.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,30 @@ jobs:
179179
# conditions is the linux-webkitgtk job's ELF cross-audit.)
180180
- name: Install GTK and Xvfb
181181
run: sudo apt-get update && sudo apt-get install -y libgtk-4-dev xvfb
182+
# The stub is the expected, configured state of every native-only
183+
# Linux app, so compiling the GTK host with the stub define must be
184+
# diagnostic-FREE, not merely successful: zig renders every clang
185+
# diagnostic of a failing translation unit as `error:` (serialized
186+
# clang diagnostics carry no severity into its error bundle), so
187+
# even an informational #pragma message in this path masquerades as
188+
# the build-killing error the moment any unrelated real error
189+
# appears in the file. `zig cc` runs clang in passthrough mode,
190+
# where warnings actually reach stderr — `zig build` only surfaces
191+
# C diagnostics on failure, which is exactly the escalation this
192+
# step pins against. The throwaway cache dir keeps the compile
193+
# cold: on a cache hit zig replays nothing, stderr included, so a
194+
# warm cache (setup-zig restores one) would hide the diagnostics
195+
# this step exists to catch.
196+
- name: WebKitGTK stub compile is diagnostic-free
197+
run: |
198+
export ZIG_GLOBAL_CACHE_DIR=$(mktemp -d) ZIG_LOCAL_CACHE_DIR=$(mktemp -d)
199+
status=0
200+
out=$(zig cc -c src/platform/linux/gtk_host.c -DNATIVE_SDK_ALLOW_WEBKITGTK_STUB $(pkg-config --cflags gtk4) -o /tmp/gtk_host_stub.o 2>&1) || status=$?
201+
if [ "$status" -ne 0 ] || [ -n "$out" ]; then
202+
echo "the WebKitGTK stub compile must succeed with zero diagnostics (exit $status):"
203+
echo "$out"
204+
exit 1
205+
fi
182206
# Drives the gpu_surface software path under Xvfb: snapshot ready,
183207
# gpu_backend=software, gpu_nonblank=true, automation widget-click,
184208
# a rendered screenshot, an ELF audit that the built binary carries
@@ -189,6 +213,33 @@ jobs:
189213
# all live in the script.
190214
- name: Build and drive ui-inbox headless
191215
run: .github/scripts/linux-canvas-smoke.sh
216+
# Durable receipt for the GLib 2.72 fallback (the pre-2.74
217+
# G_APPLICATION_DEFAULT_FLAGS shim in gtk_host.c): no stock image
218+
# pairs an old glib with GTK >= 4.10 (only backport distros do),
219+
# and ubuntu 22.04 ships GTK 4.6 — so a clean compile is
220+
# impossible here by design. This pins the error SET instead:
221+
# every diagnostic must match a GTK-age shape (the allowlist
222+
# script holds the shapes, why cascades are allowed, and the
223+
# positive-evidence floor) — a 2.74+ glib symbol, type, or
224+
# member used without a version-checked fallback surfaces as a
225+
# rejected diagnostic and fails this step, and so does a compile
226+
# that produced no classifiable error set at all. If this compile ever succeeds outright, the premise
227+
# changed (newer GTK in the image) and the receipt must be
228+
# re-verified rather than trusted.
229+
- name: GTK host GLib 2.72 fallback holds (error-set receipt)
230+
run: |
231+
docker run --rm -v "$PWD:/src" -v "$(dirname "$(which zig)"):/zig" ubuntu:22.04 bash -ec '
232+
export DEBIAN_FRONTEND=noninteractive
233+
apt-get update -q >/dev/null && apt-get install -y -q libgtk-4-dev pkg-config >/dev/null
234+
export ZIG_GLOBAL_CACHE_DIR=$(mktemp -d) ZIG_LOCAL_CACHE_DIR=$(mktemp -d)
235+
status=0
236+
out=$(/zig/zig cc -c /src/src/platform/linux/gtk_host.c -DNATIVE_SDK_ALLOW_WEBKITGTK_STUB $(pkg-config --cflags gtk4) -ferror-limit=0 -o /tmp/gtk_host_2272.o 2>&1) || status=$?
237+
if [ "$status" -eq 0 ]; then
238+
echo "unexpected clean compile on ubuntu 22.04 - this receipt assumes GTK-age errors; re-verify what it proves now"
239+
exit 1
240+
fi
241+
echo "$out" | python3 /src/.github/scripts/glib272_error_allowlist.py
242+
'
192243
193244
linux-dev-smoke:
194245
name: Linux Dev Smoke (Debug scaffold)
@@ -230,6 +281,22 @@ jobs:
230281
version: 0.16.0
231282
- name: Install Wine, Xvfb, and xdotool
232283
run: sudo apt-get update && sudo apt-get install -y wine xvfb xdotool
284+
# The Windows twin of the linux-canvas-smoke stub receipt: the
285+
# WebView2 stub is the expected, configured state of every
286+
# native-only Windows app, so cross-compiling the host with the
287+
# stub define must be diagnostic-free (see that job's step comment
288+
# for why even an informational #pragma message is dangerous, and
289+
# why the compile must run against a cold cache).
290+
- name: WebView2 stub cross-compile is diagnostic-free
291+
run: |
292+
export ZIG_GLOBAL_CACHE_DIR=$(mktemp -d) ZIG_LOCAL_CACHE_DIR=$(mktemp -d)
293+
status=0
294+
out=$(zig c++ -target x86_64-windows-gnu -std=c++17 -DNATIVE_SDK_ALLOW_WEBVIEW2_STUB -c src/platform/windows/webview2_host.cpp -o /tmp/webview2_host_stub.o 2>&1) || status=$?
295+
if [ "$status" -ne 0 ] || [ -n "$out" ]; then
296+
echo "the WebView2 stub cross-compile must succeed with zero diagnostics (exit $status):"
297+
echo "$out"
298+
exit 1
299+
fi
233300
# Cross-compiles ui-inbox for x86_64-windows-gnu and drives the
234301
# gpu_surface software path (child HWND + WM_TIMER + SetDIBitsToDevice)
235302
# under Wine: snapshot ready, gpu_backend=software, gpu_nonblank=true,

build/app.zig

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,14 @@ fn linkPlatform(b: *std.Build, dep: *std.Build.Dependency, target: std.Build.Res
946946
// the layer stays out even on machines where the
947947
// development package is installed — libwebkitgtk is
948948
// neither linked nor required at runtime, and the
949-
// executable carries no WebKit reference at all.
949+
// executable carries no WebKit reference at all. This
950+
// is the expected, configured state of every canvas
951+
// app on Linux, so the stub compile is deliberately
952+
// silent — no build note, no compiler diagnostic (the
953+
// host's seam comment explains why even an
954+
// informational pragma is dangerous); a stubbed host
955+
// teaches at runtime by reporting WebViewNotFound the
956+
// moment an app actually uses a WebView.
950957
app_mod.addCSourceFile(.{ .file = dep.path("src/platform/linux/gtk_host.c"), .flags = &.{"-DNATIVE_SDK_ALLOW_WEBKITGTK_STUB"} });
951958
app_mod.linkSystemLibrary("gtk4", .{});
952959
app_mod.linkSystemLibrary("dl", .{});
@@ -999,6 +1006,14 @@ fn linkPlatform(b: *std.Build, dep: *std.Build.Dependency, target: std.Build.Res
9991006
// headers are reachable through the system include paths
10001007
// — no WebView2Loader.dll is installed or path-wired,
10011008
// and the executable carries no reference to it at all.
1009+
// This is the expected, configured state of every
1010+
// canvas app on Windows, so the stub compile is
1011+
// deliberately silent — no build note, no compiler
1012+
// diagnostic (the host's seam comment explains why
1013+
// even an informational pragma is dangerous); a
1014+
// stubbed host teaches at runtime by reporting
1015+
// WebViewNotFound the moment an app actually uses a
1016+
// WebView.
10021017
app_mod.addCSourceFile(.{ .file = dep.path("src/platform/windows/webview2_host.cpp"), .flags = &.{ "-std=c++17", "-DNATIVE_SDK_ALLOW_WEBVIEW2_STUB" } });
10031018
},
10041019
.chromium => {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fix: **Canvas-app hosts compile silently without a WebView SDK**: the informational `#pragma message` in the GTK host's WebKitGTK stub path (and its Windows WebView2 twin) is gone — zig renders every clang diagnostic of a failing C compile as `error:`, so on machines where a real, unrelated compile error occurred (for example a too-old GTK), the note itself surfaced as the first build-killing error and masked the actual cause; the stub is the expected state of every canvas app and now compiles with zero diagnostics, while a genuinely misconfigured web build still fails loudly via `#error`.
2+
- **GTK host compiles against GLib 2.72**: the host now spells "no application flags" in a way that compiles on GLib older than 2.74, so distros that backport GTK 4.10 onto a GLib 2.72 base (Ubuntu 22.04-derived) build canvas apps out of the box.

src/platform/linux/gtk_host.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,17 @@
2424
* NATIVE_SDK_ALLOW_WEBVIEW2_STUB. */
2525
#if defined(NATIVE_SDK_ALLOW_WEBKITGTK_STUB)
2626
#define NATIVE_SDK_HAS_WEBKITGTK 0
27-
#pragma message("Embedded web layer excluded by the build configuration: building the GTK host without WebKitGTK (canvas apps unaffected; WebView loads will report WebViewNotFound)")
28-
/* The stubbed web layer keeps the window/webview bookkeeping SHAPE so
27+
/* Deliberately NO compiler diagnostic in this branch — not even an
28+
* informational #pragma message. The stub is the expected, configured
29+
* state of every native-only Linux build, and zig renders every clang
30+
* diagnostic of a failing translation unit as `error:` (its serialized
31+
* clang diagnostics carry no severity into the error bundle), so an
32+
* informational note here masquerades as the build-killing error the
33+
* moment any unrelated real error appears anywhere in this file. The
34+
* teaching lives where it is actionable instead: a stubbed host
35+
* reports WebViewNotFound the moment an app actually uses a WebView.
36+
*
37+
* The stubbed web layer keeps the window/webview bookkeeping SHAPE so
2938
* every GTK-only path (overlay reordering, focus lookups, window
3039
* teardown) compiles unchanged: the web-view pointers below are opaque
3140
* and permanently NULL — every path that could create one is compiled
@@ -43,6 +52,18 @@ typedef struct native_sdk_absent_content_manager WebKitUserContentManager;
4352
#error "webkit/webkit.h not found: install the WebKitGTK 6.0 development package (libwebkitgtk-6.0-dev on Debian/Ubuntu), or define NATIVE_SDK_ALLOW_WEBKITGTK_STUB to build without the embedded web layer"
4453
#endif
4554

55+
/* G_APPLICATION_DEFAULT_FLAGS arrived in GLib 2.74 as the
56+
* non-deprecated spelling of "no flags". This host's GTK floor is 4.10
57+
* (the GtkFileDialog family below), and GTK 4.10's own GLib floor is
58+
* 2.72 — distros that backport GTK 4.10 onto a GLib 2.72 base (Ubuntu
59+
* 22.04 derivatives) must still compile this file. Same value, gated to
60+
* older GLib only; the pre-2.74 name G_APPLICATION_FLAGS_NONE is not
61+
* used because it is deprecated from 2.74 on and would emit a warning
62+
* exactly where the newer name exists. */
63+
#if !GLIB_CHECK_VERSION(2, 74, 0)
64+
#define G_APPLICATION_DEFAULT_FLAGS ((GApplicationFlags) 0)
65+
#endif
66+
4667
#define NATIVE_SDK_MAX_WINDOWS 16
4768
#define NATIVE_SDK_MAX_WEBVIEWS 16
4869
#define NATIVE_SDK_MAX_TIMERS 64

src/platform/windows/webview2_host.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,16 @@
4141
* WebView loads report WebViewNotFound at runtime. */
4242
#if defined(NATIVE_SDK_ALLOW_WEBVIEW2_STUB)
4343
#define NATIVE_SDK_HAS_WEBVIEW2 0
44-
#pragma message("Embedded WebView layer excluded by the build configuration: building the Windows host without it (canvas apps unaffected; WebView loads will report WebViewNotFound)")
44+
/* Deliberately NO compiler diagnostic in this branch — not even an
45+
* informational #pragma message. The stub is the expected, configured
46+
* state of every native-only Windows build, and zig renders every
47+
* clang diagnostic of a failing translation unit as `error:` (its
48+
* serialized clang diagnostics carry no severity into the error
49+
* bundle), so an informational note here masquerades as the
50+
* build-killing error the moment any unrelated real error appears
51+
* anywhere in this file. The teaching lives where it is actionable
52+
* instead: a stubbed host reports WebViewNotFound the moment an app
53+
* actually uses a WebView. */
4554
#elif __has_include(<WebView2.h>) && __has_include(<wrl.h>)
4655
#include <WebView2.h>
4756
#include <wrl.h>

src/tooling/templates.zig

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1751,7 +1751,14 @@ fn buildZig(allocator: std.mem.Allocator, names: TemplateNames, framework_path:
17511751
\\ // the layer stays out even on machines where the
17521752
\\ // development package is installed — libwebkitgtk is
17531753
\\ // neither linked nor required at runtime, and the
1754-
\\ // executable carries no WebKit reference at all.
1754+
\\ // executable carries no WebKit reference at all. This
1755+
\\ // is the expected, configured state of every canvas
1756+
\\ // app on Linux, so the stub compile is deliberately
1757+
\\ // silent — no build note, no compiler diagnostic (the
1758+
\\ // host's seam comment explains why even an
1759+
\\ // informational pragma is dangerous); a stubbed host
1760+
\\ // teaches at runtime by reporting WebViewNotFound the
1761+
\\ // moment an app actually uses a WebView.
17551762
\\ app_mod.addCSourceFile(.{ .file = nativeSdkPath(b, native_sdk_path, "src/platform/linux/gtk_host.c"), .flags = &.{"-DNATIVE_SDK_ALLOW_WEBKITGTK_STUB"} });
17561763
\\ app_mod.linkSystemLibrary("gtk4", .{});
17571764
\\ app_mod.linkSystemLibrary("dl", .{});
@@ -1797,6 +1804,14 @@ fn buildZig(allocator: std.mem.Allocator, names: TemplateNames, framework_path:
17971804
\\ // headers are reachable through the system include paths
17981805
\\ // — no WebView2Loader.dll is installed or path-wired,
17991806
\\ // and the executable carries no reference to it at all.
1807+
\\ // This is the expected, configured state of every
1808+
\\ // canvas app on Windows, so the stub compile is
1809+
\\ // deliberately silent — no build note, no compiler
1810+
\\ // diagnostic (the host's seam comment explains why
1811+
\\ // even an informational pragma is dangerous); a
1812+
\\ // stubbed host teaches at runtime by reporting
1813+
\\ // WebViewNotFound the moment an app actually uses a
1814+
\\ // WebView.
18001815
\\ app_mod.addCSourceFile(.{ .file = nativeSdkPath(b, native_sdk_path, "src/platform/windows/webview2_host.cpp"), .flags = &.{ "-std=c++17", "-DNATIVE_SDK_ALLOW_WEBVIEW2_STUB" } });
18011816
\\ },
18021817
\\ .chromium => {

0 commit comments

Comments
 (0)