From aa075024caa87fc38d68e247938a2c04a14ce023 Mon Sep 17 00:00:00 2001 From: vasilito Date: Mon, 3 Aug 2026 09:10:21 +0300 Subject: [PATCH] fix: cross-build host-tool resolution and staging correctness Four distinct ways the cross build reached for the wrong thing: mesa-clc: 'unset LDFLAGS' left only /usr/lib on the link path, so the HOST libLLVM won over llvm-native. Arch-family builds use -DLLVM_LINK_LLVM_DYLIB, so libLLVM re-exports libstdc++ symbols under its own version node; mesa_clc then recorded std::string::reserve@LLVM_21.1, which no llvm-native build provides. When it instead resolved the host libLLVM at runtime, clang derived its resource dir from the HOST install, and with host clang 22 beside an llvm-runtime 21.1 the directory /usr/lib/clang/21 does not exist, so every OpenCL compile died with "'opencl-c-base.h' file not found" -- nowhere near the cause. Put llvm-native back on the link path with a matching -rpath, and pin the staged tools' RUNPATH to this recipe's own sysroot. Also wipe build-clc before meson setup: re-running setup on a configured dir reinterprets -D flags as option CHANGES and aborts on any option the old configuration lacked ("Unknown option: mesa-clc"). breeze: kconfig_compiler_kf6 resolved to the cross-compiled Redox binary, which the host cannot execute ('cannot execute: required file not found' is ENOENT on the ELF interpreter). Point at the host tool. kde-cli-tools: installs to KDE_INSTALL_FULL_BINDIR, an ABSOLUTE /usr/bin. 'cmake --install --prefix' only re-roots relative destinations, so cmake wrote straight into the BUILD HOST's filesystem and only file permissions stopped it. Use DESTDIR, which re-roots absolute paths too. kstart is X11-only (Qt private X11 interop header) and cannot work without an X server, so exclude it as kdesu already is. sddm: QML_INSTALL_DIR fell back to 'qmake -query QT_INSTALL_QML', i.e. the HOST Qt, so SddmComponents installed into the host build tree. Every greeter theme does 'import SddmComponents 2.0', so this broke the login UI at runtime with no build-time error. polkit: dbus-1.pc's system_bus_services_dir comes back sysroot-prefixed under a cross build, dropping a bogus /mnt/... tree into the image. --- local/recipes/dev/mesa-clc/recipe.toml | 64 +++++++++++++++++++++ local/recipes/kde/breeze/recipe.toml | 2 + local/recipes/kde/kde-cli-tools/recipe.toml | 18 +++++- local/recipes/kde/sddm/recipe.toml | 7 +++ local/recipes/libs/polkit/recipe.toml | 10 ++++ 5 files changed, 100 insertions(+), 1 deletion(-) diff --git a/local/recipes/dev/mesa-clc/recipe.toml b/local/recipes/dev/mesa-clc/recipe.toml index a0fa4f4913..e9ccd0f30a 100644 --- a/local/recipes/dev/mesa-clc/recipe.toml +++ b/local/recipes/dev/mesa-clc/recipe.toml @@ -40,6 +40,27 @@ unset LDFLAGS CFLAGS CXXFLAGS CPPFLAGS export CC=/usr/bin/gcc export CXX=/usr/bin/g++ +# ...but put OUR host LLVM back on the link path. Clearing LDFLAGS leaves the +# linker with only the default /usr/lib, so on a host that ships its own +# llvm-runtime the system libLLVM.so wins over llvm-native's. That mislink is +# silent and produces two failures far from the cause: +# +# * Arch/Manjaro build libLLVM with -DLLVM_LINK_LLVM_DYLIB, so it re-exports +# libstdc++ symbols under its own LLVM_ version node. mesa_clc then +# records a versioned reference (e.g. std::string::reserve@LLVM_21.1) that +# NO llvm-native build provides, and dies at runtime with +# "undefined symbol: ..., version LLVM_21.1". +# * If it instead resolves the host libLLVM at runtime too, clang derives its +# resource dir from the HOST install. When the host's clang major differs +# from its llvm-runtime major (clang 22 + libLLVM 21.1 here), that directory +# does not exist and every OpenCL compile fails with +# "'opencl-c-base.h' file not found". +# +# -L puts llvm-native's libs ahead of /usr/lib for the linker; the matching +# -rpath makes the runtime loader agree, so link-time and run-time resolve to +# the same libLLVM. +export LDFLAGS="-L${COOKBOOK_SYSROOT}/usr/lib -Wl,-rpath,${COOKBOOK_SYSROOT}/usr/lib" + # Use llvm-native's CLEAN host LLVM/Clang (staged in the sysroot at usr/bin). # Do NOT use the redoxer toolchain's llvm-config: its includedir # (/include) also holds the Redox *target* libc headers @@ -74,6 +95,19 @@ done # Configure a NATIVE mesa restricted to the shader compilers. No window-system # platforms / GL runtime — we only need the clc/precomp tool executables. +# +# Always configure from scratch. `meson setup` on an ALREADY-configured build +# dir does not re-run configuration: it reinterprets the -D flags as option +# *changes* against the stored configuration and aborts on any option the old +# configuration did not define, e.g. +# Directory already configured. +# ERROR: Unknown option: "mesa-clc". +# That is exactly what happens after a Mesa version bump (the option set moves) +# or when a build dir survives from an earlier run, and the failure message +# points at the option rather than at the stale directory. Wiping is cheap here +# because the cookbook only re-enters this script on a content-hash miss. +rm -rf build-clc + meson setup build-clc "${COOKBOOK_SOURCE}" \ --buildtype=release \ --prefix=/usr \ @@ -119,5 +153,35 @@ for t in $_targets; do echo "mesa-clc: WARN target build-clc/$t not found after build" fi done + +# Pin the RUNPATH to THIS recipe's sysroot (host LLVM/Clang), regenerated on +# every build. +# +# These are NATIVE host tools that the cross Mesa build executes out of *mesa's* +# sysroot. Two wrong answers to guard against: +# +# 1. A stale absolute path (e.g. left over from a moved checkout). The loader +# then silently falls back to the host's /usr/lib. That is not a +# missing-library error — it succeeds against whatever host LLVM runtime +# happens to be installed, and clang derives its resource dir from that +# install. With host LLVM 21.1 libs present but the host clang at 22, +# /usr/lib/clang/21 does not exist and every OpenCL compile dies with +# "'opencl-c-base.h' file not found" — nowhere near the real cause. +# +# 2. $ORIGIN/../lib. Tempting because it is relocatable, but WRONG here: it +# resolves inside the *consumer's* sysroot (mesa's), which also contains +# the Redox TARGET relibc. A host binary then loads the target libc.so.6 +# and dies with "undefined symbol: __fini_array_end". +# +# COOKBOOK_SYSROOT is this recipe's own sysroot and contains host-only +# libraries, so it is the correct target. It is absolute, so a checkout move +# requires re-cooking mesa-clc — acceptable, since the content-hash cache +# re-cooks it whenever the recipe or its deps change anyway. +for t in $_targets; do + _b="${COOKBOOK_STAGE}/usr/bin/$(basename "$t")" + [ -f "${_b}" ] || continue + patchelf --set-rpath "${COOKBOOK_SYSROOT}/usr/lib" "${_b}" +done + ls -la "${COOKBOOK_STAGE}/usr/bin/" ''' diff --git a/local/recipes/kde/breeze/recipe.toml b/local/recipes/kde/breeze/recipe.toml index 47cef7a622..924e5db8b0 100644 --- a/local/recipes/kde/breeze/recipe.toml +++ b/local/recipes/kde/breeze/recipe.toml @@ -55,6 +55,8 @@ cmake "${COOKBOOK_SOURCE}" \ -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH="${COOKBOOK_SYSROOT}" \ + -DKF6_HOST_TOOLING=/usr/lib/cmake \ + -DKConfigCompiler_EXECUTABLE=/usr/lib/kf6/kconfig_compiler_kf6 \ -DBUILD_TESTING=OFF \ -DBUILD_QT5=OFF \ -DBUILD_QT6=ON \ diff --git a/local/recipes/kde/kde-cli-tools/recipe.toml b/local/recipes/kde/kde-cli-tools/recipe.toml index b26737052a..dc0e16caf7 100644 --- a/local/recipes/kde/kde-cli-tools/recipe.toml +++ b/local/recipes/kde/kde-cli-tools/recipe.toml @@ -41,6 +41,13 @@ done # Disable kdesu — no sudo/kdesu backend on Redox sed -i 's/^add_subdirectory(kdesu/#add_subdirectory(kdesu/' "${COOKBOOK_SOURCE}/CMakeLists.txt" 2>/dev/null || true +# kstart is an X11-only tool: it sets X11 window properties on the app it +# launches and includes Qt's private X11 interop header, which qtbase does not +# install on a Wayland-only build: +# kstart/kstart.cpp:19:10: fatal error: private/qtx11extras_p.h: No such file +# It cannot function without an X server, so exclude it exactly as kdesu above. +# Idempotent: once commented, ^add_subdirectory no longer matches. +sed -i 's/^add_subdirectory(kstart/#add_subdirectory(kstart/' "${COOKBOOK_SOURCE}/CMakeLists.txt" 2>/dev/null || true rm -f CMakeCache.txt rm -rf CMakeFiles @@ -58,7 +65,16 @@ cmake "${COOKBOOK_SOURCE}" \ -DUSE_DBUS=OFF \ -Wno-dev cmake --build . -j"${COOKBOOK_MAKE_JOBS}" -cmake --install . --prefix "${COOKBOOK_STAGE}/usr" +# Must be DESTDIR, not --prefix. kde-cli-tools installs several targets to +# ${KDE_INSTALL_FULL_BINDIR}, i.e. an ABSOLUTE /usr/bin. `--prefix` only +# re-roots relative destinations, so absolute ones escape the stage and cmake +# writes straight into the BUILD HOST's filesystem: +# -- Up-to-date: /usr/bin/keditfiletype5 +# CMake Error: file INSTALL cannot copy ... to "/usr/bin/keditfiletype": +# Permission denied. +# Only the host's file permissions prevented this from polluting /usr/bin. +# DESTDIR re-roots absolute destinations too, which is why sddm uses it. +DESTDIR="${COOKBOOK_STAGE}" cmake --install . --prefix /usr find "${COOKBOOK_STAGE}" -name '*.so*' -exec patchelf --remove-rpath {} \\; 2>/dev/null || true """ diff --git a/local/recipes/kde/sddm/recipe.toml b/local/recipes/kde/sddm/recipe.toml index 7b4003b8f5..cc0e3b691f 100644 --- a/local/recipes/kde/sddm/recipe.toml +++ b/local/recipes/kde/sddm/recipe.toml @@ -155,6 +155,12 @@ cd build rm -f CMakeCache.txt rm -rf CMakeFiles +# QML_INSTALL_DIR must be set explicitly. SDDM's CMakeLists falls back to +# `qmake -query QT_INSTALL_QML`, and the only qmake available in a cross build +# is the host one under build/qt-host-build — so SddmComponents would install +# into the HOST Qt's qml dir instead of the target's /usr/qml. The greeter +# themes all `import SddmComponents 2.0`, so getting this wrong means the +# login UI fails to load at runtime with no build-time error. cmake "${COOKBOOK_SOURCE}" \ -DKF_SKIP_PO_PROCESSING=ON \ -DCMAKE_TOOLCHAIN_FILE="${COOKBOOK_ROOT}/local/recipes/qt/redox-toolchain.cmake" \ @@ -174,6 +180,7 @@ cmake "${COOKBOOK_SOURCE}" \ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ -DUID_MIN=1000 \ -DUID_MAX=65000 \ + -DQML_INSTALL_DIR=/usr/qml \ -DLIBXKB_INCLUDE_DIR="${COOKBOOK_SYSROOT}/usr/include" \ -DLIBXKB_LIBRARIES="${COOKBOOK_SYSROOT}/usr/lib/libxkbcommon.so" \ -Wno-dev diff --git a/local/recipes/libs/polkit/recipe.toml b/local/recipes/libs/polkit/recipe.toml index f7eb314b9b..e763bd0069 100644 --- a/local/recipes/libs/polkit/recipe.toml +++ b/local/recipes/libs/polkit/recipe.toml @@ -41,6 +41,16 @@ export RANLIB="x86_64-unknown-redox-ranlib" export CFLAGS="-I${COOKBOOK_SYSROOT}/usr/include --sysroot=${COOKBOOK_SYSROOT} -Wno-error=deprecated-declarations -Wno-error=incompatible-pointer-types -Wno-error=implicit-function-declaration" export LDFLAGS="--sysroot=${COOKBOOK_SYSROOT}" +# dbus-1.pc's system_bus_services_dir comes back sysroot-prefixed under a cross +# build, so upstream's pkg-config branch resolves to an absolute HOST path and +# installs org.freedesktop.PolicyKit1.service into +# /usr/share/dbus-1/system-services — which lands in the image as a +# bogus /mnt/... directory tree. Upstream's own fallback branch already computes +# the correct target-relative layout, so pin the value to that. +# Idempotent: after the first pass the line no longer matches. +sed -i "s|^ dbus_system_bus_services_dir = dbus_dep.get_pkgconfig_variable.*| dbus_system_bus_services_dir = pk_prefix / pk_datadir / 'dbus-1' / 'system-services'|" \\ + "${COOKBOOK_SOURCE}/meson.build" + cookbook_meson \\ -Dlibs-only=true \\ -Dintrospection=false \\