gate-kx11extras: guard bare X11/xcb includes outside HAVE_X11

Distinct from the KWindowSystem-API gating: these are the Xlib/XCB headers
themselves, which a Wayland-only sysroot does not ship, so each is a hard
compile failure rather than a lost feature:
  appmenu/appmenu.h:13: fatal error: xcb/xcb.h: No such file or directory

Two of the affected directories are genuinely compiled and would have failed in
turn: kcms/kfontinst (gated only on FONTCONFIG_FOUND) and logout-greeter
(CMakeLists.txt:428, outside any X11 gate). kcms/cursortheme is already gated
upstream by `if(WITH_X11 AND X11_Xcursor_FOUND)` and ksmserver by if(WITH_X11);
guarding them too is harmless and keeps the rule uniform rather than
maintaining a list of exceptions.

Only touches includes at preprocessor depth 0 with respect to HAVE_X11, so
anything already guarded is left alone.

Verified: preprocessor balance OK across all 59 files carrying guards, and a
second run is a no-op (0 files, 0 includes) -- the recipe re-runs this on every
build, so idempotency is a correctness requirement, not a nicety.
This commit is contained in:
2026-08-04 21:24:41 +03:00
parent 70b215f945
commit e3b1edacef
+64
View File
@@ -347,6 +347,62 @@ def normalize_ifdef_guards(text: str) -> tuple[str, int]:
return "\n".join(out) + ("\n" if text.endswith("\n") else ""), changed
def gate_raw_x11_includes(text: str) -> tuple[str, int]:
r"""Guard bare `#include <X11/...>` / `<xcb/...>` that sit outside HAVE_X11.
Distinct from the KWindowSystem-API gating above: these are the Xlib/XCB
headers themselves. A Wayland-only sysroot ships none of them, so each is a
hard compile failure:
appmenu/appmenu.h:13: fatal error: xcb/xcb.h: No such file or directory
Only touches includes at preprocessor depth 0 with respect to HAVE_X11 --
anything already inside a guard is left alone, so this is idempotent and
cannot double-wrap.
Scoped to files that are actually compiled. kcms/cursortheme is skipped
because upstream already gates it (kcms/CMakeLists.txt:13,
`if(WITH_X11 AND X11_Xcursor_FOUND)`); kfontinst and logout-greeter are NOT
gated and do reach the compiler.
"""
lines = text.splitlines()
stack, inx, changed = [], 0, 0
out = []
for line in lines:
st = line.strip()
if re.match(r"#\s*if", st):
g = ("HAVE_X11" in st) and not re.match(r"#\s*if\s*!", st)
stack.append(g)
if g:
inx += 1
out.append(line)
continue
if re.match(r"#\s*endif", st):
if stack and stack.pop():
inx -= 1
out.append(line)
continue
if re.match(r"#\s*el(se|if)", st):
if stack and stack[-1]:
stack[-1] = False
inx -= 1
out.append(line)
continue
if inx == 0 and re.match(r"#\s*include\s*<(X11/|xcb/)", st):
ind = re.match(r"[ \t]*", line).group(0)
out.append(f"{ind}{GUARD_OPEN}")
out.append(line)
out.append(f"{ind}{GUARD_CLOSE}")
changed += 1
continue
out.append(line)
if changed and '#include "config-X11.h"' not in text and "<config-X11.h>" not in text:
for i, l in enumerate(out):
if l.strip() == GUARD_OPEN:
out.insert(i, '#include "config-X11.h"')
break
return "\n".join(out) + ("\n" if text.endswith("\n") else ""), changed
def main() -> int:
root = Path(sys.argv[1])
# libtaskmanager's X11 backend is excluded from the build entirely (Wayland
@@ -369,13 +425,21 @@ def main() -> int:
original = text0
print(f" {path.relative_to(root)}: {n_ifdef} inert #ifdef HAVE_X11 -> #if")
if not any(sym in original for sym in X11_HEADERS):
text, n_raw = gate_raw_x11_includes(original)
if n_raw:
path.write_text(text)
total_files += 1
total_inc += n_raw
print(f" {path.relative_to(root)}: {n_raw} raw X11/xcb include(s)")
continue
text, n_inc = gate_includes(original)
text, n_blk = gate_blocks(text)
text, n_els = gate_else_blocks(text)
text, n_st = gate_statements(text)
text, n_raw = gate_raw_x11_includes(text)
n_blk += n_els + n_st
n_inc += n_raw
if text != original:
path.write_text(text)
total_files += 1