swiftPackages_ng.swift: init

The Swift compiler expects to find the stdlib, its modules, etc relative
to its location. Building everything together in one derivation would be
a terrible idea because it would take a very long time to build and
require rebuilding things unnecessarily during the bootstrap.
Fortunately, we can symlink most of what Swift expects together.

Collectively, the contents of this package is called a toolchain. One
should think of it as similar to the toolchains offered on swift.org
except that it’s bootstrapped from source and is part of Nixpkgs.
This commit is contained in:
Randy Eckenrode
2026-08-06 19:56:05 -04:00
parent 0dfc837eb4
commit cbda3182f1

View File

@@ -0,0 +1,133 @@
{
lib,
apple-sdk_14,
llvmPackages_upstream,
stdenv,
swift-corelibs-libdispatch,
swiftc,
symlinkJoin,
swift_release,
}:
let
propagated-sdk = apple-sdk_14;
# `out` and `dev` are merged because thats what Swift expects.
outLinks = symlinkJoin {
name = "swift" + lib.removePrefix "swiftc" (lib.getName swiftc) + "-${swift_release}-out";
paths = [
swiftc.out
swiftc.dev
]
++ lib.optionals (!stdenv.hostPlatform.isDarwin) (
lib.optionals (swift-corelibs-libdispatch != null) [
swift-corelibs-libdispatch.out
swift-corelibs-libdispatch.dev
]
);
};
docLinks = symlinkJoin {
name = "swift" + lib.removePrefix "swiftc" (lib.getName swiftc) + "-${swift_release}-doc";
paths = [
swiftc.doc
];
};
manLinks = symlinkJoin {
name = "swift" + lib.removePrefix "swiftc" (lib.getName swiftc) + "-${swift_release}-man";
paths = [
swiftc.man
]
++ lib.optionals (!stdenv.hostPlatform.isDarwin && swift-corelibs-libdispatch != null) [
swift-corelibs-libdispatch.man
];
};
in
stdenv.mkDerivation (finalAttrs: {
pname = "swift" + lib.removePrefix "swiftc" (lib.getName swiftc);
version = swift_release;
outputs = [
"out"
"doc"
"man"
];
strictDeps = true;
# Will effectively be `buildInputs` when swift is put in `nativeBuildInputs`.
depsTargetTargetPropagated =
lib.optionals stdenv.targetPlatform.isDarwin [ propagated-sdk ]
++ lib.optionals (!stdenv.hostPlatform.isDarwin) (
lib.optionals (swift-corelibs-libdispatch != null) [
swift-corelibs-libdispatch.out
]
);
buildCommand = ''
mkdir -p "$out" "$doc" "$man"
cp -r ${lib.escapeShellArg outLinks}/* "$out"
cp -r ${lib.escapeShellArg docLinks}/* "$doc"
cp -r ${lib.escapeShellArg manLinks}/* "$man"
# Make writable temporarily to allow for the fixups below to be made to the outputs.
chmod -R u+w "$out/bin" "$out/lib" "$out/nix-support"
# Swift expects to find Clang next to it.
ln -s ${lib.escapeShellArg (lib.getExe' llvmPackages_upstream.clang "clang")} "$out/bin/clang"
ln -s ${lib.escapeShellArg (lib.getExe' llvmPackages_upstream.clang "clang++")} "$out/bin/clang++"
# Swift has a separate resource root from Clang, but locates the Clang resource root via subdir or symlink.
#
# NOTE: We dont symlink directly here, because thatd add a run-time dep on the full Clang compiler to every
# Swift executable. We instead symlink compiler-rt and copy the headers from Clang to keep the closure size down.
mkdir -p "$out/lib/swift/clang"
ln -s ${lib.escapeShellArg (lib.getBin llvmPackages.compiler-rt)}/{lib,share} "$out/lib/swift/clang/"
cp -rH ${lib.escapeShellArg (lib.getBin llvmPackages.clang)}/resource-root/include/ "$out/lib/swift/clang/"
# `swift-frontend` expects to find everything relative to its location after resolving symlinks.
# Also copy `swift-driver` assuming it does similar.
for exe in swift-driver swift-frontend; do
if [ -e "$out/bin/$exe" ]; then
orig=$(readlink "$out/bin/$exe")
rm "$out/bin/$exe"
cp "$orig" "$out/bin/$exe"
fi
done
# Propagated inputs in `$dev/nix-support` have to be substituted to use this derivation instead of swiftc.
for f in "$out/nix-support/"*; do
orig=$(readlink "$f")
rm "$f"
substitute "$orig" "$f" \
--replace-quiet ${lib.escapeShellArg swiftc.out} "$out"
done
# Dont propagate CMake files for toolchain dependencies. These are an implementation detail of the package set.
rm -rf "$out/lib/cmake"
recordPropagatedDependencies
chmod -R u-w "$out/bin" "$out/lib" "$out/nix-support"
# Have to invoke manually because of `buildCommand`.
noBrokenSymlinksInAllOutputs
'';
__structuredAttrs = true;
passthru = {
inherit swiftc;
};
meta = {
mainProgram = "swift";
description = "Swift Programming Language";
homepage = "https://github.com/swiftlang/swift";
inherit (swiftc.meta) platforms badPlatforms;
license = lib.licenses.asl20;
teams = [ lib.teams.swift ];
};
})