Skip to content

Latest commit

 

History

89 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Swift from source on NixOS (compiler + C++ interop + Foundation + sourcekit-lsp)

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 swiftc on your PATH is 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 only swiftc that reports 6.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 .#full first, or add a .envrc containing use flake .#full so direnv activates it automatically when you cd into 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).

Where to go next

  • 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.

1. Get the Swift source

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 --clone

Run 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)

Keeping the workspace consistent on main

  • Re-run update-checkout after every git pull of swift/. It pins the sibling repos (llvm-project, swift-syntax, corelibs, …) to the revisions that match your swift/ 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 (old llvm-project) and ASTGen ... has no member 'macroExpansionDecl' (old swift-syntax). Resync the siblings without moving your swift/ feature branch:
    swift/utils/update-checkout --scheme main --skip-repository swift --reset-to-remote
    (--skip-repository swift keeps your branch; --match-timestamp alone is not enough, it can leave a sibling stale.) Then rebuild. LLVM is cached after the first pass.
  • The flake/dobuild.sh fixes are the part you maintain. The NixOS-specific fixes (the #include_next glibc ordering, the sysroot, the rpath/-rpath-link flags; see What was fixed below) are tuned against the pinned toolchain (gcc 15.2.0 / glibc 2.42). Building newer main source 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.


2. Build

From swift-workspace/:

nix develop --command bash dobuild.sh foundation

Pick the build that matches what you want to work on

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.sil

After 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.txt

Disk: / 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-swift each 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.sh already sets -DLLVM_PARALLEL_LINK_JOBS=1 to 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 GiB

Rule 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.)


3. Use the compiler you built

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 && ./hello

For 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 -Xcc flags, C++ interop fails with "cannot load underlying module for 'CxxStdlib'": on NixOS the importer can't find libstdc++ on its own.

import Foundation

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_PATH for the swiftc invocation must NOT include the new Foundation: swiftc (via libllbuildSwift) links the bootstrap Foundation and the ABIs differ. Bake the new Foundation into the program's rpath instead, as above.

4. Editor setup (LSP)

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).

C++ (clangd)

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.json

The 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.

Swift (sourcekit-lsp)

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_DEPENDENCY so 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 .swift file, reusing the module's real -I/-sdk args) and merge with the C++ one. The argv0 of each Swift entry must be an absolute path to your toolchain swiftc: sourcekit-lsp resolves the per-file toolchain from it, and a bare swiftc gives "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 inside SwiftCompilerSources/, because that folder has a Package.swift so 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-toolchain and -Xcc --sysroot: the captured ninja args have no libc/libstdc++ include paths (the ninja build got them from the nix clang wrapper's CCC_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 found and completion dies while the server retries in a loop. dobuild.sh lsp generates 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.so and libSwiftSourceKitPlugin.so. Build them and drop them into the toolchain's usr/lib/ (where Toolchain.findDylib looks, next to libsourcekitdInProc.so). Without them completion returns missing 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 .#full environment itself. It uses nix print-dev-env, not nix develop --command: the latter runs the flake shellHook, whose banner lands on stdout and corrupts the LSP JSON-RPC stream. It then exports SOURCEKIT_TOOLCHAIN_PATH (so requests use your sourcekitd) 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/*.swiftmodule are the bootstrap 5.10.1 ones, which your 6.5-dev sourcekitd cannot load, so import SIL half-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 -o gives "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 libIndexStore the index reader dlopen's. sourcekit-lsp looks for libIndexStore.so under <toolchain>/lib/; it is built in the LLVM tree instead, so symlink it in. Without it the index never opens (no IndexDatabase directory 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.


What was fixed (NixOS-specific)

Each lives in flake.nix with inline comments; the git history has one commit per fix.

  1. #include_next <math.h> "file not found" building llbuild: having glibc.dev in buildInputs front-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 add glibc.dev as a buildInput; let the wrapper place it.
  2. The just-built (unwrapped) clang that compiles the stdlib knows no NixOS paths. Fixes via LIBRARY_PATH (-lstdc++ / -lgcc_s) and CCC_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 via CPLUS_INCLUDE_PATH, because that injects like -isystem, which -nostdinc++ does not suppress, so it leaked gcc's include/c++ into compiler-rt's sanitizers and (under gcc 15) broke them with "redefinition of 'array'". --gcc-install-dir is suppressed by -nostdinc++, so compiler-rt stays clean.
  3. -lcurses: nixpkgs has no bare libcurses.so; a libncursesw compat shim. Plus CC/CXX=clang (so llbuild doesn't fall back to g++) and -Wno-unused-command-line-argument (libdispatch's C is built with -Werror).
  4. Bootstrap runtime: swiftPackages.Foundation/Dispatch for llbuild, and a complete bootstrapSwift toolchain so the just-built swift-frontend can load libdispatch.so at runtime (nixpkgs uses non-transitive DT_RUNPATH).
  5. stdlib swiftc can't find libc / SwiftGlibc: its clang-importer detects libc via the sysroot's system includes. Built a glibc swiftSysroot, passed as -sdk <sysroot> via the build-script CLI.
  6. C++ interop (CxxStdlib) has two coupled problems, both solved in flake.nix + dobuild.sh:
    • Link vs. compile conflict. The overlay's clang-module compile wants glibc's real libc.so linker script inside the -sdk sysroot, but the bare-clang C++ link then breaks because ld sysroot-prefixes that script's absolute GROUP() paths. Fix: keep the original libc.so and 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 -Xcc flag, so it would fail to find libstdc++).
  7. Infra: a .gitignore so the Nix flake copies only the recipe files (not the 60 GB tree), plus disk GC.
  8. 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.

Building Foundation (and how a gdb backtrace cracked the "hang")

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:

  1. -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 in SemanticARCOpts under -O.)
  2. -sdk $SWIFT_CORELIBS_SDK: the interface rebuild needs a sysroot to find SwiftGlibc (NixOS /usr/include is empty; the importer ignores C_INCLUDE_PATH/ SDKROOT). Without it the rebuild retries forever, the real "hang".
  3. augmented sysroot: a plain glibc -sdk redirects swiftc's runtime lookup, so links can't find swiftrt.o. $SWIFT_CORELIBS_SDK (built in the shellHook) is glibc plus a symlink to the just-built Swift runtime, so one -sdk serves both the compile and the links.
  4. -L $SWIFT_GCC_LIB -Xlinker -rpath-link …: with -sdk, ld can't find libswiftCore.so's indirect libstdc++.so.6 NEEDED (an absolute /nix/store path outside the sysroot). Point ld at the gcc lib.
  5. -L $SWIFT_RUNTIME_LIB -Xlinker -rpath-link …: likewise so the corelibs executable links (plutil, FoundationNetworking) resolve libFoundation.so's indirect libswiftSynchronization.so NEEDED.

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.


Status summary

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 ⚠️ assemble with 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; ⚠️ build not yet one command (see §4)

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.

About

Build the Swift toolchain from source on NixOS: compiler, stdlib, C++ interop and Foundation

Topics

Resources

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages