The entry point for contributing to swiftlang/swift
from NixOS. The official build-script doesn't build on NixOS; this makes the full
from-source contributor loop (build, test, send a PR) work.
Two files: flake.nix (the dev shell) and dobuild.sh (the build script). No Swift /
LLVM / Foundation source is patched.
Status: it works, including the C++ interoperability overlay (CxxStdlib) and
Foundation. The built swiftc compiles, links, and runs real Swift programs, can
import CxxStdlib and call into C++, and import Foundation:
Heads up: a bare
swiftcon yourPATHis the bootstrap compiler Nix uses to build Swift (Swift version 5.10.1), not the one you built. The compiler you build lives in the build dir as$SWIFTC(defined in the note below). The snippets below use that built compiler, the onlyswiftcthat reports6.5-dev.
SWIFTC is the compiler you just built,
build/Ninja-RelWithDebInfoAssert+swift-DebugAssert/swift-linux-x86_64/bin/swiftc (the same path
nix run .#smoke-test uses). The README only ever invokes swiftc and the platform runtime dir,
so it points the variable straight at the swift tree. CONTRIBUTING.md anchors $B one level up
at the build dir instead, because its test commands also reach the sibling LLVM tree.
The snippets below run inside the dev shell. Either run
nix develop .#fullfirst, or add a.envrccontaininguse flake .#fullso direnv activates it automatically when youcdinto the workspace.
$ B=build/Ninja-RelWithDebInfoAssert+swift-DebugAssert/swift-linux-x86_64
$ SWIFTC="$B/bin/swiftc"
$ "$SWIFTC" --version
Swift version 6.5-dev (LLVM …, Swift …)
$ echo 'print((1...5).map{$0*$0})' > hi.swift && "$SWIFTC" hi.swift -o hi && ./hi
[1, 4, 9, 16, 25]
hello from C++ std::string
9A1CDB09-… 1970-01-01 00:00:00 +0000
C++ interop and Foundation each need their own flags; see §3, or run nix run .#smoke-test
to verify all three at once.
Run only one build at a time: overlapping build-script runs share the same build/
dir and corrupt each other.
This repo is only the recipe (flake + script + notes). You fetch Apple's Swift source yourself (next section).
- README (this file): reproduce the working build.
- CONTRIBUTING.md: the edit → build → test → PR loop for contributing
to
swiftlang/swift. - HACKING.md: why NixOS fights a from-source build, the five fix categories, and the Foundation gdb debugging story.
Built against swiftlang/swift main HEAD (verified nixpkgs pin and component versions in
VERSIONS.md). Clone this repo as the workspace, clone Swift into it, then pull the siblings:
git clone https://github.com/lucasly-ba/swift-nixos.git swift-workspace
cd swift-workspace
git clone https://github.com/swiftlang/swift.git
nix develop --command swift/utils/update-checkout --cloneRun update-checkout through nix develop so the flake's python3 is on PATH. Layout:
swift-workspace/ ← this repo (swift-nixos), cloned
├── flake.nix flake.lock dobuild.sh .gitignore
├── swift/ ← swiftlang/swift
├── llvm-project/ llbuild/ cmark/ swift-syntax/ … ← from update-checkout
└── build/ ← created by the build (large; keep on a roomy filesystem)
- Re-run
update-checkoutafter everygit pullofswift/. It pins the sibling repos (llvm-project, swift-syntax, corelibs, …) to the revisions that match yourswift/HEAD, keeping the workspace internally consistent so the siblings move with swift. Run it the same way:nix develop --command swift/utils/update-checkout. - If you pulled
swift/but the siblings lagged, the C++ build breaks first. Two typical symptoms of a stale workspace:fatal error: 'clang/DependencyScanning/...' file not found(oldllvm-project) andASTGen ... has no member 'macroExpansionDecl'(oldswift-syntax). Resync the siblings without moving yourswift/feature branch:(swift/utils/update-checkout --scheme main --skip-repository swift --reset-to-remote
--skip-repository swiftkeeps your branch;--match-timestampalone is not enough, it can leave a sibling stale.) Then rebuild. LLVM is cached after the first pass. - The flake/
dobuild.shfixes are the part you maintain. The NixOS-specific fixes (the#include_nextglibc ordering, the sysroot, the rpath/-rpath-linkflags; see What was fixed below) are tuned against the pinned toolchain (gcc 15.2.0 / glibc 2.42). Building newermainsource against that fixed toolchain is where breakage appears first: the question is "did Swift change, or did a toolchain assumption change". The flake is the part you own.
Cheap insurance: when a build comes up clean, note the swift/ commit hash
(git -C swift rev-parse HEAD). If a later git pull breaks the build, that gives you a
"this worked" coordinate to git log / bisect against.
From swift-workspace/:
nix develop --command bash dobuild.sh foundation| I want to contribute to... | Dev shell | Build command |
|---|---|---|
| Compiler (Sema, SIL, diagnostics) | nix develop .#compiler |
./dobuild.sh compiler |
| Standard library | nix develop .#compiler |
./dobuild.sh compiler |
| C++ interop overlay (CxxStdlib) | nix develop .#compiler |
./dobuild.sh compiler |
Running the .sil FileCheck tests |
nix develop .#compiler |
./dobuild.sh compiler-tests |
| Foundation / libdispatch | nix develop .#full |
./dobuild.sh foundation |
./dobuild.sh compiler builds the compiler, stdlib, and C++ interop overlay in a single
pass (they cannot be separated in build-script) and skips Foundation. Use it for
compiler, stdlib, or C++ interop work. ./dobuild.sh foundation adds libdispatch and
Foundation on top. See CONTRIBUTING.md for the full edit -> rebuild -> test loop.
./dobuild.sh compiler-tests is compiler plus the lit test tools, so you can run the
SIL optimizer's FileCheck tests locally (sil-opt is a symlink to swift-frontend; it is
not built by plain compiler). Switching between compiler and compiler-tests flips
SWIFT_INCLUDE_TESTS, which is cached, so delete the swift CMakeCache.txt (see below) when
you change. Run one test directly, e.g.:
B=build/Ninja-RelWithDebInfoAssert+swift-DebugAssert
$B/swift-linux-x86_64/bin/sil-opt -enable-sil-verify-all test/SILOptimizer/foo.sil <passes> \
| $B/llvm-linux-x86_64/bin/FileCheck test/SILOptimizer/foo.silAfter a build, sanity-check it with: nix run .#smoke-test
dobuild.sh foundation wraps swift/utils/build-script with the NixOS-specific options the
flake can't deliver any other way: a glibc -sdk sysroot for the stdlib's clang-importer, an
-Xcc --gcc-toolchain so the C++ interop overlay finds libstdc++, and the corelibs -sdk /
link flags that let Foundation build. These must go on the build-script command line (the
EXTRA_CMAKE_OPTIONS env var only reaches LLVM's CMake, not Swift's). ./dobuild.sh compiler
is the same minus the libdispatch/Foundation flags.
For the full per-flag rationale, see HACKING.md (§1, The build command, flag by
flag) or the header comment in dobuild.sh.
After editing flake.nix in a way that affects the swift build (e.g. the sysroot),
force a reconfigure (the relevant flags are baked into build.ninja):
rm build/Ninja-RelWithDebInfoAssert+swift-DebugAssert/swift-linux-x86_64/CMakeCache.txtDisk: / holds /nix/store (and /tmp); the build dir goes on /home. The store
can fill during development. If you hit ENOSPC, run nix-collect-garbage -d. A full
RelWithDebInfo+debug build needs ~60–100 GB on the build filesystem.
RAM / "my terminal crashed after ~1h30": that's the OOM-killer, not a build bug. The
first hour compiles (cheap); then the link phase starts, and with --release-debuginfo
--debug-swifteach link pulls GBs of debug info into RAM. On a low-RAM laptop the default (one link per core) blows past memory and the kernel kills processes, sometimes the terminal/session too.dobuild.shalready sets-DLLVM_PARALLEL_LINK_JOBS=1to serialise links. If it still dies, add swap, which turns OOM-death into "slow but finishes":
# configuration.nix, then: sudo nixos-rebuild switch
zramSwap = { enable = true; memoryPercent = 75; };
swapDevices = [ { device = "/swapfile"; size = 16 * 1024; } ]; # 16 GiBRule of thumb: ~12 GB RAM needs LLVM_PARALLEL_LINK_JOBS=1 and swap; with ≥32 GB you
can raise it to 2–4 to link faster. Confirm a kill with
journalctl -k -b | grep -i 'oom\|killed process'.
Resuming after a crash: just re-run nix develop --command bash dobuild.sh foundation. The build is
incremental (ninja + --sccache), so it picks up from the killed step instead of starting
over. Don't delete build/. (Run it through nix develop so the toolchain env is set; a
bare sh dobuild.sh outside the dev shell won't work.)
Run these inside the dev shell (enter it first with nix develop .#full, or let the
.envrc from the intro activate it). Pasting nix develop together with the lines below
would not work: it starts a subshell and blocks, so the assignments would not run until you
exit it. With the dev shell already active, point $SWIFTC at the compiler you built:
B=build/Ninja-RelWithDebInfoAssert+swift-DebugAssert/swift-linux-x86_64
SWIFTC="$B/bin/swiftc"
export LD_LIBRARY_PATH="$B/lib/swift/linux"Plain Swift works directly; do not pass -sdk:
echo 'print("hello from a swiftc I built")' > hello.swift
"$SWIFTC" hello.swift -o hello && ./helloFor C++ interop, pass the gcc-toolchain and sysroot so the importer finds libstdc++:
mkdir -p cxxmod
printf '#pragma once\ninline int cxx_answer() { return 42; }\n' > cxxmod/shim.h
printf 'module CxxHello { header "shim.h" requires cplusplus }\n' > cxxmod/module.modulemap
printf $'import CxxHello\nprint(cxx_answer())\n' > main.swift
"$SWIFTC" -cxx-interoperability-mode=default \
-Xcc --gcc-toolchain="$SWIFT_GCC_TOOLCHAIN" -Xcc --sysroot="$SWIFT_GLIBC_SYSROOT" \
-I ./cxxmod main.swift -o demo && ./demo- A
warning: libc not found for 'x86_64-unknown-linux-gnu'at compile time is harmless. - Without the two
-Xccflags, C++ interop fails with "cannot load underlying module for 'CxxStdlib'": on NixOS the importer can't find libstdc++ on its own.
The build produces libFoundation.so + Foundation.swiftmodule, but a raw build dir is
not a consumable SDK. Install the corelibs once to assemble the proper module layout
(module maps for dispatch, _FoundationCShims, CoreFoundation, …):
SDK=$PWD/foundation-sdk
DESTDIR=$SDK ninja -C build/Ninja-RelWithDebInfoAssert+swift-DebugAssert/libdispatch-linux-x86_64 install
DESTDIR=$SDK ninja -C build/Ninja-RelWithDebInfoAssert+swift-DebugAssert/foundation-linux-x86_64 install
SDKLIB=$SDK/usr/lib/swift
export LD_LIBRARY_PATH="$B/lib/swift/linux"
echo 'import Foundation; print(UUID(), Date(timeIntervalSince1970: 0))' > hello.swift
"$SWIFTC" hello.swift -o hello \
-sdk "$SWIFT_CORELIBS_SDK" -L "$SWIFT_GCC_LIB" -Xlinker -rpath-link -Xlinker "$SWIFT_GCC_LIB" \
-L "$B/lib/swift/linux" -Xlinker -rpath-link -Xlinker "$B/lib/swift/linux" \
-I "$SDKLIB/linux" -I "$SDKLIB" -L "$SDKLIB/linux" \
-Xlinker -rpath -Xlinker "$B/lib/swift/linux" -Xlinker -rpath -Xlinker "$SDKLIB/linux"
./hello./hello prints something like 9A1CDB09-... 1970-01-01 00:00:00 +0000.
LD_LIBRARY_PATHfor the swiftc invocation must NOT include the new Foundation:swiftc(vialibllbuildSwift) links the bootstrap Foundation and the ABIs differ. Bake the new Foundation into the program's rpath instead, as above.
Both language servers work against this build: clangd for the C++ compiler sources, and
sourcekit-lsp for the Swift optimizer passes in SwiftCompilerSources/. Neither writes
inside the Swift tree: all they need is a gitignored compile_commands.json symlink at the
repo root, plus artifacts under build/. The commands and flags below are editor-agnostic;
plug them into whichever LSP client you use (nvim, VS Code, emacs, and so on).
The build already emits a compile_commands.json. Symlink it to the repo root so clangd finds
it. Use an absolute path, because the build dir sits one level up from swift/, not inside it:
ln -sfn "$PWD/build/Ninja-RelWithDebInfoAssert+swift-DebugAssert/swift-linux-x86_64/compile_commands.json" \
swift/compile_commands.jsonThe one NixOS gotcha: the database's compiler is the nix clang wrapper, which injects the
glibc, libstdc++ and gcc include paths at runtime via CCC_OVERRIDE_OPTIONS. clangd does not
replay that, so <utility> and stddef.h come up as "file not found". Launch clangd with
--query-driver so it interrogates the real build compiler and picks those paths up. Whatever
your editor's clangd integration, the launch arguments are:
clangd --query-driver=/nix/store/*/bin/*g++ --background-index
A .clangd with --gcc-install-dir= is not enough (it still misses the builtin stddef.h);
--query-driver is the correct fix. Sanity-check with clangd --check=<some .cpp>: 0 errors.
sourcekit-lsp for SwiftCompilerSources/ has to be built from the toolchain you built, not
a prebuilt one. Linux Swift has no stable stdlib ABI, so a sourcekit-lsp of any other version
crashes the moment it loads your 6.5-dev sourcekitd in-process (undefined symbol _swift_backtrace_isThunkFunction and friends). And SwiftCompilerSources specifically needs
your sourcekitd: it reads the compiler's own SIL/AST bridging .swiftmodules, built by your
exact commit, so no foreign toolchain can serve it.
The build-script route to sourcekit-lsp goes through swiftpm and the new Swift Build engine,
which is its own multi-layer fight on this custom toolchain. The shortcut that works: build
sourcekit-lsp directly with CMake, using the shim swiftc from .#full. Its CMakeLists.txt
marks swiftpm as optional and keeps the compile_commands.json build system, which is exactly
what SwiftCompilerSources needs. The pieces, all under build/:
- sourcekit-lsp, indexstore-db and swift-syntax, each built by their own CMake against the
shim toolchain (swift-syntax must be the 6.5 one; the compiler's host copy is bootstrap
5.10.1 and won't load). Pass
-D NO_SWIFTPM_DEPENDENCYso the swiftpm-only sources drop out. - A merged
compile_commands.json. The C++ database has no Swift entries, so generate them from the ninja whole-module commands (one entry per.swiftfile, reusing the module's real-I/-sdkargs) and merge with the C++ one. Theargv0of each Swift entry must be an absolute path to your toolchainswiftc: sourcekit-lsp resolves the per-file toolchain from it, and a bareswiftcgives "Failed to determine toolchain" and empty results. You need two gitignored symlinks to this merged file: one at the git repo root (clangd roots there, via.git), and one insideSwiftCompilerSources/, because that folder has aPackage.swiftso the Swift workspace roots there and looks for the database next to it, not at the repo root. Miss the second one and every Swift file falls back to "No such module 'SIL'" with no goto-definition. The entries are absolute paths, so the same merged file serves both roots. Each Swift entry must also carry-Xcc --gcc-toolchainand-Xcc --sysroot: the captured ninja args have no libc/libstdc++ include paths (the ninja build got them from the nix clang wrapper'sCCC_OVERRIDE_OPTIONS, which the plain toolchain swiftc the LSP drives does not replay), so without them the C++-interop bridging modules fail to build with'assert.h' file not foundand completion dies while the server retries in a loop.dobuild.sh lspgenerates this merged database (with those flags) and both symlinks in one step; re-run it after any build that regenerates the ninja compile database, or completion/goto-def silently break. - The two SourceKit plugins. Hover works through plain sourcekitd, but completion routes
through
libSwiftSourceKitClientPlugin.soandlibSwiftSourceKitPlugin.so. Build them and drop them into the toolchain'susr/lib/(whereToolchain.findDyliblooks, next tolibsourcekitdInProc.so). Without them completion returnsmissing key.offset, 0 items. - A launcher at
…/sourcekit-lsp-cmake-build/bin/sourcekit-lsp-nixos. Your editor starts the server from a plain shell, so the launcher pulls in the.#fullenvironment itself. It usesnix print-dev-env, notnix develop --command: the latter runs the flake shellHook, whose banner lands on stdout and corrupts the LSP JSON-RPC stream. It then exportsSOURCEKIT_TOOLCHAIN_PATH(so requests use yoursourcekitd) and forces--default-workspace-type compilationDatabase.
Point your editor's Swift language server at that launcher; its path is the command to run:
build/Ninja-RelWithDebInfoAssert+swift-DebugAssert/sourcekit-lsp-cmake-build/bin/sourcekit-lsp-nixos
Open a file under SwiftCompilerSources/, give the first module build ~25s, and hover plus
completion work.
Cross-file goto-definition, find-references, call hierarchy and workspace symbols need two more
pieces, because the compilation-database build server does not build an index itself, it only
reads a prebuilt one whose path it takes from an -index-store-path argument in the database:
- A prebuilt index store, compiled from the 6.5 modules. The build tree's
SwiftCompilerSources/*.swiftmoduleare the bootstrap 5.10.1 ones, which your 6.5-dev sourcekitd cannot load, soimport SILhalf-fails and cursor-info resolves nothing outside the open file (the file still shows zero diagnostics, which hides the cause). Rebuild the four modules (Basic,AST,SIL,Optimizer) with your 6.5 swiftc, both into a scratch module dir and with-index-store-path, then prepend-I <that scratch dir>to every Swift entry in the database so sourcekitd loads the matching 6.5 modules instead of the 5.10.1 tree ones. On NixOS the recompile needs-Xcc --gcc-toolchain(libstdc++) and-Xcc --sysroot(glibc headers, else'assert.h' file not found), which the captured ninja args do not carry. Index-while-building in whole-module mode needs one index-unit output per source file, so it runs multi-threaded WMO with an-output-file-map; a single-ogives "index output filenames do not match input source files". Finally append-index-store-path <store>to the database so the build server discovers it. - The
libIndexStorethe index reader dlopen's. sourcekit-lsp looks forlibIndexStore.sounder<toolchain>/lib/; it is built in the LLVM tree instead, so symlink it in. Without it the index never opens (noIndexDatabasedirectory appears) and only file-local goto-def works:B=build/Ninja-RelWithDebInfoAssert+swift-DebugAssert ln -sfn "$PWD/$B/llvm-linux-x86_64/lib/libIndexStore.so.21.0" \ "$B/toolchain-linux-x86_64/usr/lib/libIndexStore.so.21.0" ln -sfn libIndexStore.so.21.0 "$B/toolchain-linux-x86_64/usr/lib/libIndexStore.so"
With all of it in place, every LSP feature works on SwiftCompilerSources/: hover, completion,
goto-definition, type and implementation, find-references, document and workspace symbols,
document highlight, signature help, semantic tokens, call hierarchy, folding ranges, inlay hints,
and rename. The scratch module dir is now a dependency of the server, not throwaway; only
regenerate it when the SwiftCompilerSources sources change. The build steps above are captured
under build/Ninja-RelWithDebInfoAssert+swift-DebugAssert/lsp-scripts/; folding them into a
single dobuild.sh sourcekit-lsp sub-command is the next step.
Each lives in flake.nix with inline comments; the git history has one commit per fix.
#include_next <math.h>"file not found" building llbuild: havingglibc.devinbuildInputsfront-loaded glibc into the C++ include path; clang's dedup then dropped the cc-wrapper's correctly-placed copy, so libstdc++'s<cmath>couldn't reach glibc. Fix: don't addglibc.devas a buildInput; let the wrapper place it.- The just-built (unwrapped) clang that compiles the stdlib knows no NixOS paths.
Fixes via
LIBRARY_PATH(-lstdc++/-lgcc_s) andCCC_OVERRIDE_OPTIONS, which injects--gcc-install-dir(libstdc++ headers + libs + crt),-B <glibc>(glibc crt startup objects) and-idirafter <glibc>/include(glibc C headers, placed last so libstdc++'s#include_next <math.h>/<stdlib.h>resolves to them). Headers are not delivered viaCPLUS_INCLUDE_PATH, because that injects like-isystem, which-nostdinc++does not suppress, so it leaked gcc'sinclude/c++into compiler-rt's sanitizers and (under gcc 15) broke them with "redefinition of 'array'".--gcc-install-diris suppressed by-nostdinc++, so compiler-rt stays clean. -lcurses: nixpkgs has no barelibcurses.so; alibncurseswcompat shim. PlusCC/CXX=clang(so llbuild doesn't fall back to g++) and-Wno-unused-command-line-argument(libdispatch's C is built with-Werror).- Bootstrap runtime:
swiftPackages.Foundation/Dispatchfor llbuild, and a completebootstrapSwifttoolchain so the just-builtswift-frontendcan loadlibdispatch.soat runtime (nixpkgs uses non-transitiveDT_RUNPATH). - stdlib swiftc can't find libc /
SwiftGlibc: its clang-importer detects libc via the sysroot's system includes. Built a glibcswiftSysroot, passed as-sdk <sysroot>via the build-script CLI. - C++ interop (
CxxStdlib) has two coupled problems, both solved inflake.nix+dobuild.sh:- Link vs. compile conflict. The overlay's clang-module compile wants glibc's real
libc.solinker script inside the-sdksysroot, but the bare-clang C++ link then breaks becauseldsysroot-prefixes that script's absoluteGROUP()paths. Fix: keep the originallibc.soand add a symlink farm mirroring the glibc store dir under the sysroot at its own absolute path, so the prefixed path resolves, satisfying both. - libstdc++ delivery. Don't put gcc's c++ headers in the sysroot (that gives libstdc++
two file identities →
redefinition of 'piecewise_construct_t'). Instead deliver it via-Xcc --gcc-toolchain=<nix-gcc>on every stdlib swiftc, plus-no-verify-emitted-module-interface(the interface round-trip re-verify can't record an-Xccflag, so it would fail to find libstdc++).
- Link vs. compile conflict. The overlay's clang-module compile wants glibc's real
- Infra: a
.gitignoreso the Nix flake copies only the recipe files (not the 60 GB tree), plus disk GC. - Foundation under
--debug-swift: building Foundation from source revealed a five-layer problem, all fixed via--common-swift-flags+ an augmented sysroot built in the shellHook ($SWIFT_CORELIBS_SDK), see Building Foundation below.
import Foundation works (dobuild.sh passes --foundation=1 --libdispatch=1). Getting
there meant building Foundation from source with the just-built compiler. A 5.10.x
Foundation can't be grafted onto a 6.5-dev compiler (incompatible .swiftmodule ABI). That
build first appeared to hang for 30+ minutes in the FoundationMacros step. A gdb
backtrace (taking the frontend's stack from a worker thread) showed it was not the type
checker but the SIL verifier, while the compiler rebuilt swift-syntax from its
.swiftinterface. Root cause: the host swift-syntax modules were compiled by the
bootstrap Swift 5.10.1 (build-script's CMAKE_Swift_COMPILER), so the 6.5-dev compiler
can't load them and rebuilds from the interface. On NixOS that rebuild (and the resulting
corelibs links) break five different ways. The fix delivers four flags to the corelibs
only (via --common-swift-flags, never the compiler/stdlib), plus an augmented sysroot:
-sil-verify-none: skip the assert-only SIL verifier that grinds for minutes per swift-syntax module. (Do not add-disable-sil-ownership-verifier: it trips an assert inSemanticARCOptsunder-O.)-sdk $SWIFT_CORELIBS_SDK: the interface rebuild needs a sysroot to findSwiftGlibc(NixOS/usr/includeis empty; the importer ignoresC_INCLUDE_PATH/SDKROOT). Without it the rebuild retries forever, the real "hang".- augmented sysroot: a plain glibc
-sdkredirects swiftc's runtime lookup, so links can't findswiftrt.o.$SWIFT_CORELIBS_SDK(built in the shellHook) is glibc plus a symlink to the just-built Swift runtime, so one-sdkserves both the compile and the links. -L $SWIFT_GCC_LIB -Xlinker -rpath-link …: with-sdk,ldcan't findlibswiftCore.so's indirectlibstdc++.so.6NEEDED (an absolute/nix/storepath outside the sysroot). Pointldat the gcc lib.-L $SWIFT_RUNTIME_LIB -Xlinker -rpath-link …: likewise so the corelibs executable links (plutil, FoundationNetworking) resolvelibFoundation.so's indirectlibswiftSynchronization.soNEEDED.
The toggles are written --foundation=1 --libdispatch=1 (not bare) so build-script's
argparse doesn't swallow the space-containing --common-swift-flags value.
A future cleaner fix is to make the build compile swift-syntax with the just-built 6.5-dev
compiler, so its binary modules load directly and no .swiftinterface rebuild happens.
| Component | State |
|---|---|
| Swift compiler + core stdlib | ✅ builds, runs real programs |
C++ interop overlay (CxxStdlib) |
✅ builds, verified import CxxStdlib |
| libdispatch | ✅ builds |
| Foundation | ✅ builds, verified import Foundation (Date/JSON/UUID/NSString…) |
| Relocatable installed toolchain | ninja … install DESTDIR=… (see import Foundation) |
| C++ LSP (clangd) | ✅ hover/completion/diagnostics (see §4) |
| Swift LSP (sourcekit-lsp) | ✅ works on SwiftCompilerSources/, all features: hover/completion/goto-def/find-refs/call-hierarchy/rename; |
A clean single dobuild.sh run builds the compiler, the stdlib, the C++ interop overlay,
libdispatch and Foundation, exiting 0 (0 failures) in ~40 min on a warm cache.