nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
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_14,
39 darwinMinVersionHook,
40}:
41
42let
43 apple-sdk_swift = apple-sdk_14; # 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 clangForWrappers = clang.override (prev: {
115 extraBuildCommands =
116 prev.extraBuildCommands
117 # We need to use the resource directory corresponding to Swift’s
118 # version of Clang instead of passing along the one from the
119 # `cc-wrapper` flags.
120 + ''
121 substituteInPlace $out/nix-support/cc-cflags \
122 --replace-fail " -resource-dir=$out/resource-root" ""
123 '';
124 });
125
126 # Build a tool used during the build to create a custom clang wrapper, with
127 # which we wrap the clang produced by the swift build.
128 #
129 # This is used in a `POST_BUILD` for the CMake target, so we rename the
130 # actual clang to clang-unwrapped, then put the wrapper in place.
131 #
132 # We replace the `exec ...` command with `exec -a "$0"` in order to
133 # preserve $0 for clang. This is because, unlike Nix, we don't have
134 # separate wrappers for clang/clang++, and clang uses $0 to detect C++.
135 #
136 # Similarly, the C++ detection in the wrapper itself also won't work for us,
137 # so we base it on $0 as well.
138 makeClangWrapper = writeShellScriptBin "nix-swift-make-clang-wrapper" ''
139 set -euo pipefail
140
141 targetFile="$1"
142 unwrappedClang="$targetFile-unwrapped"
143
144 mv "$targetFile" "$unwrappedClang"
145 sed < '${clangForWrappers}/bin/clang' > "$targetFile" \
146 -e 's|^\s*exec|exec -a "$0"|g' \
147 -e 's|^\[\[ "${clang.cc}/bin/clang" = \*++ ]]|[[ "$0" = *++ ]]|' \
148 -e "s|${clang.cc}/bin/clang|$unwrappedClang|g" \
149 -e "s|^\(\s*\)\($unwrappedClang\) \"@\\\$responseFile\"|\1argv0=\$0\n\1${bash}/bin/bash -c \"exec -a '\$argv0' \2 '@\$responseFile'\"|" \
150 ${lib.optionalString (clang.libcxx != null) ''
151 -e 's|$NIX_CXXSTDLIB_COMPILE_${clang.suffixSalt}|-isystem '$SWIFT_BUILD_ROOT'/libcxx/include/c++/v1|g'
152 ''}
153 chmod a+x "$targetFile"
154 '';
155
156 # Create a tool used during the build to create a custom swift wrapper for
157 # each of the swift executables produced by the build.
158 #
159 # The build produces several `swift-frontend` executables during
160 # bootstrapping. Each of these has numerous aliases via symlinks, and the
161 # executable uses $0 to detect what tool is called.
162 wrapperParams = {
163 inherit bintools;
164 coreutils_bin = lib.getBin coreutils;
165 gnugrep_bin = gnugrep;
166 suffixSalt = lib.replaceStrings [ "-" "." ] [ "_" "_" ] targetPlatform.config;
167 use_response_file_by_default = 1;
168 swiftDriver = "";
169 # NOTE: @cc_wrapper@ and @prog@ need to be filled elsewhere.
170 };
171 swiftWrapper = runCommand "swift-wrapper.sh" wrapperParams ''
172 # Make empty to avoid adding the SDK’s modules in the bootstrap wrapper. Otherwise, the SDK conflicts with the
173 # shims the wrapper tries to build.
174 darwinMinVersion="" substituteAll '${../wrapper/wrapper.sh}' "$out"
175 '';
176 makeSwiftcWrapper = writeShellScriptBin "nix-swift-make-swift-wrapper" ''
177 set -euo pipefail
178
179 targetFile="$1"
180 unwrappedSwift="$targetFile-unwrapped"
181
182 mv "$targetFile" "$unwrappedSwift"
183 sed < '${swiftWrapper}' > "$targetFile" \
184 -e "s|@prog@|'$unwrappedSwift'|g" \
185 -e 's|@cc_wrapper@|${clangForWrappers}|g' \
186 -e 's|exec "$prog"|exec -a "$0" "$prog"|g' \
187 ${lib.optionalString (clang.libcxx != null) ''
188 -e 's|$NIX_CXXSTDLIB_COMPILE_${clang.suffixSalt}|-isystem '$SWIFT_BUILD_ROOT'/libcxx/include/c++/v1|g'
189 ''}
190 chmod a+x "$targetFile"
191 '';
192
193 # On Darwin, we need to use BOOTSTRAPPING-WITH-HOSTLIBS because of ABI
194 # stability, and have to provide the definitions for the system stdlib.
195 appleSwiftCore = stdenv.mkDerivation {
196 name = "apple-swift-core";
197 dontUnpack = true;
198
199 buildInputs = [ apple-sdk_swift ];
200
201 installPhase = ''
202 mkdir -p $out/lib/swift
203 cp -r \
204 "$SDKROOT/usr/lib/swift/Swift.swiftmodule" \
205 "$SDKROOT/usr/lib/swift/CoreFoundation.swiftmodule" \
206 "$SDKROOT/usr/lib/swift/Dispatch.swiftmodule" \
207 "$SDKROOT/usr/lib/swift/ObjectiveC.swiftmodule" \
208 "$SDKROOT/usr/lib/swift/libswiftCore.tbd" \
209 "$SDKROOT/usr/lib/swift/libswiftCoreFoundation.tbd" \
210 "$SDKROOT/usr/lib/swift/libswiftDispatch.tbd" \
211 "$SDKROOT/usr/lib/swift/libswiftFoundation.tbd" \
212 "$SDKROOT/usr/lib/swift/libswiftObjectiveC.tbd" \
213 $out/lib/swift/
214 '';
215 };
216
217 # https://github.com/NixOS/nixpkgs/issues/327836
218 # Fail to build with ninja 1.12 when NIX_BUILD_CORES is low (Hydra or Github Actions).
219 # Can reproduce using `nix --option cores 2 build -f . swiftPackages.swift-unwrapped`.
220 # Until we find out the exact cause, follow [swift upstream][1], pin ninja to version
221 # 1.11.1.
222 # [1]: https://github.com/swiftlang/swift/pull/72989
223 ninja = ninja_1_11;
224
225in
226stdenv.mkDerivation {
227 pname = "swift";
228 inherit (sources) version;
229
230 outputs = [
231 "out"
232 "lib"
233 "dev"
234 "doc"
235 "man"
236 ];
237
238 nativeBuildInputs = [
239 cmake
240 git
241 ninja
242 perl # pod2man
243 pkg-config
244 python3
245 makeWrapper
246 makeClangWrapper
247 makeSwiftcWrapper
248 ]
249 ++ lib.optionals stdenv.hostPlatform.isDarwin [
250 xcbuild
251 sigtool # codesign
252 DarwinTools # sw_vers
253 fixDarwinDylibNames
254 cctools.libtool
255 ];
256
257 buildInputs = [
258 # For lldb
259 python3
260 swig
261 libxml2
262 ]
263 ++ lib.optionals stdenv.hostPlatform.isLinux [
264 libuuid
265 ]
266 ++ lib.optionals stdenv.hostPlatform.isDarwin [
267 apple-sdk_swift
268 ];
269
270 # Will effectively be `buildInputs` when swift is put in `nativeBuildInputs`.
271 depsTargetTargetPropagated = lib.optionals stdenv.targetPlatform.isDarwin [
272 apple-sdk_swift
273 ];
274
275 # This is a partial reimplementation of our setup hook. Because we reuse
276 # the Swift wrapper for the Swift build itself, we need to do some of the
277 # same preparation.
278 postHook = ''
279 for pkg in "''${pkgsHostTarget[@]}" '${clang.libc}'; do
280 for subdir in ${swiftModuleSubdir} ${swiftStaticModuleSubdir} lib/swift; do
281 if [[ -d "$pkg/$subdir" ]]; then
282 export NIX_SWIFTFLAGS_COMPILE+=" -I $pkg/$subdir"
283 fi
284 done
285 for subdir in ${swiftLibSubdir} ${swiftStaticLibSubdir} lib/swift; do
286 if [[ -d "$pkg/$subdir" ]]; then
287 export NIX_LDFLAGS+=" -L $pkg/$subdir"
288 fi
289 done
290 done
291 '';
292
293 # We setup custom build directories.
294 dontUseCmakeBuildDir = true;
295
296 unpackPhase =
297 let
298 copySource = repo: "cp -r ${sources.${repo}} ${repo}";
299 in
300 ''
301 mkdir src
302 cd src
303
304 ${copySource "swift-cmark"}
305 ${copySource "llvm-project"}
306 ${copySource "swift"}
307 ${copySource "swift-experimental-string-processing"}
308 ${copySource "swift-syntax"}
309 ${lib.optionalString (!stdenv.hostPlatform.isDarwin) (copySource "swift-corelibs-libdispatch")}
310
311 chmod -R u+w .
312 '';
313
314 patchPhase = ''
315 # Just patch all the things for now, we can focus this later.
316 # TODO: eliminate use of env.
317 find -type f -print0 | xargs -0 sed -i \
318 ${lib.optionalString stdenv.hostPlatform.isDarwin "-e 's|/usr/libexec/PlistBuddy|${xcbuild}/bin/PlistBuddy|g'"} \
319 -e 's|/usr/bin/env|${coreutils}/bin/env|g' \
320 -e 's|/usr/bin/make|${gnumake}/bin/make|g' \
321 -e 's|/bin/mkdir|${coreutils}/bin/mkdir|g' \
322 -e 's|/bin/cp|${coreutils}/bin/cp|g' \
323 -e 's|/usr/bin/file|${file}/bin/file|g'
324
325 patch -p1 -d swift -i ${./patches/swift-wrap.patch}
326 patch -p1 -d swift -i ${./patches/swift-linux-fix-libc-paths.patch}
327 patch -p1 -d swift -i ${
328 replaceVars ./patches/swift-linux-fix-linking.patch {
329 inherit clang;
330 }
331 }
332 patch -p1 -d swift -i ${
333 replaceVars ./patches/swift-darwin-plistbuddy-workaround.patch {
334 inherit swiftArch;
335 }
336 }
337 patch -p1 -d swift -i ${
338 replaceVars ./patches/swift-prevent-sdk-dirs-warning.patch {
339 inherit (builtins) storeDir;
340 }
341 }
342 patch -p1 -d swift -i ${./patches/swift-Frontend-Fix-a-small-unique_ptr-array-access.patch}
343
344 # This patch needs to know the lib output location, so must be substituted
345 # in the same derivation as the compiler.
346 storeDir="${builtins.storeDir}" \
347 substituteAll ${./patches/swift-separate-lib.patch} $TMPDIR/swift-separate-lib.patch
348 patch -p1 -d swift -i $TMPDIR/swift-separate-lib.patch
349
350 patch -p1 -d llvm-project/llvm -i ${./patches/llvm-module-cache.patch}
351
352 for lldbPatch in ${
353 lib.escapeShellArgs [
354 # Fix the build with modern libc++.
355 (fetchpatch {
356 name = "add-cstdio.patch";
357 url = "https://github.com/llvm/llvm-project/commit/73e15b5edb4fa4a77e68c299a6e3b21e610d351f.patch";
358 stripLen = 1;
359 hash = "sha256-eFcvxZaAuBsY/bda1h9212QevrXyvCHw8Cr9ngetDr0=";
360 })
361 (fetchpatch {
362 url = "https://github.com/llvm/llvm-project/commit/68744ffbdd7daac41da274eef9ac0d191e11c16d.patch";
363 stripLen = 1;
364 hash = "sha256-QCGhsL/mi7610ZNb5SqxjRGjwJeK2rwtsFVGeG3PUGc=";
365 })
366 ]
367 }; do
368 patch -p1 -d llvm-project/lldb -i $lldbPatch
369 done
370
371 patch -p1 -d llvm-project/clang -i ${./patches/clang-toolchain-dir.patch}
372 patch -p1 -d llvm-project/clang -i ${./patches/clang-wrap.patch}
373 patch -p1 -d llvm-project/clang -i ${./patches/clang-purity.patch}
374
375 patch -p1 -d llvm-project/cmake -i ${
376 fetchpatch2 {
377 name = "cmake-fix.patch";
378 url = "https://github.com/llvm/llvm-project/commit/3676a86a4322e8c2b9c541f057b5d3704146b8f3.patch?full_index=1";
379 stripLen = 1;
380 hash = "sha256-zP9dQOmWs7qrxkBRj70DyQBbRjH78B6tNJVy6ilA1xM=";
381 }
382 }
383
384 ${lib.optionalString stdenv.hostPlatform.isLinux ''
385 substituteInPlace llvm-project/clang/lib/Driver/ToolChains/Linux.cpp \
386 --replace-fail 'LibDir = "lib";' 'LibDir = "${glibc}/lib";' \
387 --replace-fail 'LibDir = "lib64";' 'LibDir = "${glibc}/lib";' \
388 --replace-fail '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 patch -p1 -d swift-corelibs-libdispatch -i ${
423 # Fix the build with modern Clang.
424 fetchpatch {
425 url = "https://github.com/swiftlang/swift-corelibs-libdispatch/commit/30bb8019ba79cdae0eb1dc0c967c17996dd5cc0a.patch";
426 hash = "sha256-wPZQ4wtEWk8HaKMfzjamlU6p/IW5EFiTssY63rGM+ZA=";
427 }
428 }
429 patch -p1 -d swift-corelibs-libdispatch -i ${
430 # Fix the build with modern Clang.
431 fetchpatch {
432 url = "https://github.com/swiftlang/swift-corelibs-libdispatch/commit/38872e2d44d66d2fb94186988509defc734888a5.patch";
433 hash = "sha256-GABwDeTjciV36Sa0FS10mCfFCqRoBBstgW/OiKdPahA=";
434 }
435 }
436 ''}
437 '';
438
439 # > clang-15-unwrapped: error: unsupported option '-fzero-call-used-regs=used-gpr' for target 'arm64-apple-macosx10.9.0'
440 # > clang-15-unwrapped: error: argument unused during compilation: '-fstack-clash-protection' [-Werror,-Wunused-command-line-argument]
441 hardeningDisable = lib.optionals stdenv.hostPlatform.isAarch64 [
442 "zerocallusedregs"
443 "stackclashprotection"
444 ];
445
446 configurePhase = ''
447 export SWIFT_SOURCE_ROOT="$PWD"
448 mkdir -p ../build
449 cd ../build
450 export SWIFT_BUILD_ROOT="$PWD"
451 '';
452
453 # These steps are derived from doing a normal build with.
454 #
455 # ./swift/utils/build-toolchain test --dry-run
456 #
457 # But dealing with the custom Python build system is far more trouble than
458 # simply invoking CMake directly. Few variables it passes to CMake are
459 # actually required or non-default.
460 #
461 # Using CMake directly also allows us to split up the already large build,
462 # and package Swift components separately.
463 #
464 # Besides `--dry-run`, another good way to compare build changes between
465 # Swift releases is to diff the scripts:
466 #
467 # git diff swift-5.6.3-RELEASE..swift-5.7-RELEASE -- utils/build*
468 #
469 buildPhase = ''
470 # Helper to build a subdirectory.
471 #
472 # Always reset cmakeFlags before calling this. The cmakeConfigurePhase
473 # amends flags and would otherwise keep expanding it.
474 function buildProject() {
475 mkdir -p $SWIFT_BUILD_ROOT/$1
476 cd $SWIFT_BUILD_ROOT/$1
477
478 cmakeDir=$SWIFT_SOURCE_ROOT/''${2-$1}
479 cmakeConfigurePhase
480
481 ninjaBuildPhase
482 }
483
484 cmakeFlags="-GNinja"
485 buildProject swift-cmark
486
487 ${lib.optionalString (clang.libcxx != null) ''
488 # Install the libc++ headers corresponding to the LLVM version of
489 # Swift’s Clang.
490 cmakeFlags="
491 -GNinja
492 -DLLVM_ENABLE_RUNTIMES=libcxx;libcxxabi
493 -DLIBCXXABI_INSTALL_INCLUDE_DIR=$dev/include/c++/v1
494 "
495 ninjaFlags="install-cxx-headers install-cxxabi-headers"
496 buildProject libcxx llvm-project/runtimes
497 unset ninjaFlags
498 ''}
499
500 # Some notes:
501 # - The Swift build just needs Clang.
502 # - We can further reduce targets to just our targetPlatform.
503 cmakeFlags="
504 -GNinja
505 -DLLVM_BUILD_TOOLS=NO
506 -DLLVM_ENABLE_PROJECTS=clang
507 -DLLVM_TARGETS_TO_BUILD=${
508 {
509 "x86_64" = "X86";
510 "aarch64" = "AArch64";
511 }
512 .${targetPlatform.parsed.cpu.name}
513 or (throw "Unsupported CPU architecture: ${targetPlatform.parsed.cpu.name}")
514 }
515 "
516 buildProject llvm llvm-project/llvm
517
518 # Ensure that the built Clang can find the runtime libraries by
519 # copying the symlinks from the main wrapper.
520 cp -P ${clang}/resource-root/{lib,share} $SWIFT_BUILD_ROOT/llvm/lib/clang/16.0.0/
521
522 ''
523 + lib.optionalString stdenv.hostPlatform.isDarwin ''
524 # Add appleSwiftCore to the search paths. Adding the whole SDK results in build failures.
525 OLD_NIX_SWIFTFLAGS_COMPILE="$NIX_SWIFTFLAGS_COMPILE"
526 OLD_NIX_LDFLAGS="$NIX_LDFLAGS"
527 OLD_NIX_CFLAGS_COMPILE="$NIX_CFLAGS_COMPILE"
528 export NIX_SWIFTFLAGS_COMPILE=" -I ${appleSwiftCore}/lib/swift"
529 export NIX_LDFLAGS+=" -L ${appleSwiftCore}/lib/swift"
530 export NIX_CFLAGS_COMPILE+=" -Wno-error=unguarded-availability"
531 ''
532 + ''
533
534 # Some notes:
535 # - BOOTSTRAPPING_MODE defaults to OFF in CMake, but is enabled in standard
536 # builds, so we enable it as well. On Darwin, we have to use the system
537 # Swift libs because of ABI-stability, but this may be trouble if the
538 # builder is an older macOS.
539 # - Experimental features are OFF by default in CMake, but are enabled in
540 # official builds, so we do the same. (Concurrency is also required in
541 # the stdlib. StringProcessing is often implicitely imported, causing
542 # lots of warnings if missing.)
543 # - SWIFT_STDLIB_ENABLE_OBJC_INTEROP is set explicitely because its check
544 # is buggy. (Uses SWIFT_HOST_VARIANT_SDK before initialized.)
545 # Fixed in: https://github.com/apple/swift/commit/84083afef1de5931904d5c815d53856cdb3fb232
546 cmakeFlags="
547 -GNinja
548 -DBOOTSTRAPPING_MODE=BOOTSTRAPPING${lib.optionalString stdenv.hostPlatform.isDarwin "-WITH-HOSTLIBS"}
549 -DSWIFT_ENABLE_EXPERIMENTAL_DIFFERENTIABLE_PROGRAMMING=ON
550 -DSWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY=ON
551 -DSWIFT_ENABLE_EXPERIMENTAL_CXX_INTEROP=ON
552 -DSWIFT_ENABLE_EXPERIMENTAL_DISTRIBUTED=ON
553 -DSWIFT_ENABLE_EXPERIMENTAL_STRING_PROCESSING=ON
554 -DSWIFT_ENABLE_BACKTRACING=ON
555 -DSWIFT_ENABLE_EXPERIMENTAL_OBSERVATION=ON
556 -DLLVM_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/llvm
557 -DClang_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/clang
558 -DSWIFT_PATH_TO_CMARK_SOURCE=$SWIFT_SOURCE_ROOT/swift-cmark
559 -DSWIFT_PATH_TO_CMARK_BUILD=$SWIFT_BUILD_ROOT/swift-cmark
560 -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE=$SWIFT_SOURCE_ROOT/swift-corelibs-libdispatch
561 -DSWIFT_PATH_TO_SWIFT_SYNTAX_SOURCE=$SWIFT_SOURCE_ROOT/swift-syntax
562 -DSWIFT_PATH_TO_STRING_PROCESSING_SOURCE=$SWIFT_SOURCE_ROOT/swift-experimental-string-processing
563 -DSWIFT_INSTALL_COMPONENTS=${lib.concatStringsSep ";" swiftInstallComponents}
564 -DSWIFT_STDLIB_ENABLE_OBJC_INTEROP=${if stdenv.hostPlatform.isDarwin then "ON" else "OFF"}
565 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_OSX=${deploymentVersion}
566 "
567 buildProject swift
568
569 ''
570 + lib.optionalString stdenv.hostPlatform.isDarwin ''
571 # Restore search paths to remove appleSwiftCore.
572 export NIX_SWIFTFLAGS_COMPILE="$OLD_NIX_SWIFTFLAGS_COMPILE"
573 export NIX_LDFLAGS="$OLD_NIX_LDFLAGS"
574 export NIX_CFLAGS_COMPILE="$OLD_NIX_CFLAGS_COMPILE"
575 ''
576 + ''
577
578 # These are based on flags in `utils/build-script-impl`.
579 #
580 # LLDB_USE_SYSTEM_DEBUGSERVER=ON disables the debugserver build on Darwin,
581 # which requires a special signature.
582 #
583 # CMAKE_BUILD_WITH_INSTALL_NAME_DIR ensures we don't use rpath on Darwin.
584 cmakeFlags="
585 -GNinja
586 -DLLDB_SWIFTC=$SWIFT_BUILD_ROOT/swift/bin/swiftc
587 -DLLDB_SWIFT_LIBS=$SWIFT_BUILD_ROOT/swift/lib/swift
588 -DLLVM_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/llvm
589 -DClang_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/clang
590 -DSwift_DIR=$SWIFT_BUILD_ROOT/swift/lib/cmake/swift
591 -DLLDB_ENABLE_CURSES=ON
592 -DLLDB_ENABLE_LIBEDIT=ON
593 -DLLDB_ENABLE_PYTHON=ON
594 -DLLDB_ENABLE_LZMA=OFF
595 -DLLDB_ENABLE_LUA=OFF
596 -DLLDB_INCLUDE_TESTS=OFF
597 -DCMAKE_BUILD_WITH_INSTALL_NAME_DIR=ON
598 ${lib.optionalString stdenv.hostPlatform.isDarwin ''
599 -DLLDB_USE_SYSTEM_DEBUGSERVER=ON
600 ''}
601 -DLibEdit_INCLUDE_DIRS=${lib.getInclude libedit}/include
602 -DLibEdit_LIBRARIES=${lib.getLib libedit}/lib/libedit${stdenv.hostPlatform.extensions.sharedLibrary}
603 -DCURSES_INCLUDE_DIRS=${lib.getInclude ncurses}/include
604 -DCURSES_LIBRARIES=${lib.getLib ncurses}/lib/libncurses${stdenv.hostPlatform.extensions.sharedLibrary}
605 -DPANEL_LIBRARIES=${lib.getLib ncurses}/lib/libpanel${stdenv.hostPlatform.extensions.sharedLibrary}
606 ";
607 buildProject lldb llvm-project/lldb
608
609 ${lib.optionalString stdenv.targetPlatform.isDarwin ''
610 # Need to do a standalone build of concurrency for Darwin back deployment.
611 # Based on: utils/swift_build_support/swift_build_support/products/backdeployconcurrency.py
612 cmakeFlags="
613 -GNinja
614 -DCMAKE_Swift_COMPILER=$SWIFT_BUILD_ROOT/swift/bin/swiftc
615 -DSWIFT_PATH_TO_SWIFT_SYNTAX_SOURCE=$SWIFT_SOURCE_ROOT/swift-syntax
616
617 -DTOOLCHAIN_DIR=/var/empty
618 -DSWIFT_NATIVE_LLVM_TOOLS_PATH=${stdenv.cc}/bin
619 -DSWIFT_NATIVE_CLANG_TOOLS_PATH=${stdenv.cc}/bin
620 -DSWIFT_NATIVE_SWIFT_TOOLS_PATH=$SWIFT_BUILD_ROOT/swift/bin
621
622 -DCMAKE_CROSSCOMPILING=ON
623
624 -DBUILD_SWIFT_CONCURRENCY_BACK_DEPLOYMENT_LIBRARIES=ON
625 -DSWIFT_INCLUDE_TOOLS=OFF
626 -DSWIFT_BUILD_STDLIB_EXTRA_TOOLCHAIN_CONTENT=OFF
627 -DSWIFT_BUILD_TEST_SUPPORT_MODULES=OFF
628 -DSWIFT_BUILD_STDLIB=OFF
629 -DSWIFT_BUILD_DYNAMIC_STDLIB=OFF
630 -DSWIFT_BUILD_STATIC_STDLIB=OFF
631 -DSWIFT_BUILD_REMOTE_MIRROR=OFF
632 -DSWIFT_BUILD_SDK_OVERLAY=OFF
633 -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY=OFF
634 -DSWIFT_BUILD_STATIC_SDK_OVERLAY=OFF
635 -DSWIFT_INCLUDE_TESTS=OFF
636 -DSWIFT_BUILD_PERF_TESTSUITE=OFF
637
638 -DSWIFT_HOST_VARIANT_ARCH=${swiftArch}
639 -DBUILD_STANDALONE=ON
640
641 -DSWIFT_INSTALL_COMPONENTS=back-deployment
642
643 -DSWIFT_SDKS=${
644 {
645 "macos" = "OSX";
646 "ios" = "IOS";
647 #IOS_SIMULATOR
648 #TVOS
649 #TVOS_SIMULATOR
650 #WATCHOS
651 #WATCHOS_SIMULATOR
652 }
653 .${targetPlatform.darwinPlatform}
654 }
655
656 -DLLVM_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/llvm
657
658 -DSWIFT_DEST_ROOT=$out
659 -DSWIFT_HOST_VARIANT_SDK=OSX
660
661 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_OSX=${deploymentVersion}
662 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_IOS=13.0
663 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_MACCATALYST=13.0
664 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_TVOS=13.0
665 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_WATCHOS=6.0
666 "
667
668 # This depends on the special Clang build specific to the Swift branch.
669 # We also need to call a specific Ninja target.
670 export CC=$SWIFT_BUILD_ROOT/llvm/bin/clang
671 export CXX=$SWIFT_BUILD_ROOT/llvm/bin/clang++
672 ninjaFlags="back-deployment"
673
674 buildProject swift-concurrency-backdeploy swift
675
676 export CC=$NIX_CC/bin/clang
677 export CXX=$NIX_CC/bin/clang++
678 unset ninjaFlags
679 ''}
680 '';
681
682 # TODO: ~50 failing tests on x86_64-linux. Other platforms not checked.
683 doCheck = false;
684 nativeCheckInputs = [ file ];
685 # TODO: consider using stress-tester and integration-test.
686 checkPhase = ''
687 cd $SWIFT_BUILD_ROOT/swift
688 checkTarget=check-swift-all
689 ninjaCheckPhase
690 unset checkTarget
691 '';
692
693 installPhase = ''
694 # Undo the clang and swift wrapping we did for the build.
695 # (This happened via patches to cmake files.)
696 cd $SWIFT_BUILD_ROOT
697 mv llvm/bin/clang-16{-unwrapped,}
698 mv swift/bin/swift-frontend{-unwrapped,}
699
700 mkdir $lib
701
702 # Install clang binaries only. We hide these with the wrapper, so they are
703 # for private use by Swift only.
704 cd $SWIFT_BUILD_ROOT/llvm
705 installTargets=install-clang
706 ninjaInstallPhase
707 unset installTargets
708
709 # LLDB is also a private install.
710 cd $SWIFT_BUILD_ROOT/lldb
711 ninjaInstallPhase
712
713 cd $SWIFT_BUILD_ROOT/swift
714 ninjaInstallPhase
715
716 ${lib.optionalString stdenv.hostPlatform.isDarwin ''
717 cd $SWIFT_BUILD_ROOT/swift-concurrency-backdeploy
718 installTargets=install-back-deployment
719 ninjaInstallPhase
720 unset installTargets
721 ''}
722
723 # Separate $lib output here, because specific logic follows.
724 # Only move the dynamic run-time parts, to keep $lib small. Every Swift
725 # build will depend on it.
726 moveToOutput "lib/swift" "$lib"
727 moveToOutput "lib/libswiftDemangle.*" "$lib"
728
729 # This link is here because various tools (swiftpm) check for stdlib
730 # relative to the swift compiler. It's fine if this is for build-time
731 # stuff, but we should patch all cases were it would end up in an output.
732 ln -s $lib/lib/swift $out/lib/swift
733
734 # Swift has a separate resource root from Clang, but locates the Clang
735 # resource root via subdir or symlink.
736 mv $SWIFT_BUILD_ROOT/llvm/lib/clang/16.0.0 $lib/lib/swift/clang
737 '';
738
739 preFixup = lib.optionalString stdenv.hostPlatform.isLinux ''
740 # This is cheesy, but helps the patchelf hook remove /build from RPATH.
741 cd $SWIFT_BUILD_ROOT/..
742 mv build buildx
743 '';
744
745 postFixup = lib.optionalString stdenv.hostPlatform.isDarwin ''
746 # These libraries need to use the system install name. The official SDK
747 # does the same (as opposed to using rpath). Presumably, they are part of
748 # the stable ABI. Not using the system libraries at run-time is known to
749 # cause ObjC class conflicts and segfaults.
750 declare -A systemLibs=(
751 [libswiftCore.dylib]=1
752 [libswiftDarwin.dylib]=1
753 [libswiftSwiftOnoneSupport.dylib]=1
754 [libswift_Concurrency.dylib]=1
755 )
756
757 for systemLib in "''${!systemLibs[@]}"; do
758 install_name_tool -id /usr/lib/swift/$systemLib $lib/${swiftLibSubdir}/$systemLib
759 done
760
761 for file in $out/bin/swift-frontend $lib/${swiftLibSubdir}/*.dylib; do
762 changeArgs=""
763 for dylib in $(otool -L $file | awk '{ print $1 }'); do
764 if [[ ''${systemLibs["$(basename $dylib)"]} ]]; then
765 changeArgs+=" -change $dylib /usr/lib/swift/$(basename $dylib)"
766 elif [[ "$dylib" = */bootstrapping1/* ]]; then
767 changeArgs+=" -change $dylib $lib/lib/swift/$(basename $dylib)"
768 fi
769 done
770 if [[ -n "$changeArgs" ]]; then
771 install_name_tool $changeArgs $file
772 fi
773 done
774
775 wrapProgram $out/bin/swift-frontend \
776 --prefix PATH : ${lib.makeBinPath [ cctools.libtool ]}
777
778 # Needs to be propagated by the compiler not by its dev output.
779 moveToOutput nix-support/propagated-target-target-deps "$out"
780 '';
781
782 passthru = {
783 inherit
784 swiftOs
785 swiftArch
786 swiftModuleSubdir
787 swiftLibSubdir
788 swiftStaticModuleSubdir
789 swiftStaticLibSubdir
790 ;
791
792 tests = {
793 cxx-interop-test = callPackage ../cxx-interop-test { };
794 };
795
796 # Internal attr for the wrapper.
797 _wrapperParams = wrapperParams;
798 };
799
800 meta = {
801 description = "Swift Programming Language";
802 homepage = "https://github.com/apple/swift";
803 teams = [ lib.teams.swift ];
804 license = lib.licenses.asl20;
805 platforms = with lib.platforms; linux ++ darwin;
806 # Swift doesn't support 32-bit Linux, unknown on other platforms.
807 badPlatforms = lib.platforms.i686;
808 timeout = 86400; # 24 hours.
809 };
810}