#!/bin/sh #SPDX-License-Identifier: LGPL-3.0-only #SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® # Bootstrap: compile crafter-build by hand, without crafter-build. The # self-host build through project.cpp follows (`./bin/crafter-build`). set -eu # The toolchain. CRAFTER_BUILD_LLVM_DIR names an LLVM prefix (the Flatpak # sets /app); otherwise the tools come from PATH. The same rule the built # binary applies at run time (Crafter.Build:Toolchain). if [ -n "${CRAFTER_BUILD_LLVM_DIR:-}" ]; then CXX="$CRAFTER_BUILD_LLVM_DIR/bin/clang++" CC="$CRAFTER_BUILD_LLVM_DIR/bin/clang" AR="$CRAFTER_BUILD_LLVM_DIR/bin/llvm-ar" LLVM_CONFIG="$CRAFTER_BUILD_LLVM_DIR/bin/llvm-config" # A prefix other than the system one keeps its libc++ off both the # linker's search path (clang looks in lib/ and the system dirs, # not /lib) and the loader's; -L and an rpath cover the two. if [ "$CRAFTER_BUILD_LLVM_DIR" != /usr ]; then LIBCXX_LINK_FLAGS="-L$CRAFTER_BUILD_LLVM_DIR/lib -Wl,-rpath,$CRAFTER_BUILD_LLVM_DIR/lib" else LIBCXX_LINK_FLAGS="" fi if [ -f "$CRAFTER_BUILD_LLVM_DIR/share/libc++/v1/std.cppm" ]; then STD_CPPM="$CRAFTER_BUILD_LLVM_DIR/share/libc++/v1/std.cppm" else STD_CPPM=/usr/share/libc++/v1/std.cppm fi else CXX=clang++ CC=clang AR=llvm-ar LLVM_CONFIG=llvm-config LIBCXX_LINK_FLAGS="" STD_CPPM=/usr/share/libc++/v1/std.cppm fi # The version baked into the binary: the environment (CI sets it from the # tag), else the nearest tag, else a development marker. `latest` is the # rolling CI tag and never a version. VERSION="${CRAFTER_BUILD_VERSION:-$(git describe --tags --always --dirty --exclude=latest 2>/dev/null || echo 0.0.0-dev)}" mkdir -p build bin lib share/crafter-build share/crafter-build/wasi-runtime cp wasi-runtime/runtime.js share/crafter-build/wasi-runtime/ cp wasi-runtime/index.html.in share/crafter-build/wasi-runtime/ # Partition order is the import order: every unit is listed before the # units that import it, and the umbrella last. PARTITIONS="Toolchain Shader Platform Interface Implementation External Clang Test Lint Progress Asset" cp interfaces/Crafter.Build.cppm share/crafter-build/ for p in $PARTITIONS; do cp "interfaces/Crafter.Build-$p.cppm" share/crafter-build/ done if [ ! -d build/glslang/.git ]; then git clone --depth 1 https://github.com/KhronosGroup/glslang.git build/glslang fi current_dir=$(pwd) cd build/glslang cmake -B build \ -DCMAKE_C_COMPILER="$CC" \ -DCMAKE_CXX_COMPILER="$CXX" \ -DCMAKE_CXX_FLAGS="-stdlib=libc++" \ -DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++ $LIBCXX_LINK_FLAGS" \ -DCMAKE_SHARED_LINKER_FLAGS="-stdlib=libc++ $LIBCXX_LINK_FLAGS" \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$current_dir/build" \ -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$current_dir/build" \ -DENABLE_OPT=OFF cmake --build build --config Release cd ../../ MARCH="${CRAFTER_BUILD_MARCH:-native}" MTUNE="${CRAFTER_BUILD_MTUNE:-native}" # The bootstrap targets the toolchain's own triple: x86_64-pc-linux-gnu on # glibc distros, x86_64-unknown-linux-gnu for the bundled LLVM, # x86_64-alpine-linux-musl on Alpine. Override with CRAFTER_BUILD_TARGET. TARGET="${CRAFTER_BUILD_TARGET:-$("$CXX" -print-target-triple)}" TARGET_DEFINE="CRAFTER_BUILD_CONFIGURATION_TARGET_$(printf '%s' "$TARGET" | tr - _)" # Crafter.Build-Lint includes libclang's clang-c/Index.h. glibc distros keep # it in /usr/include; other prefixes keep it under their own include dir, so # ask llvm-config and add the dir when it is not already on the default path # (never add /usr/include itself: that breaks libc++'s #include_next). LLVM_INCDIR="$("$LLVM_CONFIG" --includedir 2>/dev/null || true)" case "$LLVM_INCDIR" in ""|/usr/include) LLVM_INCFLAG="" ;; *) LLVM_INCFLAG="-I$LLVM_INCDIR" ;; esac common_options="--target=$TARGET -stdlib=libc++ -I./build/glslang $LLVM_INCFLAG -std=c++26 -O3 -march=$MARCH -mtune=$MTUNE -fprebuilt-module-path=./build -D $TARGET_DEFINE -D CRAFTER_BUILD_CONFIGURATION_TYPE_EXECUTABLE -D CRAFTER_BUILD_VERSION=\"$VERSION\" -c" "$CXX" --target="$TARGET" -std=c++26 -stdlib=libc++ -O3 -march="$MARCH" -mtune="$MTUNE" -Wno-reserved-identifier -Wno-reserved-module-identifier --precompile "$STD_CPPM" -o ./build/std.pcm # Asset partition: bootstrap compiles it WITHOUT CRAFTER_BUILD_HAS_ASSET so # CompressAsset takes the stub branch and the impl unit doesn't try to # `import Crafter.Asset` (no Crafter.Asset PCM exists at this stage — the # self-host pass that follows wires in the real dep). OBJECTS="" for p in $PARTITIONS; do "$CXX" $common_options -fmodule-output "interfaces/Crafter.Build-$p.cppm" -o "./build/Crafter.Build-$p.o" OBJECTS="$OBJECTS ./build/Crafter.Build-$p.o" done "$CXX" $common_options -fmodule-output interfaces/Crafter.Build.cppm -o ./build/Crafter.Build.o OBJECTS="$OBJECTS ./build/Crafter.Build.o" for p in $PARTITIONS; do "$CXX" $common_options "./implementations/Crafter.Build-$p.cpp" -o "./build/Crafter.Build-${p}_impl.o" OBJECTS="$OBJECTS ./build/Crafter.Build-${p}_impl.o" done "$CXX" $common_options ./implementations/main.cpp -o ./build/main.o # A fresh archive each time: `ar rcs` into an existing one keeps members a # previous layout left behind. rm -f ./lib/libcrafter-build.a "$AR" rcs ./lib/libcrafter-build.a $OBJECTS "$CXX" --target="$TARGET" -std=c++26 -stdlib=libc++ -O3 -march="$MARCH" -mtune="$MTUNE" -fuse-ld=lld \ -Wl,--export-dynamic $LIBCXX_LINK_FLAGS \ -L./build \ $OBJECTS \ ./build/main.o \ -lSPIRV -lGenericCodeGen -lglslang -lOSDependent -lMachineIndependent -lglslang-default-resource-limits \ -ldl \ -o ./bin/crafter-build