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