feat(toolchain): resolve the compiler in one place
Every clang++, clang and llvm-ar the tool spawned was a bare name on PATH, the std module source was /usr/share/libc++/v1/std.cppm, the WASI sysroot /usr/share/wasi-sysroot and the mingw headers /usr/x86_64-w64-mingw32, spelled out at eighteen call sites. A toolchain installed anywhere else, which is what the Flatpak ships under /app, had no way in. Crafter.Build:Toolchain resolves all of it once per process: CRAFTER_BUILD_LLVM_DIR, else a clang++ installed beside crafter-build (<prefix>/bin, found through the same walk GetCrafterBuildHome does), else PATH. What sits beside the compiler is used when present: its libclang.so, its clang-c headers, its std module source, its WASI sysroot. An explicit prefix without a clang++ is an error rather than a fallback, for the same reason CRAFTER_BUILD_LIBCLANG was already exclusive. CRAFTER_BUILD_LIBCXX_DIR points at a libc++ install other than the compiler's own, and CRAFTER_MINGW_DIR now does what its help line always claimed: it is passed as --sysroot for the mingw target. Binaries linked by a toolchain outside /usr get an rpath to its lib dir, since its libc++.so.1 is not on the loader's default path. HostTarget() is the resolved clang's -print-target-triple. A clang built without a vendor reports x86_64-unknown-linux-gnu where Arch's reports x86_64-pc-linux-gnu, so target equality that decides whether a test runs locally and which targets a bare `test` sweeps goes through SameTarget, which ignores the vendor field. The strings themselves are never rewritten: clang rejects a PCM whose triple differs from the importing unit's. The examples and README stop hardcoding the host triple; the default is already the host. `crafter-build --version` prints the version baked in at build time (CRAFTER_BUILD_VERSION, else `git describe`, else 0.0.0-dev), the compiler and the host triple, and is answered before any argument is forwarded to project.cpp. The version is a define on the library, so each version is its own library variant and relinks the executable and tests once per commit. build.sh gains a shebang and `set -eu`, honours CRAFTER_BUILD_LLVM_DIR and CRAFTER_BUILD_VERSION, skips the glslang clone when it is already there, and writes a fresh archive instead of appending to one that may hold members from an older layout. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
68e9b6bfa5
commit
046609ff6f
18 changed files with 767 additions and 190 deletions
190
build.sh
190
build.sh
|
|
@ -1,142 +1,126 @@
|
|||
#!/bin/sh
|
||||
#SPDX-License-Identifier: LGPL-3.0-only
|
||||
#SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
||||
|
||||
mkdir -p build
|
||||
mkdir -p bin
|
||||
mkdir -p lib
|
||||
mkdir -p share/crafter-build
|
||||
mkdir -p share/crafter-build/wasi-runtime
|
||||
# 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 the loader's
|
||||
# default path; the rpath is what lets the binary start.
|
||||
if [ "$CRAFTER_BUILD_LLVM_DIR" != /usr ]; then
|
||||
RPATH_FLAG="-Wl,-rpath,$CRAFTER_BUILD_LLVM_DIR/lib"
|
||||
else
|
||||
RPATH_FLAG=""
|
||||
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
|
||||
RPATH_FLAG=""
|
||||
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/
|
||||
|
||||
cp interfaces/Crafter.Build.cppm share/crafter-build/
|
||||
cp interfaces/Crafter.Build-Shader.cppm share/crafter-build/
|
||||
cp interfaces/Crafter.Build-Platform.cppm share/crafter-build/
|
||||
cp interfaces/Crafter.Build-Interface.cppm share/crafter-build/
|
||||
cp interfaces/Crafter.Build-Implementation.cppm share/crafter-build/
|
||||
cp interfaces/Crafter.Build-External.cppm share/crafter-build/
|
||||
cp interfaces/Crafter.Build-Clang.cppm share/crafter-build/
|
||||
cp interfaces/Crafter.Build-Test.cppm share/crafter-build/
|
||||
cp interfaces/Crafter.Build-Lint.cppm share/crafter-build/
|
||||
cp interfaces/Crafter.Build-Progress.cppm share/crafter-build/
|
||||
cp interfaces/Crafter.Build-Asset.cppm share/crafter-build/
|
||||
# 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"
|
||||
|
||||
git clone https://github.com/KhronosGroup/glslang.git ./build/glslang
|
||||
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
|
||||
cd build/glslang
|
||||
cmake -B build \
|
||||
-DCMAKE_C_COMPILER=clang \
|
||||
-DCMAKE_CXX_COMPILER=clang++ \
|
||||
-DCMAKE_C_COMPILER="$CC" \
|
||||
-DCMAKE_CXX_COMPILER="$CXX" \
|
||||
-DCMAKE_CXX_FLAGS="-stdlib=libc++" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++" \
|
||||
-DCMAKE_SHARED_LINKER_FLAGS="-stdlib=libc++" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++ $RPATH_FLAG" \
|
||||
-DCMAKE_SHARED_LINKER_FLAGS="-stdlib=libc++ $RPATH_FLAG" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=$current_dir/build \
|
||||
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=$current_dir/build \
|
||||
-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 host toolchain's own triple: x86_64-pc-linux-gnu
|
||||
# on glibc distros, x86_64-alpine-linux-musl on Alpine. Override with
|
||||
# CRAFTER_BUILD_TARGET. The per-target define (triple with '-' -> '_') is the
|
||||
# same one the self-hosted build emits, so the host-gated code paths match.
|
||||
TARGET="${CRAFTER_BUILD_TARGET:-$(clang++ -print-target-triple)}"
|
||||
# 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; Alpine keeps LLVM under /usr/lib/llvmNN, so ask
|
||||
# llvm-config and add the dir when it is not already on the default path
|
||||
# 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)"
|
||||
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 -c"
|
||||
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"
|
||||
|
||||
clang++ --target=$TARGET -std=c++26 -stdlib=libc++ -O3 -march=$MARCH -mtune=$MTUNE -Wno-reserved-identifier -Wno-reserved-module-identifier --precompile /usr/share/libc++/v1/std.cppm -o ./build/std.pcm
|
||||
"$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
|
||||
|
||||
clang++ $common_options -fmodule-output interfaces/Crafter.Build-Shader.cppm -o ./build/Crafter.Build-Shader.o
|
||||
clang++ $common_options -fmodule-output interfaces/Crafter.Build-Platform.cppm -o ./build/Crafter.Build-Platform.o
|
||||
clang++ $common_options -fmodule-output interfaces/Crafter.Build-Interface.cppm -o ./build/Crafter.Build-Interface.o
|
||||
clang++ $common_options -fmodule-output interfaces/Crafter.Build-Implementation.cppm -o ./build/Crafter.Build-Implementation.o
|
||||
clang++ $common_options -fmodule-output interfaces/Crafter.Build-External.cppm -o ./build/Crafter.Build-External.o
|
||||
clang++ $common_options -fmodule-output interfaces/Crafter.Build-Clang.cppm -o ./build/Crafter.Build-Clang.o
|
||||
clang++ $common_options -fmodule-output interfaces/Crafter.Build-Test.cppm -o ./build/Crafter.Build-Test.o
|
||||
clang++ $common_options -fmodule-output interfaces/Crafter.Build-Lint.cppm -o ./build/Crafter.Build-Lint.o
|
||||
clang++ $common_options -fmodule-output interfaces/Crafter.Build-Progress.cppm -o ./build/Crafter.Build-Progress.o
|
||||
# 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).
|
||||
clang++ $common_options -fmodule-output interfaces/Crafter.Build-Asset.cppm -o ./build/Crafter.Build-Asset.o
|
||||
clang++ $common_options -fmodule-output interfaces/Crafter.Build.cppm -o ./build/Crafter.Build.o
|
||||
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"
|
||||
|
||||
clang++ $common_options ./implementations/Crafter.Build-Shader.cpp -o ./build/Crafter.Build-Shader_impl.o
|
||||
clang++ $common_options ./implementations/Crafter.Build-Platform.cpp -o ./build/Crafter.Build-Platform_impl.o
|
||||
clang++ $common_options ./implementations/Crafter.Build-Interface.cpp -o ./build/Crafter.Build-Interface_impl.o
|
||||
clang++ $common_options ./implementations/Crafter.Build-Implementation.cpp -o ./build/Crafter.Build-Implementation_impl.o
|
||||
clang++ $common_options ./implementations/Crafter.Build-External.cpp -o ./build/Crafter.Build-External_impl.o
|
||||
clang++ $common_options ./implementations/Crafter.Build-Clang.cpp -o ./build/Crafter.Build-Clang_impl.o
|
||||
clang++ $common_options ./implementations/Crafter.Build-Test.cpp -o ./build/Crafter.Build-Test_impl.o
|
||||
clang++ $common_options ./implementations/Crafter.Build-Lint.cpp -o ./build/Crafter.Build-Lint_impl.o
|
||||
clang++ $common_options ./implementations/Crafter.Build-Progress.cpp -o ./build/Crafter.Build-Progress_impl.o
|
||||
clang++ $common_options ./implementations/Crafter.Build-Asset.cpp -o ./build/Crafter.Build-Asset_impl.o
|
||||
clang++ $common_options ./implementations/main.cpp -o ./build/main.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
|
||||
|
||||
ar rcs ./lib/libcrafter-build.a \
|
||||
./build/Crafter.Build-Shader.o \
|
||||
./build/Crafter.Build-Platform.o \
|
||||
./build/Crafter.Build-Interface.o \
|
||||
./build/Crafter.Build-Implementation.o \
|
||||
./build/Crafter.Build-External.o \
|
||||
./build/Crafter.Build-Clang.o \
|
||||
./build/Crafter.Build-Test.o \
|
||||
./build/Crafter.Build-Lint.o \
|
||||
./build/Crafter.Build-Progress.o \
|
||||
./build/Crafter.Build-Asset.o \
|
||||
./build/Crafter.Build.o \
|
||||
./build/Crafter.Build-Shader_impl.o \
|
||||
./build/Crafter.Build-Platform_impl.o \
|
||||
./build/Crafter.Build-Interface_impl.o \
|
||||
./build/Crafter.Build-Implementation_impl.o \
|
||||
./build/Crafter.Build-External_impl.o \
|
||||
./build/Crafter.Build-Clang_impl.o \
|
||||
./build/Crafter.Build-Test_impl.o \
|
||||
./build/Crafter.Build-Lint_impl.o \
|
||||
./build/Crafter.Build-Progress_impl.o \
|
||||
./build/Crafter.Build-Asset_impl.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
|
||||
|
||||
clang++ --target=$TARGET -std=c++26 -stdlib=libc++ -O3 -march=$MARCH -mtune=$MTUNE -fuse-ld=lld \
|
||||
-Wl,--export-dynamic \
|
||||
"$CXX" --target="$TARGET" -std=c++26 -stdlib=libc++ -O3 -march="$MARCH" -mtune="$MTUNE" -fuse-ld=lld \
|
||||
-Wl,--export-dynamic $RPATH_FLAG \
|
||||
-L./build \
|
||||
./build/Crafter.Build-Shader.o \
|
||||
./build/Crafter.Build-Platform.o \
|
||||
./build/Crafter.Build-Interface.o \
|
||||
./build/Crafter.Build-Implementation.o \
|
||||
./build/Crafter.Build-External.o \
|
||||
./build/Crafter.Build-Clang.o \
|
||||
./build/Crafter.Build-Test.o \
|
||||
./build/Crafter.Build-Lint.o \
|
||||
./build/Crafter.Build-Progress.o \
|
||||
./build/Crafter.Build-Asset.o \
|
||||
./build/Crafter.Build.o \
|
||||
./build/Crafter.Build-Shader_impl.o \
|
||||
./build/Crafter.Build-Platform_impl.o \
|
||||
./build/Crafter.Build-Interface_impl.o \
|
||||
./build/Crafter.Build-Implementation_impl.o \
|
||||
./build/Crafter.Build-External_impl.o \
|
||||
./build/Crafter.Build-Clang_impl.o \
|
||||
./build/Crafter.Build-Test_impl.o \
|
||||
./build/Crafter.Build-Lint_impl.o \
|
||||
./build/Crafter.Build-Progress_impl.o \
|
||||
./build/Crafter.Build-Asset_impl.o \
|
||||
$OBJECTS \
|
||||
./build/main.o \
|
||||
-lSPIRV -lGenericCodeGen -lglslang -lOSDependent -lMachineIndependent -lglslang-default-resource-limits \
|
||||
-ldl \
|
||||
-o ./bin/crafter-build
|
||||
-o ./bin/crafter-build
|
||||
|
|
|
|||
Loading…
Reference in a new issue