{ lib , stdenv , callPackage , cmake , bash , coreutils , gnugrep , perl , ninja , pkg-config , clang , bintools , python3 , git , fetchpatch , makeWrapper , gnumake , file , runCommand , writeShellScriptBin # For lldb , libedit , ncurses , swig , libxml2 # Linux-specific , glibc , libuuid # Darwin-specific , substituteAll , fixDarwinDylibNames , runCommandLocal , xcbuild , cctools # libtool , sigtool , DarwinTools , CoreServices , Foundation , Combine , MacOSX-SDK , CLTools_Executables }: let inherit (stdenv) hostPlatform targetPlatform; sources = callPackage ../sources.nix { }; # Tools invoked by swift at run-time. runtimeDeps = lib.optionals stdenv.isDarwin [ # libtool is used for static linking. This is part of cctools, but adding # that as a build input puts an unwrapped linker in PATH, and breaks # builds. This small derivation exposes just libtool. # NOTE: The same applies to swift-driver, but that is currently always # invoked via the old `swift` / `swiftc`. May change in the future. (runCommandLocal "libtool" { } '' mkdir -p $out/bin ln -s ${cctools}/bin/libtool $out/bin/libtool '') ]; # There are apparently multiple naming conventions on Darwin. Swift uses the # xcrun naming convention. See `configure_sdk_darwin` calls in CMake files. swiftOs = if targetPlatform.isDarwin then { "macos" = "macosx"; "ios" = "iphoneos"; #iphonesimulator #appletvos #appletvsimulator #watchos #watchsimulator }.${targetPlatform.darwinPlatform} or (throw "Cannot build Swift for target Darwin platform '${targetPlatform.darwinPlatform}'") else targetPlatform.parsed.kernel.name; # Apple Silicon uses a different CPU name in the target triple. swiftArch = if stdenv.isDarwin && stdenv.isAarch64 then "arm64" else targetPlatform.parsed.cpu.name; # On Darwin, a `.swiftmodule` is a subdirectory in `lib/swift/`, # containing binaries for supported archs. On other platforms, binaries are # installed to `lib/swift//`. Note that our setup-hook also adds # `lib/swift` for convenience. swiftLibSubdir = "lib/swift/${swiftOs}"; swiftModuleSubdir = if hostPlatform.isDarwin then "lib/swift/${swiftOs}" else "lib/swift/${swiftOs}/${swiftArch}"; # And then there's also a separate subtree for statically linked modules. toStaticSubdir = lib.replaceStrings [ "/swift/" ] [ "/swift_static/" ]; swiftStaticLibSubdir = toStaticSubdir swiftLibSubdir; swiftStaticModuleSubdir = toStaticSubdir swiftModuleSubdir; # This matches _SWIFT_DEFAULT_COMPONENTS, with specific components disabled. swiftInstallComponents = [ "autolink-driver" "compiler" # "clang-builtin-headers" "stdlib" "sdk-overlay" "static-mirror-lib" "editor-integration" # "tools" # "testsuite-tools" "toolchain-tools" "toolchain-dev-tools" "license" (if stdenv.isDarwin then "sourcekit-xpc-service" else "sourcekit-inproc") "swift-remote-mirror" "swift-remote-mirror-headers" ]; # Build a tool used during the build to create a custom clang wrapper, with # which we wrap the clang produced by the swift build. # # This is used in a `POST_BUILD` for the CMake target, so we rename the # actual clang to clang-unwrapped, then put the wrapper in place. # # We replace the `exec ...` command with `exec -a "$0"` in order to # preserve $0 for clang. This is because, unlike Nix, we don't have # separate wrappers for clang/clang++, and clang uses $0 to detect C++. # # Similarly, the C++ detection in the wrapper itself also won't work for us, # so we base it on $0 as well. makeClangWrapper = writeShellScriptBin "nix-swift-make-clang-wrapper" '' set -euo pipefail targetFile="$1" unwrappedClang="$targetFile-unwrapped" mv "$targetFile" "$unwrappedClang" sed < '${clang}/bin/clang' > "$targetFile" \ -e 's|^\s*exec|exec -a "$0"|g' \ -e 's|^\[\[ "${clang.cc}/bin/clang" = \*++ ]]|[[ "$0" = *++ ]]|' \ -e "s|${clang.cc}/bin/clang|$unwrappedClang|g" \ -e "s|^\(\s*\)\($unwrappedClang\) \"@\\\$responseFile\"|\1argv0=\$0\n\1${bash}/bin/bash -c \"exec -a '\$argv0' \2 '@\$responseFile'\"|" chmod a+x "$targetFile" ''; # Create a tool used during the build to create a custom swift wrapper for # each of the swift executables produced by the build. # # The build produces several `swift-frontend` executables during # bootstrapping. Each of these has numerous aliases via symlinks, and the # executable uses $0 to detect what tool is called. wrapperParams = { inherit bintools; default_cc_wrapper = clang; # Instead of `@out@` in the original. coreutils_bin = lib.getBin coreutils; gnugrep_bin = gnugrep; suffixSalt = lib.replaceStrings ["-" "."] ["_" "_"] targetPlatform.config; use_response_file_by_default = 1; swiftDriver = ""; # NOTE: @prog@ needs to be filled elsewhere. }; swiftWrapper = runCommand "swift-wrapper.sh" wrapperParams '' substituteAll '${../wrapper/wrapper.sh}' "$out" ''; makeSwiftcWrapper = writeShellScriptBin "nix-swift-make-swift-wrapper" '' set -euo pipefail targetFile="$1" unwrappedSwift="$targetFile-unwrapped" mv "$targetFile" "$unwrappedSwift" sed < '${swiftWrapper}' > "$targetFile" \ -e "s|@prog@|'$unwrappedSwift'|g" \ -e 's|exec "$prog"|exec -a "$0" "$prog"|g' chmod a+x "$targetFile" ''; # On Darwin, we need to use BOOTSTRAPPING-WITH-HOSTLIBS because of ABI # stability, and have to provide the definitions for the system stdlib. appleSwiftCore = stdenv.mkDerivation { name = "apple-swift-core"; dontUnpack = true; installPhase = '' mkdir -p $out/lib/swift cp -r \ "${MacOSX-SDK}/usr/lib/swift/Swift.swiftmodule" \ "${MacOSX-SDK}/usr/lib/swift/libswiftCore.tbd" \ $out/lib/swift/ ''; }; in stdenv.mkDerivation { pname = "swift"; inherit (sources) version; outputs = [ "out" "lib" "dev" "doc" "man" ]; nativeBuildInputs = [ cmake git ninja perl # pod2man pkg-config python3 makeWrapper makeClangWrapper makeSwiftcWrapper ] ++ lib.optionals stdenv.isDarwin [ xcbuild sigtool # codesign DarwinTools # sw_vers fixDarwinDylibNames ]; buildInputs = [ # For lldb python3 swig libxml2 ] ++ lib.optionals stdenv.isLinux [ libuuid ] ++ lib.optionals stdenv.isDarwin [ CoreServices Foundation Combine ]; # This is a partial reimplementation of our setup hook. Because we reuse # the Swift wrapper for the Swift build itself, we need to do some of the # same preparation. postHook = '' for pkg in "''${pkgsHostTarget[@]}" '${clang.libc}'; do for subdir in ${swiftModuleSubdir} ${swiftStaticModuleSubdir} lib/swift; do if [[ -d "$pkg/$subdir" ]]; then export NIX_SWIFTFLAGS_COMPILE+=" -I $pkg/$subdir" fi done for subdir in ${swiftLibSubdir} ${swiftStaticLibSubdir} lib/swift; do if [[ -d "$pkg/$subdir" ]]; then export NIX_LDFLAGS+=" -L $pkg/$subdir" fi done done ''; # We invoke cmakeConfigurePhase multiple times, but only need this once. dontFixCmake = true; # We setup custom build directories. dontUseCmakeBuildDir = true; unpackPhase = let copySource = repo: "cp -r ${sources.${repo}} ${repo}"; in '' mkdir src cd src ${copySource "swift-cmark"} ${copySource "llvm-project"} ${copySource "swift"} ${copySource "swift-experimental-string-processing"} ${copySource "swift-syntax"} ${lib.optionalString (!stdenv.isDarwin) (copySource "swift-corelibs-libdispatch")} chmod -R u+w . ''; patchPhase = '' # Just patch all the things for now, we can focus this later. # TODO: eliminate use of env. find -type f -print0 | xargs -0 sed -i \ ${lib.optionalString stdenv.isDarwin "-e 's|/usr/libexec/PlistBuddy|${xcbuild}/bin/PlistBuddy|g'"} \ -e 's|/usr/bin/env|${coreutils}/bin/env|g' \ -e 's|/usr/bin/make|${gnumake}/bin/make|g' \ -e 's|/bin/mkdir|${coreutils}/bin/mkdir|g' \ -e 's|/bin/cp|${coreutils}/bin/cp|g' \ -e 's|/usr/bin/file|${file}/bin/file|g' patch -p1 -d swift -i ${./patches/swift-cmake-3.25-compat.patch} patch -p1 -d swift -i ${./patches/swift-wrap.patch} patch -p1 -d swift -i ${./patches/swift-nix-resource-root.patch} patch -p1 -d swift -i ${./patches/swift-linux-fix-libc-paths.patch} patch -p1 -d swift -i ${./patches/swift-linux-fix-linking.patch} patch -p1 -d swift -i ${./patches/swift-darwin-libcxx-flags.patch} patch -p1 -d swift -i ${substituteAll { src = ./patches/swift-darwin-plistbuddy-workaround.patch; inherit swiftArch; }} patch -p1 -d swift -i ${substituteAll { src = ./patches/swift-prevent-sdk-dirs-warning.patch; inherit (builtins) storeDir; }} # This patch needs to know the lib output location, so must be substituted # in the same derivation as the compiler. storeDir="${builtins.storeDir}" \ substituteAll ${./patches/swift-separate-lib.patch} $TMPDIR/swift-separate-lib.patch patch -p1 -d swift -i $TMPDIR/swift-separate-lib.patch patch -p1 -d llvm-project/llvm -i ${./patches/llvm-module-cache.patch} patch -p1 -d llvm-project/clang -i ${./patches/clang-toolchain-dir.patch} patch -p1 -d llvm-project/clang -i ${./patches/clang-wrap.patch} patch -p1 -d llvm-project/clang -i ${../../llvm/14/clang/purity.patch} patch -p2 -d llvm-project/clang -i ${fetchpatch { name = "clang-cmake-fix-interpreter.patch"; url = "https://github.com/llvm/llvm-project/commit/b5eaf500f2441eff2277ea2973878fb1f171fd0a.patch"; sha256 = "1rma1al0rbm3s3ql6bnvbcighp74lri1lcrwbyacgdqp80fgw1b6"; }} # gcc-13 build fixes patch -p2 -d llvm-project/llvm -i ${fetchpatch { name = "gcc-13.patch"; url = "https://github.com/llvm/llvm-project/commit/ff1681ddb303223973653f7f5f3f3435b48a1983.patch"; hash = "sha256-nkRPWx8gNvYr7mlvEUiOAb1rTrf+skCZjAydJVUHrcI="; }} ${lib.optionalString stdenv.isLinux '' substituteInPlace llvm-project/clang/lib/Driver/ToolChains/Linux.cpp \ --replace 'SysRoot + "/lib' '"${glibc}/lib" "' \ --replace 'SysRoot + "/usr/lib' '"${glibc}/lib" "' \ --replace 'LibDir = "lib";' 'LibDir = "${glibc}/lib";' \ --replace 'LibDir = "lib64";' 'LibDir = "${glibc}/lib";' \ --replace 'LibDir = X32 ? "libx32" : "lib64";' 'LibDir = "${glibc}/lib";' # uuid.h is not part of glibc, but of libuuid. sed -i 's|''${GLIBC_INCLUDE_PATH}/uuid/uuid.h|${libuuid.dev}/include/uuid/uuid.h|' \ swift/stdlib/public/Platform/glibc.modulemap.gyb ''} # Remove tests for cross compilation, which we don't currently support. rm swift/test/Interop/Cxx/class/constructors-copy-irgen-*.swift rm swift/test/Interop/Cxx/class/constructors-irgen-*.swift # TODO: consider fixing and re-adding. This test fails due to a non-standard "install_prefix". rm swift/validation-test/Python/build_swift.swift # We cannot handle the SDK location being in "Weird Location" due to Nix isolation. rm swift/test/DebugInfo/compiler-flags.swift # TODO: Fix issue with ld.gold invoked from script finding crtbeginS.o and crtendS.o. rm swift/test/IRGen/ELF-remove-autolink-section.swift # The following two tests fail because we use don't use the bundled libicu: # [SOURCE_DIR/utils/build-script] ERROR: can't find source directory for libicu (tried /build/src/icu) rm swift/validation-test/BuildSystem/default_build_still_performs_epilogue_opts_after_split.test rm swift/validation-test/BuildSystem/test_early_swift_driver_and_infer.swift # TODO: This test fails for some unknown reason rm swift/test/Serialization/restrict-swiftmodule-to-revision.swift # This test was flaky in ofborg, see #186476 rm swift/test/AutoDiff/compiler_crashers_fixed/issue-56649-missing-debug-scopes-in-pullback-trampoline.swift patchShebangs . ${lib.optionalString (!stdenv.isDarwin) '' # NOTE: This interferes with ABI stability on Darwin, which uses the system # libraries in the hardcoded path /usr/lib/swift. fixCmakeFiles . ''} ''; configurePhase = '' export SWIFT_SOURCE_ROOT="$PWD" mkdir -p ../build cd ../build export SWIFT_BUILD_ROOT="$PWD" # Most builds set a target, but LLDB doesn't. Harmless on non-Darwin. export MACOSX_DEPLOYMENT_TARGET=10.15 ''; # These steps are derived from doing a normal build with. # # ./swift/utils/build-toolchain test --dry-run # # But dealing with the custom Python build system is far more trouble than # simply invoking CMake directly. Few variables it passes to CMake are # actually required or non-default. # # Using CMake directly also allows us to split up the already large build, # and package Swift components separately. # # Besides `--dry-run`, another good way to compare build changes between # Swift releases is to diff the scripts: # # git diff swift-5.6.3-RELEASE..swift-5.7-RELEASE -- utils/build* # buildPhase = '' # Helper to build a subdirectory. # # Always reset cmakeFlags before calling this. The cmakeConfigurePhase # amends flags and would otherwise keep expanding it. function buildProject() { mkdir -p $SWIFT_BUILD_ROOT/$1 cd $SWIFT_BUILD_ROOT/$1 cmakeDir=$SWIFT_SOURCE_ROOT/''${2-$1} cmakeConfigurePhase ninjaBuildPhase } cmakeFlags="-GNinja" buildProject swift-cmark # Some notes: # - The Swift build just needs Clang. # - We can further reduce targets to just our targetPlatform. cmakeFlags=" -GNinja -DLLVM_ENABLE_PROJECTS=clang -DLLVM_TARGETS_TO_BUILD=${{ "x86_64" = "X86"; "aarch64" = "AArch64"; }.${targetPlatform.parsed.cpu.name}} " buildProject llvm llvm-project/llvm '' + lib.optionalString stdenv.isDarwin '' # Add appleSwiftCore to the search paths. We can't simply add it to # buildInputs, because it is potentially an older stdlib than the one we're # building. We have to remove it again after the main Swift build, or later # build steps may fail. (Specific case: Concurrency backdeploy uses the # Sendable protocol, which appears to not be present in the macOS 11 SDK.) OLD_NIX_SWIFTFLAGS_COMPILE="$NIX_SWIFTFLAGS_COMPILE" OLD_NIX_LDFLAGS="$NIX_LDFLAGS" export NIX_SWIFTFLAGS_COMPILE+=" -I ${appleSwiftCore}/lib/swift" export NIX_LDFLAGS+=" -L ${appleSwiftCore}/lib/swift" '' + '' # Some notes: # - BOOTSTRAPPING_MODE defaults to OFF in CMake, but is enabled in standard # builds, so we enable it as well. On Darwin, we have to use the system # Swift libs because of ABI-stability, but this may be trouble if the # builder is an older macOS. # - Experimental features are OFF by default in CMake, but are enabled in # official builds, so we do the same. (Concurrency is also required in # the stdlib. StringProcessing is often implicitely imported, causing # lots of warnings if missing.) # - SWIFT_STDLIB_ENABLE_OBJC_INTEROP is set explicitely because its check # is buggy. (Uses SWIFT_HOST_VARIANT_SDK before initialized.) # Fixed in: https://github.com/apple/swift/commit/84083afef1de5931904d5c815d53856cdb3fb232 cmakeFlags=" -GNinja -DBOOTSTRAPPING_MODE=BOOTSTRAPPING${lib.optionalString stdenv.isDarwin "-WITH-HOSTLIBS"} -DSWIFT_ENABLE_EXPERIMENTAL_DIFFERENTIABLE_PROGRAMMING=ON -DSWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY=ON -DSWIFT_ENABLE_EXPERIMENTAL_DISTRIBUTED=ON -DSWIFT_ENABLE_EXPERIMENTAL_STRING_PROCESSING=ON -DLLVM_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/llvm -DClang_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/clang -DSWIFT_PATH_TO_CMARK_SOURCE=$SWIFT_SOURCE_ROOT/swift-cmark -DSWIFT_PATH_TO_CMARK_BUILD=$SWIFT_BUILD_ROOT/swift-cmark -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE=$SWIFT_SOURCE_ROOT/swift-corelibs-libdispatch -DSWIFT_PATH_TO_SWIFT_SYNTAX_SOURCE=$SWIFT_SOURCE_ROOT/swift-syntax -DSWIFT_PATH_TO_STRING_PROCESSING_SOURCE=$SWIFT_SOURCE_ROOT/swift-experimental-string-processing -DSWIFT_INSTALL_COMPONENTS=${lib.concatStringsSep ";" swiftInstallComponents} -DSWIFT_STDLIB_ENABLE_OBJC_INTEROP=${if stdenv.isDarwin then "ON" else "OFF"} " buildProject swift '' + lib.optionalString stdenv.isDarwin '' # Restore search paths to remove appleSwiftCore. export NIX_SWIFTFLAGS_COMPILE="$OLD_NIX_SWIFTFLAGS_COMPILE" export NIX_LDFLAGS="$OLD_NIX_LDFLAGS" '' + '' # These are based on flags in `utils/build-script-impl`. # # LLDB_USE_SYSTEM_DEBUGSERVER=ON disables the debugserver build on Darwin, # which requires a special signature. # # CMAKE_BUILD_WITH_INSTALL_NAME_DIR ensures we don't use rpath on Darwin. # # NOTE: On Darwin, we only want ncurses in the linker search path, because # headers are part of libsystem. Adding its headers to the search path # causes strange mixing and errors. Note that libedit propagates ncurses, # so we add both manually here, instead of relying on setup hooks. # TODO: Find a better way to prevent this conflict. cmakeFlags=" -GNinja -DLLDB_SWIFTC=$SWIFT_BUILD_ROOT/swift/bin/swiftc -DLLDB_SWIFT_LIBS=$SWIFT_BUILD_ROOT/swift/lib/swift -DLLVM_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/llvm -DClang_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/clang -DSwift_DIR=$SWIFT_BUILD_ROOT/swift/lib/cmake/swift -DLLDB_ENABLE_CURSES=ON -DLLDB_ENABLE_LIBEDIT=ON -DLLDB_ENABLE_PYTHON=ON -DLLDB_ENABLE_LZMA=OFF -DLLDB_ENABLE_LUA=OFF -DLLDB_INCLUDE_TESTS=OFF -DCMAKE_BUILD_WITH_INSTALL_NAME_DIR=ON ${lib.optionalString stdenv.isDarwin '' -DLLDB_USE_SYSTEM_DEBUGSERVER=ON ''} -DLibEdit_INCLUDE_DIRS=${libedit.dev}/include -DLibEdit_LIBRARIES=${libedit}/lib/libedit${stdenv.hostPlatform.extensions.sharedLibrary} -DCURSES_INCLUDE_DIRS=${if stdenv.isDarwin then "/var/empty" else ncurses.dev}/include -DCURSES_LIBRARIES=${ncurses}/lib/libncurses${stdenv.hostPlatform.extensions.sharedLibrary} -DPANEL_LIBRARIES=${ncurses}/lib/libpanel${stdenv.hostPlatform.extensions.sharedLibrary} "; buildProject lldb llvm-project/lldb ${lib.optionalString stdenv.isDarwin '' # Need to do a standalone build of concurrency for Darwin back deployment. # Based on: utils/swift_build_support/swift_build_support/products/backdeployconcurrency.py cmakeFlags=" -GNinja -DCMAKE_Swift_COMPILER=$SWIFT_BUILD_ROOT/swift/bin/swiftc -DSWIFT_PATH_TO_SWIFT_SYNTAX_SOURCE=$SWIFT_SOURCE_ROOT/swift-syntax -DTOOLCHAIN_DIR=/var/empty -DSWIFT_NATIVE_LLVM_TOOLS_PATH=${stdenv.cc}/bin -DSWIFT_NATIVE_CLANG_TOOLS_PATH=${stdenv.cc}/bin -DSWIFT_NATIVE_SWIFT_TOOLS_PATH=$SWIFT_BUILD_ROOT/swift/bin -DCMAKE_CROSSCOMPILING=ON -DBUILD_SWIFT_CONCURRENCY_BACK_DEPLOYMENT_LIBRARIES=ON -DSWIFT_INCLUDE_TOOLS=OFF -DSWIFT_BUILD_STDLIB_EXTRA_TOOLCHAIN_CONTENT=OFF -DSWIFT_BUILD_TEST_SUPPORT_MODULES=OFF -DSWIFT_BUILD_STDLIB=OFF -DSWIFT_BUILD_DYNAMIC_STDLIB=OFF -DSWIFT_BUILD_STATIC_STDLIB=OFF -DSWIFT_BUILD_REMOTE_MIRROR=OFF -DSWIFT_BUILD_SDK_OVERLAY=OFF -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY=OFF -DSWIFT_BUILD_STATIC_SDK_OVERLAY=OFF -DSWIFT_INCLUDE_TESTS=OFF -DSWIFT_BUILD_PERF_TESTSUITE=OFF -DSWIFT_HOST_VARIANT_ARCH=${swiftArch} -DBUILD_STANDALONE=ON -DSWIFT_INSTALL_COMPONENTS=back-deployment -DSWIFT_SDKS=${{ "macos" = "OSX"; "ios" = "IOS"; #IOS_SIMULATOR #TVOS #TVOS_SIMULATOR #WATCHOS #WATCHOS_SIMULATOR }.${targetPlatform.darwinPlatform}} -DLLVM_DIR=$SWIFT_BUILD_ROOT/llvm/lib/cmake/llvm -DSWIFT_DEST_ROOT=$out -DSWIFT_HOST_VARIANT_SDK=OSX -DSWIFT_DARWIN_DEPLOYMENT_VERSION_OSX=10.15 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_IOS=13.0 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_MACCATALYST=13.0 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_TVOS=13.0 -DSWIFT_DARWIN_DEPLOYMENT_VERSION_WATCHOS=6.0 " # This depends on the special Clang build specific to the Swift branch. # We also need to call a specific Ninja target. export CC=$SWIFT_BUILD_ROOT/llvm/bin/clang export CXX=$SWIFT_BUILD_ROOT/llvm/bin/clang++ ninjaFlags="back-deployment" buildProject swift-concurrency-backdeploy swift export CC=$NIX_CC/bin/clang export CXX=$NIX_CC/bin/clang++ unset ninjaFlags ''} ''; # TODO: ~50 failing tests on x86_64-linux. Other platforms not checked. doCheck = false; nativeCheckInputs = [ file ]; # TODO: consider using stress-tester and integration-test. checkPhase = '' cd $SWIFT_BUILD_ROOT/swift checkTarget=check-swift-all ninjaCheckPhase unset checkTarget ''; installPhase = '' # Undo the clang and swift wrapping we did for the build. # (This happened via patches to cmake files.) cd $SWIFT_BUILD_ROOT mv llvm/bin/clang-15{-unwrapped,} mv swift/bin/swift-frontend{-unwrapped,} mkdir $out $lib # Install clang binaries only. We hide these with the wrapper, so they are # for private use by Swift only. cd $SWIFT_BUILD_ROOT/llvm installTargets=install-clang ninjaInstallPhase unset installTargets # LLDB is also a private install. cd $SWIFT_BUILD_ROOT/lldb ninjaInstallPhase cd $SWIFT_BUILD_ROOT/swift ninjaInstallPhase ${lib.optionalString stdenv.isDarwin '' cd $SWIFT_BUILD_ROOT/swift-concurrency-backdeploy installTargets=install-back-deployment ninjaInstallPhase unset installTargets ''} # Separate $lib output here, because specific logic follows. # Only move the dynamic run-time parts, to keep $lib small. Every Swift # build will depend on it. moveToOutput "lib/swift" "$lib" moveToOutput "lib/libswiftDemangle.*" "$lib" # This link is here because various tools (swiftpm) check for stdlib # relative to the swift compiler. It's fine if this is for build-time # stuff, but we should patch all cases were it would end up in an output. ln -s $lib/lib/swift $out/lib/swift # Swift has a separate resource root from Clang, but locates the Clang # resource root via subdir or symlink. Provide a default here, but we also # patch Swift to prefer NIX_CC if set. # # NOTE: We don't symlink directly here, because that'd add a run-time dep # on the full Clang compiler to every Swift executable. The copy here is # just copying the 3 symlinks inside to smaller closures. mkdir $lib/lib/swift/clang cp -P ${clang}/resource-root/* $lib/lib/swift/clang/ ${lib.optionalString stdenv.isDarwin '' # Install required library for ObjC interop. # TODO: Is there no source code for this available? cp -r ${CLTools_Executables}/usr/lib/arc $out/lib/arc ''} ''; preFixup = lib.optionalString stdenv.isLinux '' # This is cheesy, but helps the patchelf hook remove /build from RPATH. cd $SWIFT_BUILD_ROOT/.. mv build buildx ''; postFixup = lib.optionalString stdenv.isDarwin '' # These libraries need to use the system install name. The official SDK # does the same (as opposed to using rpath). Presumably, they are part of # the stable ABI. Not using the system libraries at run-time is known to # cause ObjC class conflicts and segfaults. declare -A systemLibs=( [libswiftCore.dylib]=1 [libswiftDarwin.dylib]=1 [libswiftSwiftOnoneSupport.dylib]=1 [libswift_Concurrency.dylib]=1 ) for systemLib in "''${!systemLibs[@]}"; do install_name_tool -id /usr/lib/swift/$systemLib $lib/${swiftLibSubdir}/$systemLib done for file in $out/bin/swift-frontend $lib/${swiftLibSubdir}/*.dylib; do changeArgs="" for dylib in $(otool -L $file | awk '{ print $1 }'); do if [[ ''${systemLibs["$(basename $dylib)"]} ]]; then changeArgs+=" -change $dylib /usr/lib/swift/$(basename $dylib)" elif [[ "$dylib" = */bootstrapping1/* ]]; then changeArgs+=" -change $dylib $lib/lib/swift/$(basename $dylib)" fi done if [[ -n "$changeArgs" ]]; then install_name_tool $changeArgs $file fi done wrapProgram $out/bin/swift-frontend \ --prefix PATH : ${lib.makeBinPath runtimeDeps} ''; passthru = { inherit swiftOs swiftArch swiftModuleSubdir swiftLibSubdir swiftStaticModuleSubdir swiftStaticLibSubdir; # Internal attr for the wrapper. _wrapperParams = wrapperParams; }; meta = { description = "The Swift Programming Language"; homepage = "https://github.com/apple/swift"; maintainers = with lib.maintainers; [ dtzWill trepetti dduan trundle stephank ]; license = lib.licenses.asl20; platforms = with lib.platforms; linux ++ darwin; # Swift doesn't support 32-bit Linux, unknown on other platforms. badPlatforms = lib.platforms.i686; timeout = 86400; # 24 hours. }; }