1{
2 lib,
3 stdenv,
4 callPackage,
5 cmake,
6 bash,
7 coreutils,
8 gnugrep,
9 perl,
10 ninja_1_11,
11 pkg-config,
12 clang,
13 bintools,
14 python312Packages,
15 git,
16 fetchpatch,
17 fetchpatch2,
18 makeWrapper,
19 gnumake,
20 file,
21 runCommand,
22 writeShellScriptBin,
23 # For lldb
24 libedit,
25 ncurses,
26 swig,
27 libxml2,
28 # Linux-specific
29 glibc,
30 libuuid,
31 # Darwin-specific
32 replaceVars,
33 fixDarwinDylibNames,
34 xcbuild,
35 cctools, # libtool
36 sigtool,
37 DarwinTools,
38 apple-sdk_13,
39 darwinMinVersionHook,
40}:
41
42let
43 apple-sdk_swift = apple-sdk_13; # Use the SDK that was available when Swift shipped.
44
45 deploymentVersion =
46 if lib.versionOlder (targetPlatform.darwinMinVersion or "0") "10.15" then
47 "10.15"
48 else
49 targetPlatform.darwinMinVersion;
50
51 # Use Python 3.12 for now because Swift 5.8 depends on Python's PyEval_ThreadsInitialized(), which was removed in 3.13.
52 python3 = python312Packages.python.withPackages (p: [ p.setuptools ]); # python 3.12 compat.
53
54 inherit (stdenv) hostPlatform targetPlatform;
55
56 sources = callPackage ../sources.nix { };
57
58 # There are apparently multiple naming conventions on Darwin. Swift uses the
59 # xcrun naming convention. See `configure_sdk_darwin` calls in CMake files.
60 swiftOs =
61 if targetPlatform.isDarwin then
62 {
63 "macos" = "macosx";
64 "ios" = "iphoneos";
65 #iphonesimulator
66 #appletvos
67 #appletvsimulator
68 #watchos
69 #watchsimulator
70 }
71 .${targetPlatform.darwinPlatform}
72 or (throw "Cannot build Swift for target Darwin platform '${targetPlatform.darwinPlatform}'")
73 else
74 targetPlatform.parsed.kernel.name;
75
76 # This causes swiftPackages.XCTest to fail to build on aarch64-linux
77 # as I believe this is because Apple calls the architecture aarch64
78 # on Linux rather than arm64 when used with macOS.
79 swiftArch =
80 if hostPlatform.isDarwin then hostPlatform.darwinArch else targetPlatform.parsed.cpu.name;
81
82 # On Darwin, a `.swiftmodule` is a subdirectory in `lib/swift/<OS>`,
83 # containing binaries for supported archs. On other platforms, binaries are
84 # installed to `lib/swift/<OS>/<ARCH>`. Note that our setup-hook also adds
85 # `lib/swift` for convenience.
86 swiftLibSubdir = "lib/swift/${swiftOs}";
87 swiftModuleSubdir =
88 if hostPlatform.isDarwin then "lib/swift/${swiftOs}" else "lib/swift/${swiftOs}/${swiftArch}";
89
90 # And then there's also a separate subtree for statically linked modules.
91 toStaticSubdir = lib.replaceStrings [ "/swift/" ] [ "/swift_static/" ];
92 swiftStaticLibSubdir = toStaticSubdir swiftLibSubdir;
93 swiftStaticModuleSubdir = toStaticSubdir swiftModuleSubdir;
94
95 # This matches _SWIFT_DEFAULT_COMPONENTS, with specific components disabled.
96 swiftInstallComponents = [
97 "autolink-driver"
98 "compiler"
99 # "clang-builtin-headers"
100 "stdlib"
101 "sdk-overlay"
102 "static-mirror-lib"
103 "editor-integration"
104 # "tools"
105 # "testsuite-tools"
106 "toolchain-tools"
107 "toolchain-dev-tools"
108 "license"
109 (if stdenv.hostPlatform.isDarwin then "sourcekit-xpc-service" else "sourcekit-inproc")
110 "swift-remote-mirror"
111 "swift-remote-mirror-headers"
112 ];
113
114 # Build a tool used during the build to create a custom clang wrapper, with
115 # which we wrap the clang produced by the swift build.
116 #
117 # This is used in a `POST_BUILD` for the CMake target, so we rename the
118 # actual clang to clang-unwrapped, then put the wrapper in place.
119 #
120 # We replace the `exec ...` command with `exec -a "$0"` in order to
121 # preserve $0 for clang. This is because, unlike Nix, we don't have
122 # separate wrappers for clang/clang++, and clang uses $0 to detect C++.
123 #
124 # Similarly, the C++ detection in the wrapper itself also won't work for us,
125 # so we base it on $0 as well.
126 makeClangWrapper = writeShellScriptBin "nix-swift-make-clang-wrapper" ''
127 set -euo pipefail
128
129 targetFile="$1"
130 unwrappedClang="$targetFile-unwrapped"
131
132 mv "$targetFile" "$unwrappedClang"
133 sed < '${clang}/bin/clang' > "$targetFile" \
134 -e 's|^\s*exec|exec -a "$0"|g' \
135 -e 's|^\[\[ "${clang.cc}/bin/clang" = \*++ ]]|[[ "$0" = *++ ]]|' \
136 -e "s|${clang.cc}/bin/clang|$unwrappedClang|g" \
137 -e "s|^\(\s*\)\($unwrappedClang\) \"@\\\$responseFile\"|\1argv0=\$0\n\1${bash}/bin/bash -c \"exec -a '\$argv0' \2 '@\$responseFile'\"|"
138 chmod a+x "$targetFile"
139 '';
140
141 # Create a tool used during the build to create a custom swift wrapper for
142 # each of the swift executables produced by the build.
143 #
144 # The build produces several `swift-frontend` executables during
145 # bootstrapping. Each of these has numerous aliases via symlinks, and the
146 # executable uses $0 to detect what tool is called.
147 wrapperParams = {
148 inherit bintools;
149 default_cc_wrapper = clang; # Instead of `@out@` in the original.
150 coreutils_bin = lib.getBin coreutils;
151 gnugrep_bin = gnugrep;
152 suffixSalt = lib.replaceStrings [ "-" "." ] [ "_" "_" ] targetPlatform.config;
153 use_response_file_by_default = 1;
154 swiftDriver = "";
155 # NOTE: @prog@ needs to be filled elsewhere.
156 };
157 swiftWrapper = runCommand "swift-wrapper.sh" wrapperParams ''
158 # Make empty to avoid adding the SDK’s modules in the bootstrap wrapper. Otherwise, the SDK conflicts with the
159 # shims the wrapper tries to build.
160 darwinMinVersion="" substituteAll '${../wrapper/wrapper.sh}' "$out"
161 '';
162 makeSwiftcWrapper = writeShellScriptBin "nix-swift-make-swift-wrapper" ''
163 set -euo pipefail
164
165 targetFile="$1"
166 unwrappedSwift="$targetFile-unwrapped"
167
168 mv "$targetFile" "$unwrappedSwift"
169 sed < '${swiftWrapper}' > "$targetFile" \
170 -e "s|@prog@|'$unwrappedSwift'|g" \
171 -e 's|exec "$prog"|exec -a "$0" "$prog"|g'
172 chmod a+x "$targetFile"
173 '';
174
175 # On Darwin, we need to use BOOTSTRAPPING-WITH-HOSTLIBS because of ABI
176 # stability, and have to provide the definitions for the system stdlib.
177 appleSwiftCore = stdenv.mkDerivation {
178 name = "apple-swift-core";
179 dontUnpack = true;
180
181 buildInputs = [ apple-sdk_swift ];
182
183 installPhase = ''
184 mkdir -p $out/lib/swift
185 cp -r \
186 "$SDKROOT/usr/lib/swift/Swift.swiftmodule" \
187 "$SDKROOT/usr/lib/swift/CoreFoundation.swiftmodule" \
188 "$SDKROOT/usr/lib/swift/Dispatch.swiftmodule" \
189 "$SDKROOT/usr/lib/swift/ObjectiveC.swiftmodule" \
190 "$SDKROOT/usr/lib/swift/libswiftCore.tbd" \
191 "$SDKROOT/usr/lib/swift/libswiftCoreFoundation.tbd" \
192 "$SDKROOT/usr/lib/swift/libswiftDispatch.tbd" \
193 "$SDKROOT/usr/lib/swift/libswiftFoundation.tbd" \
194 "$SDKROOT/usr/lib/swift/libswiftObjectiveC.tbd" \
195 $out/lib/swift/
196 '';
197 };
198
199 # https://github.com/NixOS/nixpkgs/issues/327836
200 # Fail to build with ninja 1.12 when NIX_BUILD_CORES is low (Hydra or Github Actions).
201 # Can reproduce using `nix --option cores 2 build -f . swiftPackages.swift-unwrapped`.
202 # Until we find out the exact cause, follow [swift upstream][1], pin ninja to version
203 # 1.11.1.
204 # [1]: https://github.com/swiftlang/swift/pull/72989
205 ninja = ninja_1_11;
206
207in
208stdenv.mkDerivation {
209 pname = "swift";
210 inherit (sources) version;
211
212 outputs = [
213 "out"
214 "lib"
215 "dev"
216 "doc"
217 "man"
218 ];
219
220 nativeBuildInputs = [
221 cmake
222 git
223 ninja
224 perl # pod2man
225 pkg-config
226 python3
227 makeWrapper
228 makeClangWrapper
229 makeSwiftcWrapper
230 ]
231 ++ lib.optionals stdenv.hostPlatform.isDarwin [
232 xcbuild
233 sigtool # codesign
234 DarwinTools # sw_vers
235 fixDarwinDylibNames
236 cctools.libtool
237 ];
238
239 buildInputs = [
240 # For lldb
241 python3
242 swig
243 libxml2
244 ]
245 ++ lib.optionals stdenv.hostPlatform.isLinux [
246 libuuid
247 ]
248 ++ lib.optionals stdenv.hostPlatform.isDarwin [
249 apple-sdk_swift
250 ];
251
252 # Will effectively be `buildInputs` when swift is put in `nativeBuildInputs`.
253 depsTargetTargetPropagated = lib.optionals stdenv.targetPlatform.isDarwin [
254 apple-sdk_swift
255 ];
256
257 # This is a partial reimplementation of our setup hook. Because we reuse
258 # the Swift wrapper for the Swift build itself, we need to do some of the
259 # same preparation.
260 postHook = ''
261 for pkg in "''${pkgsHostTarget[@]}" '${clang.libc}'; do
262 for subdir in ${swiftModuleSubdir} ${swiftStaticModuleSubdir} lib/swift; do
263 if [[ -d "$pkg/$subdir" ]]; then
264 export NIX_SWIFTFLAGS_COMPILE+=" -I $pkg/$subdir"
265 fi
266 done
267 for subdir in ${swiftLibSubdir} ${swiftStaticLibSubdir} lib/swift; do
268 if [[ -d "$pkg/$subdir" ]]; then
269 export NIX_LDFLAGS+=" -L $pkg/$subdir"
270 fi
271 done
272 done
273 '';
274
275 # We invoke cmakeConfigurePhase multiple times, but only need this once.
276 dontFixCmake = true;
277 # We setup custom build directories.
278 dontUseCmakeBuildDir = true;
279
280 unpackPhase =
281 let
282 copySource = repo: "cp -r ${sources.${repo}} ${repo}";
283 in
284 ''
285 mkdir src
286 cd src
287
288 ${copySource "swift-cmark"}
289 ${copySource "llvm-project"}
290 ${copySource "swift"}
291 ${copySource "swift-experimental-string-processing"}
292 ${copySource "swift-syntax"}
293 ${lib.optionalString (!stdenv.hostPlatform.isDarwin) (copySource "swift-corelibs-libdispatch")}
294
295 chmod -R u+w .
296 '';
297
298 patchPhase = ''
299 # Just patch all the things for now, we can focus this later.
300 # TODO: eliminate use of env.
301 find -type f -print0 | xargs -0 sed -i \
302 ${lib.optionalString stdenv.hostPlatform.isDarwin "-e 's|/usr/libexec/PlistBuddy|${xcbuild}/bin/PlistBuddy|g'"} \
303 -e 's|/usr/bin/env|${coreutils}/bin/env|g' \
304 -e 's|/usr/bin/make|${gnumake}/bin/make|g' \
305 -e 's|/bin/mkdir|${coreutils}/bin/mkdir|g' \
306 -e 's|/bin/cp|${coreutils}/bin/cp|g' \
307 -e 's|/usr/bin/file|${file}/bin/file|g'
308
309 patch -p1 -d swift -i ${./patches/swift-cmake-3.25-compat.patch}
310 patch -p1 -d swift -i ${./patches/swift-wrap.patch}
311 patch -p1 -d swift -i ${./patches/swift-nix-resource-root.patch}
312 patch -p1 -d swift -i ${./patches/swift-linux-fix-libc-paths.patch}
313 patch -p1 -d swift -i ${./patches/swift-linux-fix-linking.patch}
314 patch -p1 -d swift -i ${./patches/swift-darwin-libcxx-flags.patch}
315 patch -p1 -d swift -i ${
316 replaceVars ./patches/swift-darwin-plistbuddy-workaround.patch {
317 inherit swiftArch;
318 }
319 }
320 patch -p1 -d swift -i ${
321 replaceVars ./patches/swift-prevent-sdk-dirs-warning.patch {
322 inherit (builtins) storeDir;
323 }
324 }
325
326 # This patch needs to know the lib output location, so must be substituted
327 # in the same derivation as the compiler.
328 storeDir="${builtins.storeDir}" \
329 substituteAll ${./patches/swift-separate-lib.patch} $TMPDIR/swift-separate-lib.patch
330 patch -p1 -d swift -i $TMPDIR/swift-separate-lib.patch
331
332 patch -p1 -d llvm-project/llvm -i ${./patches/llvm-module-cache.patch}
333
334 for lldbPatch in ${
335 lib.escapeShellArgs [
336 # Fixes for SWIG 4
337 (fetchpatch2 {
338 url = "https://github.com/llvm/llvm-project/commit/81fc5f7909a4ef5a8d4b5da2a10f77f7cb01ba63.patch?full_index=1";
339 stripLen = 1;
340 hash = "sha256-Znw+C0uEw7lGETQLKPBZV/Ymo2UigZS+Hv/j1mUo7p0=";
341 })
342 (fetchpatch2 {
343 url = "https://github.com/llvm/llvm-project/commit/f0a25fe0b746f56295d5c02116ba28d2f965c175.patch?full_index=1";
344 stripLen = 1;
345 hash = "sha256-QzVeZzmc99xIMiO7n//b+RNAvmxghISKQD93U2zOgFI=";
346 })
347 (fetchpatch2 {
348 url = "https://github.com/llvm/llvm-project/commit/ba35c27ec9aa9807f5b4be2a0c33ca9b045accc7.patch?full_index=1";
349 stripLen = 1;
350 hash = "sha256-LXl+WbpmWZww5xMDrle3BM2Tw56v8k9LO1f1Z1/wDTs=";
351 })
352 (fetchpatch2 {
353 url = "https://github.com/llvm/llvm-project/commit/9ec115978ea2bdfc60800cd3c21264341cdc8b0a.patch?full_index=1";
354 stripLen = 1;
355 hash = "sha256-u0zSejEjfrH3ZoMFm1j+NVv2t5AP9cE5yhsrdTS1dG4=";
356 })
357 ]
358 }; do
359 patch -p1 -d llvm-project/lldb -i $lldbPatch
360 done
361
362 patch -p1 -d llvm-project/clang -i ${./patches/clang-toolchain-dir.patch}
363 patch -p1 -d llvm-project/clang -i ${./patches/clang-wrap.patch}
364 patch -p1 -d llvm-project/clang -i ${../../llvm/12/clang/purity.patch}
365 patch -p2 -d llvm-project/clang -i ${
366 fetchpatch {
367 name = "clang-cmake-fix-interpreter.patch";
368 url = "https://github.com/llvm/llvm-project/commit/b5eaf500f2441eff2277ea2973878fb1f171fd0a.patch";
369 sha256 = "1rma1al0rbm3s3ql6bnvbcighp74lri1lcrwbyacgdqp80fgw1b6";
370 }
371 }
372
373 # gcc-13 build fixes
374 patch -p2 -d llvm-project/llvm -i ${
375 fetchpatch {
376 name = "gcc-13.patch";
377 url = "https://github.com/llvm/llvm-project/commit/ff1681ddb303223973653f7f5f3f3435b48a1983.patch";
378 hash = "sha256-nkRPWx8gNvYr7mlvEUiOAb1rTrf+skCZjAydJVUHrcI=";
379 }
380 }
381
382 ${lib.optionalString stdenv.hostPlatform.isLinux ''
383 substituteInPlace llvm-project/clang/lib/Driver/ToolChains/Linux.cpp \
384 --replace 'SysRoot + "/lib' '"${glibc}/lib" "' \
385 --replace 'SysRoot + "/usr/lib' '"${glibc}/lib" "' \
386 --replace 'LibDir = "lib";' 'LibDir = "${glibc}/lib";' \
387 --replace 'LibDir = "lib64";' 'LibDir = "${glibc}/lib";' \
388 --replace 'LibDir = X32 ? "libx32" : "lib64";' 'LibDir = "${glibc}/lib";'
389
390 # uuid.h is not part of glibc, but of libuuid.
391 sed -i 's|''${GLIBC_INCLUDE_PATH}/uuid/uuid.h|${libuuid.dev}/include/uuid/uuid.h|' \
392 swift/stdlib/public/Platform/glibc.modulemap.gyb
393 ''}
394
395 # Remove tests for cross compilation, which we don't currently support.
396 rm swift/test/Interop/Cxx/class/constructors-copy-irgen-*.swift
397 rm swift/test/Interop/Cxx/class/constructors-irgen-*.swift
398
399 # TODO: consider fixing and re-adding. This test fails due to a non-standard "install_prefix".
400 rm swift/validation-test/Python/build_swift.swift
401
402 # We cannot handle the SDK location being in "Weird Location" due to Nix isolation.
403 rm swift/test/DebugInfo/compiler-flags.swift
404
405 # TODO: Fix issue with ld.gold invoked from script finding crtbeginS.o and crtendS.o.
406 rm swift/test/IRGen/ELF-remove-autolink-section.swift
407
408 # The following two tests fail because we use don't use the bundled libicu:
409 # [SOURCE_DIR/utils/build-script] ERROR: can't find source directory for libicu (tried /build/src/icu)
410 rm swift/validation-test/BuildSystem/default_build_still_performs_epilogue_opts_after_split.test
411 rm swift/validation-test/BuildSystem/test_early_swift_driver_and_infer.swift
412
413 # TODO: This test fails for some unknown reason
414 rm swift/test/Serialization/restrict-swiftmodule-to-revision.swift
415
416 # This test was flaky in ofborg, see #186476
417 rm swift/test/AutoDiff/compiler_crashers_fixed/issue-56649-missing-debug-scopes-in-pullback-trampoline.swift
418
419 patchShebangs .
420
421 ${lib.optionalString (!stdenv.hostPlatform.isDarwin) ''
422 # NOTE: This interferes with ABI stability on Darwin, which uses the system
423 # libraries in the hardcoded path /usr/lib/swift.
424 fixCmakeFiles .
425 ''}
426 '';
427
428 # > clang-15-unwrapped: error: unsupported option '-fzero-call-used-regs=used-gpr' for target 'arm64-apple-macosx10.9.0'
429 hardeningDisable = lib.optional stdenv.hostPlatform.isAarch64 "zerocallusedregs";
430
431 configurePhase = ''
432 export SWIFT_SOURCE_ROOT="$PWD"
433 mkdir -p ../build
434 cd ../build
435 export SWIFT_BUILD_ROOT="$PWD"
436 '';
437
438 # These steps are derived from doing a normal build with.
439 #
440 # ./swift/utils/build-toolchain test --dry-run
441 #
442 # But dealing with the custom Python build system is far more trouble than
443 # simply invoking CMake directly. Few variables it passes to CMake are
444 # actually required or non-default.
445 #
446 # Using CMake directly also allows us to split up the already large build,
447 # and package Swift components separately.
448 #
449 # Besides `--dry-run`, another good way to compare build changes between
450 # Swift releases is to diff the scripts:
451 #
452 # git diff swift-5.6.3-RELEASE..swift-5.7-RELEASE -- utils/build*
453 #
454 buildPhase = ''
455 # Helper to build a subdirectory.
456 #
457 # Always reset cmakeFlags before calling this. The cmakeConfigurePhase
458 # amends flags and would otherwise keep expanding it.
459 function buildProject() {
460 mkdir -p $SWIFT_BUILD_ROOT/$1
461 cd $SWIFT_BUILD_ROOT/$1
462
463 cmakeDir=$SWIFT_SOURCE_ROOT/''${2-$1}
464 cmakeConfigurePhase
465
466 ninjaBuildPhase
467 }
468
469 cmakeFlags="-GNinja"
470 buildProject swift-cmark
471
472 # Some notes:
473 # - The Swift build just needs Clang.
474 # - We can further reduce targets to just our targetPlatform.
475 cmakeFlags="
476 -GNinja
477 -DLLVM_ENABLE_PROJECTS=clang
478 -DLLVM_TARGETS_TO_BUILD=${
479 {
480 "x86_64" = "X86";
481 "aarch64" = "AArch64";
482 }
483 .${targetPlatform.parsed.cpu.name}
484 or (throw "Unsupported CPU architecture: ${targetPlatform.parsed.cpu.name}")
485 }
486 "
487 buildProject llvm llvm-project/llvm
488
489 ''
490 + lib.optionalString stdenv.hostPlatform.isDarwin ''
491 # Add appleSwiftCore to the search paths. Adding the whole SDK results in build failures.
492 OLD_NIX_SWIFTFLAGS_COMPILE="$NIX_SWIFTFLAGS_COMPILE"
493 OLD_NIX_LDFLAGS="$NIX_LDFLAGS"
494 export NIX_SWIFTFLAGS_COMPILE=" -I ${appleSwiftCore}/lib/swift"
495 export NIX_LDFLAGS+=" -L ${appleSwiftCore}/lib/swift"
496 ''
497 + ''
498
499 # Some notes:
500 # - BOOTSTRAPPING_MODE defaults to OFF in CMake, but is enabled in standard
501 # builds, so we enable it as well. On Darwin, we have to use the system
502 # Swift libs because of ABI-stability, but this may be trouble if the
503 # builder is an older macOS.
504 # - Experimental features are OFF by default in CMake, but are enabled in
505 # official builds, so we do the same. (Concurrency is also required in
506 # the stdlib. StringProcessing is often implicitely imported, causing
507 # lots of warnings if missing.)
508 # - SWIFT_STDLIB_ENABLE_OBJC_INTEROP is set explicitely because its check
509 # is buggy. (Uses SWIFT_HOST_VARIANT_SDK before initialized.)
510 # Fixed in: https://github.com/apple/swift/commit/84083afef1de5931904d5c815d53856cdb3fb232
511 cmakeFlags="
512 -GNinja
513 -DBOOTSTRAPPING_MODE=BOOTSTRAPPING${lib.optionalString stdenv.hostPlatform.isDarwin "-WITH-HOSTLIBS"}
514 -DSWIFT_ENABLE_EXPERIMENTAL_DIFFERENTIABLE_PROGRAMMING=ON
515 -DSWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY=ON
516 -DSWIFT_ENABLE_EXPERIMENTAL_DISTRIBUTED=ON
517 -DSWIFT_ENABLE_EXPERIMENTAL_STRING_PROCESSING=ON
518 -DLLVM_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/llvm
519 -DClang_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/clang
520 -DSWIFT_PATH_TO_CMARK_SOURCE=$SWIFT_SOURCE_ROOT/swift-cmark
521 -DSWIFT_PATH_TO_CMARK_BUILD=$SWIFT_BUILD_ROOT/swift-cmark
522 -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE=$SWIFT_SOURCE_ROOT/swift-corelibs-libdispatch
523 -DSWIFT_PATH_TO_SWIFT_SYNTAX_SOURCE=$SWIFT_SOURCE_ROOT/swift-syntax
524 -DSWIFT_PATH_TO_STRING_PROCESSING_SOURCE=$SWIFT_SOURCE_ROOT/swift-experimental-string-processing
525 -DSWIFT_INSTALL_COMPONENTS=${lib.concatStringsSep ";" swiftInstallComponents}
526 -DSWIFT_STDLIB_ENABLE_OBJC_INTEROP=${if stdenv.hostPlatform.isDarwin then "ON" else "OFF"}
527 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_OSX=${deploymentVersion}
528 "
529 buildProject swift
530
531 ''
532 + lib.optionalString stdenv.hostPlatform.isDarwin ''
533 # Restore search paths to remove appleSwiftCore.
534 export NIX_SWIFTFLAGS_COMPILE="$OLD_NIX_SWIFTFLAGS_COMPILE"
535 export NIX_LDFLAGS="$OLD_NIX_LDFLAGS"
536 ''
537 + ''
538
539 # These are based on flags in `utils/build-script-impl`.
540 #
541 # LLDB_USE_SYSTEM_DEBUGSERVER=ON disables the debugserver build on Darwin,
542 # which requires a special signature.
543 #
544 # CMAKE_BUILD_WITH_INSTALL_NAME_DIR ensures we don't use rpath on Darwin.
545 cmakeFlags="
546 -GNinja
547 -DLLDB_SWIFTC=$SWIFT_BUILD_ROOT/swift/bin/swiftc
548 -DLLDB_SWIFT_LIBS=$SWIFT_BUILD_ROOT/swift/lib/swift
549 -DLLVM_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/llvm
550 -DClang_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/clang
551 -DSwift_DIR=$SWIFT_BUILD_ROOT/swift/lib/cmake/swift
552 -DLLDB_ENABLE_CURSES=ON
553 -DLLDB_ENABLE_LIBEDIT=ON
554 -DLLDB_ENABLE_PYTHON=ON
555 -DLLDB_ENABLE_LZMA=OFF
556 -DLLDB_ENABLE_LUA=OFF
557 -DLLDB_INCLUDE_TESTS=OFF
558 -DCMAKE_BUILD_WITH_INSTALL_NAME_DIR=ON
559 ${lib.optionalString stdenv.hostPlatform.isDarwin ''
560 -DLLDB_USE_SYSTEM_DEBUGSERVER=ON
561 ''}
562 -DLibEdit_INCLUDE_DIRS=${lib.getInclude libedit}/include
563 -DLibEdit_LIBRARIES=${lib.getLib libedit}/lib/libedit${stdenv.hostPlatform.extensions.sharedLibrary}
564 -DCURSES_INCLUDE_DIRS=${lib.getInclude ncurses}/include
565 -DCURSES_LIBRARIES=${lib.getLib ncurses}/lib/libncurses${stdenv.hostPlatform.extensions.sharedLibrary}
566 -DPANEL_LIBRARIES=${lib.getLib ncurses}/lib/libpanel${stdenv.hostPlatform.extensions.sharedLibrary}
567 ";
568 buildProject lldb llvm-project/lldb
569
570 ${lib.optionalString stdenv.targetPlatform.isDarwin ''
571 # Need to do a standalone build of concurrency for Darwin back deployment.
572 # Based on: utils/swift_build_support/swift_build_support/products/backdeployconcurrency.py
573 cmakeFlags="
574 -GNinja
575 -DCMAKE_Swift_COMPILER=$SWIFT_BUILD_ROOT/swift/bin/swiftc
576 -DSWIFT_PATH_TO_SWIFT_SYNTAX_SOURCE=$SWIFT_SOURCE_ROOT/swift-syntax
577
578 -DTOOLCHAIN_DIR=/var/empty
579 -DSWIFT_NATIVE_LLVM_TOOLS_PATH=${stdenv.cc}/bin
580 -DSWIFT_NATIVE_CLANG_TOOLS_PATH=${stdenv.cc}/bin
581 -DSWIFT_NATIVE_SWIFT_TOOLS_PATH=$SWIFT_BUILD_ROOT/swift/bin
582
583 -DCMAKE_CROSSCOMPILING=ON
584
585 -DBUILD_SWIFT_CONCURRENCY_BACK_DEPLOYMENT_LIBRARIES=ON
586 -DSWIFT_INCLUDE_TOOLS=OFF
587 -DSWIFT_BUILD_STDLIB_EXTRA_TOOLCHAIN_CONTENT=OFF
588 -DSWIFT_BUILD_TEST_SUPPORT_MODULES=OFF
589 -DSWIFT_BUILD_STDLIB=OFF
590 -DSWIFT_BUILD_DYNAMIC_STDLIB=OFF
591 -DSWIFT_BUILD_STATIC_STDLIB=OFF
592 -DSWIFT_BUILD_REMOTE_MIRROR=OFF
593 -DSWIFT_BUILD_SDK_OVERLAY=OFF
594 -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY=OFF
595 -DSWIFT_BUILD_STATIC_SDK_OVERLAY=OFF
596 -DSWIFT_INCLUDE_TESTS=OFF
597 -DSWIFT_BUILD_PERF_TESTSUITE=OFF
598
599 -DSWIFT_HOST_VARIANT_ARCH=${swiftArch}
600 -DBUILD_STANDALONE=ON
601
602 -DSWIFT_INSTALL_COMPONENTS=back-deployment
603
604 -DSWIFT_SDKS=${
605 {
606 "macos" = "OSX";
607 "ios" = "IOS";
608 #IOS_SIMULATOR
609 #TVOS
610 #TVOS_SIMULATOR
611 #WATCHOS
612 #WATCHOS_SIMULATOR
613 }
614 .${targetPlatform.darwinPlatform}
615 }
616
617 -DLLVM_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/llvm
618
619 -DSWIFT_DEST_ROOT=$out
620 -DSWIFT_HOST_VARIANT_SDK=OSX
621
622 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_OSX=${deploymentVersion}
623 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_IOS=13.0
624 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_MACCATALYST=13.0
625 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_TVOS=13.0
626 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_WATCHOS=6.0
627 "
628
629 # This depends on the special Clang build specific to the Swift branch.
630 # We also need to call a specific Ninja target.
631 export CC=$SWIFT_BUILD_ROOT/llvm/bin/clang
632 export CXX=$SWIFT_BUILD_ROOT/llvm/bin/clang++
633 ninjaFlags="back-deployment"
634
635 buildProject swift-concurrency-backdeploy swift
636
637 export CC=$NIX_CC/bin/clang
638 export CXX=$NIX_CC/bin/clang++
639 unset ninjaFlags
640 ''}
641 '';
642
643 # TODO: ~50 failing tests on x86_64-linux. Other platforms not checked.
644 doCheck = false;
645 nativeCheckInputs = [ file ];
646 # TODO: consider using stress-tester and integration-test.
647 checkPhase = ''
648 cd $SWIFT_BUILD_ROOT/swift
649 checkTarget=check-swift-all
650 ninjaCheckPhase
651 unset checkTarget
652 '';
653
654 installPhase = ''
655 # Undo the clang and swift wrapping we did for the build.
656 # (This happened via patches to cmake files.)
657 cd $SWIFT_BUILD_ROOT
658 mv llvm/bin/clang-15{-unwrapped,}
659 mv swift/bin/swift-frontend{-unwrapped,}
660
661 mkdir $out $lib
662
663 # Install clang binaries only. We hide these with the wrapper, so they are
664 # for private use by Swift only.
665 cd $SWIFT_BUILD_ROOT/llvm
666 installTargets=install-clang
667 ninjaInstallPhase
668 unset installTargets
669
670 # LLDB is also a private install.
671 cd $SWIFT_BUILD_ROOT/lldb
672 ninjaInstallPhase
673
674 cd $SWIFT_BUILD_ROOT/swift
675 ninjaInstallPhase
676
677 ${lib.optionalString stdenv.hostPlatform.isDarwin ''
678 cd $SWIFT_BUILD_ROOT/swift-concurrency-backdeploy
679 installTargets=install-back-deployment
680 ninjaInstallPhase
681 unset installTargets
682 ''}
683
684 # Separate $lib output here, because specific logic follows.
685 # Only move the dynamic run-time parts, to keep $lib small. Every Swift
686 # build will depend on it.
687 moveToOutput "lib/swift" "$lib"
688 moveToOutput "lib/libswiftDemangle.*" "$lib"
689
690 # This link is here because various tools (swiftpm) check for stdlib
691 # relative to the swift compiler. It's fine if this is for build-time
692 # stuff, but we should patch all cases were it would end up in an output.
693 ln -s $lib/lib/swift $out/lib/swift
694
695 # Swift has a separate resource root from Clang, but locates the Clang
696 # resource root via subdir or symlink. Provide a default here, but we also
697 # patch Swift to prefer NIX_CC if set.
698 #
699 # NOTE: We don't symlink directly here, because that'd add a run-time dep
700 # on the full Clang compiler to every Swift executable. The copy here is
701 # just copying the 3 symlinks inside to smaller closures.
702 mkdir $lib/lib/swift/clang
703 cp -P ${clang}/resource-root/* $lib/lib/swift/clang/
704 '';
705
706 preFixup = lib.optionalString stdenv.hostPlatform.isLinux ''
707 # This is cheesy, but helps the patchelf hook remove /build from RPATH.
708 cd $SWIFT_BUILD_ROOT/..
709 mv build buildx
710 '';
711
712 postFixup = lib.optionalString stdenv.hostPlatform.isDarwin ''
713 # These libraries need to use the system install name. The official SDK
714 # does the same (as opposed to using rpath). Presumably, they are part of
715 # the stable ABI. Not using the system libraries at run-time is known to
716 # cause ObjC class conflicts and segfaults.
717 declare -A systemLibs=(
718 [libswiftCore.dylib]=1
719 [libswiftDarwin.dylib]=1
720 [libswiftSwiftOnoneSupport.dylib]=1
721 [libswift_Concurrency.dylib]=1
722 )
723
724 for systemLib in "''${!systemLibs[@]}"; do
725 install_name_tool -id /usr/lib/swift/$systemLib $lib/${swiftLibSubdir}/$systemLib
726 done
727
728 for file in $out/bin/swift-frontend $lib/${swiftLibSubdir}/*.dylib; do
729 changeArgs=""
730 for dylib in $(otool -L $file | awk '{ print $1 }'); do
731 if [[ ''${systemLibs["$(basename $dylib)"]} ]]; then
732 changeArgs+=" -change $dylib /usr/lib/swift/$(basename $dylib)"
733 elif [[ "$dylib" = */bootstrapping1/* ]]; then
734 changeArgs+=" -change $dylib $lib/lib/swift/$(basename $dylib)"
735 fi
736 done
737 if [[ -n "$changeArgs" ]]; then
738 install_name_tool $changeArgs $file
739 fi
740 done
741
742 wrapProgram $out/bin/swift-frontend \
743 --prefix PATH : ${lib.makeBinPath [ cctools.libtool ]}
744
745 # Needs to be propagated by the compiler not by its dev output.
746 moveToOutput nix-support/propagated-target-target-deps "$out"
747 '';
748
749 passthru = {
750 inherit
751 swiftOs
752 swiftArch
753 swiftModuleSubdir
754 swiftLibSubdir
755 swiftStaticModuleSubdir
756 swiftStaticLibSubdir
757 ;
758
759 # Internal attr for the wrapper.
760 _wrapperParams = wrapperParams;
761 };
762
763 meta = {
764 description = "Swift Programming Language";
765 homepage = "https://github.com/apple/swift";
766 teams = [ lib.teams.swift ];
767 license = lib.licenses.asl20;
768 platforms = with lib.platforms; linux ++ darwin;
769 # Swift doesn't support 32-bit Linux, unknown on other platforms.
770 badPlatforms = lib.platforms.i686;
771 timeout = 86400; # 24 hours.
772 };
773}