Crafter.Build/packaging/flatpak/net.catcrafts.CrafterBuild.yaml
Jorijn van der Graaf 16db37bbe6
feat(flatpak): ship lldb and the Khronos validation layers
Programs that -r and the test runner start run inside the Flatpak's
sandbox, and the Sdk it runs on has gdb but neither lldb nor the Khronos
validation layer: in the sandbox of beta 5.0.0, a vkCreateInstance that
asks for VK_LAYER_KHRONOS_validation returns VK_ERROR_LAYER_NOT_PRESENT.
flatpak run clears VK_LAYER_PATH and VK_ADD_LAYER_PATH, so the layer the
host has cannot stand in.

lldb becomes a project of the llvm module and brings lldb-server,
lldb-dap and lldb-mcp. Its Python, libedit, curses, libxml2 and lzma
support are set ON instead of being left to detection, so a dependency
that goes missing fails the configure step rather than shipping an lldb
without it. The Sdk has neither SWIG nor libedit, so both become modules
before llvm, SWIG as build-only.

The layer is Vulkan-ValidationLayers vulkan-sdk-1.4.357.0, the Vulkan
SDK release of the Sdk's loader (libvulkan.so.1.4.357), built from
Vulkan-Headers, Vulkan-Utility-Libraries, SPIRV-Headers and SPIRV-Tools
at the revisions that release's scripts/known_good.json names. Those
four are built into /app at those revisions and removed afterwards. All
five come after the LLVM and WASI modules, so that bumping them reuses
the cached LLVM and WASI builds. UPDATE_DEPS is turned off: it defaults
to ON, which has update_deps.py clone the dependencies, and of all the
modules only crafter-build's build-args share the network.
2026-11-01 19:20:22 +01:00

397 lines
17 KiB
YAML

# SPDX-License-Identifier: LGPL-3.0-only
# SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
#
# crafter-build as a Flatpak. The runtime is the Freedesktop *Sdk*, not the
# Platform: a build tool needs glibc's headers and crt objects, gcc's
# libgcc_s, cmake, ninja, make, git and python at run time. Everything
# compiler-shaped is ours and lives under /app: clang, lld, libclang, libc++,
# compiler-rt (native and wasm32), lldb and the WASI sysroot, all built from
# one LLVM source tree so the modules crafter-build builds and the compiler
# that consumes them can never drift apart.
#
# Programs that `-r` and the test runner start run in this sandbox, so the
# tools to debug them live here too: lldb (above), the Sdk's gdb, valgrind
# and strace, and the Khronos Vulkan validation layers, GPU-assisted
# validation included, which neither the Sdk nor its GL extensions carry.
app-id: net.catcrafts.CrafterBuild
runtime: org.freedesktop.Sdk
runtime-version: '26.08'
sdk: org.freedesktop.Sdk
command: crafter-build
finish-args:
# git dependencies, and the local web server `-r` starts for browser builds
- --share=network
- --socket=ssh-auth
# projects live anywhere; user sysroots too
- --filesystem=host
# so `-r` can launch what it built, games included
- --share=ipc
- --socket=wayland
- --socket=fallback-x11
- --socket=pulseaudio
- --device=all
# lldb, and gdb and friends from the Sdk
- --allow=devel
- --env=PATH=/app/bin:/usr/bin
cleanup:
- /share/man
- /share/doc
modules:
- name: swig
# Generates lldb's Python bindings while the llvm module builds; nothing
# of it ships.
cleanup:
- '*'
sources:
- type: archive
url: https://downloads.sourceforge.net/project/swig/swig/swig-4.4.1/swig-4.4.1.tar.gz
sha256: 40162a706c56f7592d08fd52ef5511cb7ac191f3593cf07306a0a554c6281fcf
- name: libedit
# Line editing, history and completion at lldb's prompt. The Sdk has the
# ncurses it needs but not libedit itself; liblldb links the shared
# library, so that ships and the rest goes.
config-opts:
- --disable-static
cleanup:
- /include
- /lib/pkgconfig
- /lib/*.la
sources:
- type: archive
url: https://thrysoee.dk/editline/libedit-20260512-3.1.tar.gz
sha256: 432d5e7ea8b0116dd39f2eca7bc11d0eed77faa6b77ea526ace89907c23ea4a0
- name: llvm
buildsystem: cmake-ninja
builddir: true
subdir: llvm
build-options:
# flatpak-builder's default CFLAGS carry -g. For all of LLVM that is a
# 30 GB build tree and a multi-gigabyte .Debug extension, so build
# without debug info, strip, and skip the split. The hardening flags
# from the defaults stay.
no-debuginfo: true
strip: true
cflags: -O2 -pipe -fexceptions -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protection
cflags-override: true
cxxflags: -O2 -pipe -fexceptions -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protection
cxxflags-override: true
config-opts:
- -DCMAKE_BUILD_TYPE=Release
- -DLLVM_ENABLE_ASSERTIONS=OFF
- -DLLVM_ENABLE_PROJECTS=clang;lld;lldb
- -DLLVM_ENABLE_RUNTIMES=compiler-rt;libcxx;libcxxabi;libunwind
# lldb with Python scripting (its bindings generated by the swig module
# above, against the Sdk's Python), libedit (the module above), curses,
# libxml2 and lzma, each set ON rather than left to the default of "if
# found", so a dependency gone missing fails the configure step instead
# of shipping an lldb without it. lldb-server, lldb-dap and lldb-mcp
# come with it.
- -DLLDB_ENABLE_PYTHON=ON
- -DLLDB_ENABLE_LIBEDIT=ON
- -DLLDB_ENABLE_CURSES=ON
- -DLLDB_ENABLE_LIBXML2=ON
- -DLLDB_ENABLE_LZMA=ON
- -DLLDB_ENABLE_LUA=OFF
- -DLLVM_TARGETS_TO_BUILD=X86;AArch64;WebAssembly
# Classic layout: libc++ in lib/ and include/c++/v1, not under a
# per-target subdirectory, the same shape as a distro install.
# crafter-build adds -L and an rpath for <prefix>/lib itself, since
# clang searches only its per-target directory and the system paths.
- -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF
# One shared LLVM and one shared clang library instead of a statically
# linked copy per tool: a fraction of the install size.
- -DLLVM_BUILD_LLVM_DYLIB=ON
- -DLLVM_LINK_LLVM_DYLIB=ON
- -DCLANG_LINK_CLANG_DYLIB=ON
- -DCLANG_DEFAULT_CXX_STDLIB=libc++
- -DCLANG_DEFAULT_LINKER=lld
- -DLIBCXX_INSTALL_MODULES=ON
- -DLLVM_INCLUDE_TESTS=OFF
- -DLLVM_INCLUDE_EXAMPLES=OFF
- -DLLVM_INCLUDE_DOCS=OFF
- -DLLVM_INCLUDE_BENCHMARKS=OFF
- -DLLVM_INSTALL_UTILS=OFF
- -DCLANG_INCLUDE_TESTS=OFF
- -DCOMPILER_RT_INCLUDE_TESTS=OFF
# The Sdk links with binutils' ld; two libLLVM-sized links at a time
# fit the CX53's memory with room to spare.
- -DLLVM_PARALLEL_LINK_JOBS=2
cleanup:
- /include/llvm
- /include/llvm-c
- /include/clang
- /include/clang-tidy
- /include/lld
- /include/lldb
- /lib/cmake
- /lib/*.a
- /share/opt-viewer
- /share/scan-build
- /share/scan-view
- /bin/clang-check
- /bin/clang-extdef-mapping
- /bin/clang-import-test
- /bin/clang-linker-wrapper
- /bin/clang-nvlink-wrapper
- /bin/clang-offload-bundler
- /bin/clang-offload-packager
- /bin/clang-refactor
- /bin/clang-rename
- /bin/clang-repl
- /bin/clang-sycl-linker
- /bin/diagtool
- /bin/git-clang-format
- /bin/hmaptool
- /bin/llvm-exegesis
- /bin/scan-build*
- /bin/scan-view
sources:
- type: archive
url: https://github.com/llvm/llvm-project/releases/download/llvmorg-23.1.2/llvm-project-23.1.2.src.tar.xz
sha256: c98bbef08a2b4c2613cd50e9aa9ae7b69b1fe6c16b2c40373bc0ab6116fdf78a
- name: wasi-sysroot
# wasi-sdk's sysroot-only mode, driven by the clang built above:
# wasi-libc, compiler-rt builtins (installed into our clang's resource
# dir, where the wasm32 driver looks for them) and libc++ for wasip1 and
# wasip1-threads. The llvm-project tree is the same release as above so
# the wasm libc++ matches the native one.
buildsystem: cmake-ninja
builddir: true
build-options:
no-debuginfo: true
# flatpak-builder's default CFLAGS/LDFLAGS are x86-64 hardening flags
# (-fcf-protection, -z relro) that the nested wasm32 builds inherit
# through the environment and clang rejects for that target.
cflags: ""
cflags-override: true
cxxflags: ""
cxxflags-override: true
ldflags: ""
ldflags-override: true
strip: true
config-opts:
- -DCMAKE_TOOLCHAIN_FILE=/run/build/wasi-sysroot/wasi-host-toolchain.cmake
- -DWASI_SDK_BUILD_TOOLCHAIN=OFF
- -DWASI_SDK_INSTALL_TO_CLANG_RESOURCE_DIR=ON
- -DWASI_SDK_TARGETS=wasm32-wasip1;wasm32-wasip1-threads
- -DWASI_SDK_INCLUDE_TESTS=OFF
# crafter-build compiles every wasm unit with C++ exceptions and links
# the libc++ and libunwind built with them, from lib/<triple>/eh. The
# default is DUAL only when the driving clang is 23 or newer and OFF
# below that; said outright, an LLVM downgrade cannot quietly ship a
# sysroot that no wasm build links against.
- -DWASI_SDK_EXCEPTIONS=DUAL
- -DCMAKE_INSTALL_PREFIX=/app
post-install:
# wasi-sdk installs into <prefix>/share/wasi-sysroot; crafter-build
# looks there (Crafter.Build:Toolchain), so nothing to move.
- test -f /app/share/wasi-sysroot/share/libc++/v1/std.cppm
# The wasm tests skip when these are missing, as on a distro sysroot,
# so the Flatpak checks for them itself: without them its CI would
# pass while every wasm build failed.
- test -f /app/share/wasi-sysroot/lib/wasm32-wasip1/eh/libunwind.a
- test -f /app/share/wasi-sysroot/lib/wasm32-wasip1-threads/eh/libunwind.a
sources:
- type: git
url: https://github.com/WebAssembly/wasi-sdk.git
tag: wasi-sdk-34
disable-submodules: true
# The compiler-rt sub-build gets the C target but not the ASM target, so
# its two wasm/*.S stubs come out as host objects when the driving clang
# does not default to wasm32. Reported upstream; drop once wasi-sdk has it.
- type: patch
path: wasi-sdk-asm-target.patch
- type: git
url: https://github.com/WebAssembly/wasi-libc.git
commit: 2e6fb9d8ee0cdf9e431fbcabe8af3115de000a13
dest: src/wasi-libc
# A git checkout, where the llvm module above unpacks the release
# tarball of the same tag: wasi-sdk treats src/llvm-project as the
# submodule it is upstream. It patches the tree with `git apply` before
# building libc++, and records `git rev-parse HEAD` in the sysroot's
# VERSION file. Unpacked from a tarball the directory is a plain
# subdirectory of the wasi-sdk checkout, where git treats the patched
# paths as outside the current directory, skips every one of them and
# exits 0. LLVM 22 happened to build without the patches; LLVM 23's
# libc++ does not compile for WASI without one of them.
- type: git
url: https://github.com/llvm/llvm-project.git
tag: llvmorg-23.1.2
commit: 85ac560262434c9ccfc0c183ec22d4138ed647fb
dest: src/llvm-project
- type: file
path: wasi-host-toolchain.cmake
- name: wasmtime
# The runner for wasm32-wasi tests and `-r` on a non-browser wasm build.
buildsystem: simple
build-commands:
- install -Dm755 wasmtime /app/bin/wasmtime
sources:
- type: archive
url: https://github.com/bytecodealliance/wasmtime/releases/download/v49.0.2/wasmtime-v49.0.2-x86_64-linux.tar.xz
sha256: a4d6e9e3a5a60f527cf7793d674c48930c80c2e8977995b8a275cad3254b9322
- name: libcxx-22-modules
# The std module source of the libc++ release before the bundled one, for
# cross sysroots that carry that libc++ without it: Alpine packages the
# headers and the library but not share/libc++/v1, and a module source
# only compiles against the headers of its own release. crafter-build
# picks <major>/std.cppm here by the sysroot's _LIBCPP_VERSION
# (SysrootStdModule in Crafter.Build:Toolchain). Add a module like this
# one per release worth supporting; the bundled clang has to be able to
# compile that release's headers.
buildsystem: simple
build-commands:
# Configure only. The cxx-modules component is std.cppm as configure
# generates it plus the .inc files straight from the source tree, so
# nothing is compiled, and libc++'s own install rule stays the one
# place that knows what a module source install consists of.
- cmake -S runtimes -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/app/bin/clang -DCMAKE_CXX_COMPILER=/app/bin/clang++ "-DLLVM_ENABLE_RUNTIMES=libcxx;libcxxabi" -DLIBCXXABI_USE_LLVM_UNWINDER=OFF -DLIBCXX_INSTALL_MODULES=ON
# Staged, not installed to /app: the component also writes
# lib/libc++.modules.json, which would replace the bundled libc++'s.
- cmake --install build --component cxx-modules --prefix "$PWD/stage"
- grep -q "_LIBCPP_VERSION 22" libcxx/include/__config
- mkdir -p /app/share/crafter-build/libc++-modules
- cp -r stage/share/libc++/v1 /app/share/crafter-build/libc++-modules/22
sources:
- type: archive
url: https://github.com/llvm/llvm-project/releases/download/llvmorg-22.1.8/llvm-project-22.1.8.src.tar.xz
sha256: 922f1817a0df7b1489272d18134ee0087a8b068828f87ac63b9861b1a9965888
# The Khronos validation layers and the four modules they are built from,
# after llvm, so that bumping them reuses the cached LLVM build. All five
# are pinned to the Vulkan SDK release of the Sdk's own Vulkan loader and
# headers (1.4.357), at the dependency revisions that release's
# scripts/known_good.json names. When the runtime moves to a newer loader,
# move the layers to the SDK release of that loader and take the other
# four revisions from its known_good.json again. The four are built into
# /app at those revisions rather than taken from the Sdk, whose versions
# follow the runtime, and none of them ships.
- name: vulkan-headers
buildsystem: cmake-ninja
builddir: true
cleanup:
- '*'
sources:
- type: archive
url: https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/v1.4.357.tar.gz
sha256: 7dc0dbcf1d49dd3d7da3761c251c6097dfbaac475321a4a8a99269d3d5abecdc
- name: vulkan-utility-libraries
buildsystem: cmake-ninja
builddir: true
config-opts:
- -DCMAKE_BUILD_TYPE=Release
# CMake searches its install prefix after /usr, where the Sdk has
# Vulkan headers of its own.
- -DCMAKE_PREFIX_PATH=/app
cleanup:
- '*'
sources:
- type: archive
url: https://github.com/KhronosGroup/Vulkan-Utility-Libraries/archive/refs/tags/v1.4.357.tar.gz
sha256: e8688013cdc67dad26f15dcece91fa6b80ad595d551fceb56397fc4795efd00a
- name: spirv-headers
buildsystem: cmake-ninja
builddir: true
cleanup:
- '*'
sources:
- type: archive
url: https://github.com/KhronosGroup/SPIRV-Headers/archive/29981f65241605e08b0ede4cfeb999fe3b723c6a.tar.gz
sha256: 232899f1ad4104fb5bc377b94596c7621575eee62ad9a9e8f929b63a7dd8a7ad
- name: spirv-tools
# The optimizer GPU-assisted validation instruments shaders with, linked
# into the layer statically.
buildsystem: cmake-ninja
builddir: true
build-options:
no-debuginfo: true
config-opts:
- -DCMAKE_BUILD_TYPE=Release
# The installed SPIRV-Headers: its include/ holds the grammar files
# SPIRV-Tools generates its tables from, as the source tree does.
- -DSPIRV-Headers_SOURCE_DIR=/app
- -DSPIRV_SKIP_EXECUTABLES=ON
- -DSPIRV_WERROR=OFF
cleanup:
- '*'
sources:
- type: archive
url: https://github.com/KhronosGroup/SPIRV-Tools/archive/b707790a898e44038547df54580022fc1cf89c3d.tar.gz
sha256: 05d8af89737bde57571c48dbd36714c9f520a69623e14de72c3be6b600e277d6
- name: vulkan-validation-layers
# VK_LAYER_KHRONOS_validation. The loader finds its manifest under
# /app/share/vulkan/explicit_layer.d through XDG_DATA_DIRS, and the
# manifest names the library without a path, which the sandbox's loader
# finds in /app/lib. GPU-AV is a setting of this layer, not a layer of
# its own (VK_KHRONOS_VALIDATION_GPUAV_ENABLE=1, or the layer settings).
buildsystem: cmake-ninja
builddir: true
build-options:
no-debuginfo: true
strip: true
config-opts:
- -DCMAKE_BUILD_TYPE=Release
- -DCMAKE_PREFIX_PATH=/app
# ON by default: it clones every dependency with update_deps.py, which
# the build sandbox has no network for, instead of using the four
# modules above.
- -DUPDATE_DEPS=OFF
- -DBUILD_TESTS=OFF
- -DBUILD_WERROR=OFF
post-install:
- test -f /app/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json
- test -f /app/lib/libVkLayer_khronos_validation.so
sources:
- type: archive
url: https://github.com/KhronosGroup/Vulkan-ValidationLayers/archive/refs/tags/vulkan-sdk-1.4.357.0.tar.gz
sha256: 73180b11992a3554e97ebc18e6bf2b45ff9790ded9d87fc526c7bab865d1303f
- name: crafter-build
buildsystem: simple
build-options:
# The self-host build fetches Crafter.Math, Crafter.Asset,
# Crafter.LintRules and glslang from git; they are unpinned on purpose
# (sibling repos tracking their default branch, see AGENTS.template.md).
build-args:
- --share=network
# On this module, not at the top of the manifest: top-level build
# options are part of every module's cache key, and the version changes
# with every commit, which made flatpak-builder rebuild LLVM each run.
env:
CRAFTER_BUILD_LLVM_DIR: /app
# The shipped binary runs on any x86_64 from the last decade; user
# projects still build with -march=native by default.
CRAFTER_BUILD_MARCH: x86-64-v2
CRAFTER_BUILD_MTUNE: generic
# CI replaces this with the version; a local build is a development
# build.
CRAFTER_BUILD_VERSION: 0.0.0-dev
build-commands:
# Bootstrap by hand, then let the result build itself: only the
# self-hosted binary has asset support and ThinLTO.
- ./build.sh
- ./bin/crafter-build
- CRAFTER_BUILD_HOME=$PWD/share/crafter-build ./bin/crafter-build test
- install -Dm755 bin/crafter.build-exe-*/crafter-build /app/bin/crafter-build
- install -Dm644 bin/crafter.build-lib-*/libcrafter-build.a /app/lib/libcrafter-build.a
- mkdir -p /app/share && cp -r share/crafter-build /app/share/
- install -Dm644 LICENSE LICENSE.GPL -t /app/share/licenses/net.catcrafts.CrafterBuild/
- install -Dm644 packaging/flatpak/net.catcrafts.CrafterBuild.metainfo.xml -t /app/share/metainfo/
sources:
- type: dir
path: ../..
skip:
- .git
- bin
- build
- lib/libcrafter-build.a
- share/crafter-build