From 809f7d037c8c3a773b9f83df2fbeeef66bf00548 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 11 Aug 2025 15:36:06 +0100 Subject: [PATCH] swiftPackages.swift{,-unwrapped,-driver}: ignore `$NIX_CC` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Swift needs Clang to link with. The linker patch breaks linking when using Swift with a GCC‐based standard environment. Similarly, the internal Clang headers in the resource directory are coupled to the corresponding version of Clang. The resource root patch caused Swift’s Clang to use the resource directory from the version of Clang used in the build environment, which is only compatible if the versions match. Instead, hard‐code the Clang path in the patches and wrappers. --- .../compilers/swift/compiler/default.nix | 39 +++++++---- .../patches/swift-linux-fix-linking.patch | 28 ++++---- .../patches/swift-nix-resource-root.patch | 67 ------------------- .../compilers/swift/swift-driver/default.nix | 6 +- .../patches/linux-fix-linking.patch | 14 ++-- .../patches/nix-resource-root.patch | 28 -------- .../compilers/swift/wrapper/default.nix | 15 +++++ .../compilers/swift/wrapper/wrapper.sh | 2 +- 8 files changed, 65 insertions(+), 134 deletions(-) delete mode 100644 pkgs/development/compilers/swift/compiler/patches/swift-nix-resource-root.patch delete mode 100644 pkgs/development/compilers/swift/swift-driver/patches/nix-resource-root.patch diff --git a/pkgs/development/compilers/swift/compiler/default.nix b/pkgs/development/compilers/swift/compiler/default.nix index 222f8e6b1d6b..891e209dca4d 100644 --- a/pkgs/development/compilers/swift/compiler/default.nix +++ b/pkgs/development/compilers/swift/compiler/default.nix @@ -111,6 +111,18 @@ let "swift-remote-mirror-headers" ]; + clangForWrappers = clang.override (prev: { + extraBuildCommands = + prev.extraBuildCommands + # We need to use the resource directory corresponding to Swift’s + # version of Clang instead of passing along the one from the + # `cc-wrapper` flags. + + '' + substituteInPlace $out/nix-support/cc-cflags \ + --replace-fail " -resource-dir=$out/resource-root" "" + ''; + }); + # Build a tool used during the build to create a custom clang wrapper, with # which we wrap the clang produced by the swift build. # @@ -130,7 +142,7 @@ let unwrappedClang="$targetFile-unwrapped" mv "$targetFile" "$unwrappedClang" - sed < '${clang}/bin/clang' > "$targetFile" \ + sed < '${clangForWrappers}/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" \ @@ -146,13 +158,12 @@ let # 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. + # NOTE: @cc_wrapper@ and @prog@ need to be filled elsewhere. }; swiftWrapper = runCommand "swift-wrapper.sh" wrapperParams '' # Make empty to avoid adding the SDK’s modules in the bootstrap wrapper. Otherwise, the SDK conflicts with the @@ -168,6 +179,7 @@ let mv "$targetFile" "$unwrappedSwift" sed < '${swiftWrapper}' > "$targetFile" \ -e "s|@prog@|'$unwrappedSwift'|g" \ + -e 's|@cc_wrapper@|${clangForWrappers}|g' \ -e 's|exec "$prog"|exec -a "$0" "$prog"|g' chmod a+x "$targetFile" ''; @@ -308,9 +320,12 @@ stdenv.mkDerivation { 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 ${ + replaceVars ./patches/swift-linux-fix-linking.patch { + inherit clang; + } + } patch -p1 -d swift -i ${./patches/swift-darwin-libcxx-flags.patch} patch -p1 -d swift -i ${ replaceVars ./patches/swift-darwin-plistbuddy-workaround.patch { @@ -507,6 +522,10 @@ stdenv.mkDerivation { " buildProject llvm llvm-project/llvm + # Ensure that the built Clang can find the runtime libraries by + # copying the symlinks from the main wrapper. + cp -P ${clang}/resource-root/{lib,share} $SWIFT_BUILD_ROOT/llvm/lib/clang/15.0.0/ + '' + lib.optionalString stdenv.hostPlatform.isDarwin '' # Add appleSwiftCore to the search paths. Adding the whole SDK results in build failures. @@ -714,14 +733,8 @@ stdenv.mkDerivation { 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/ + # resource root via subdir or symlink. + mv $SWIFT_BUILD_ROOT/llvm/lib/clang/15.0.0 $lib/lib/swift/clang ''; preFixup = lib.optionalString stdenv.hostPlatform.isLinux '' diff --git a/pkgs/development/compilers/swift/compiler/patches/swift-linux-fix-linking.patch b/pkgs/development/compilers/swift/compiler/patches/swift-linux-fix-linking.patch index e09d5162a93a..c10b4038a9c4 100644 --- a/pkgs/development/compilers/swift/compiler/patches/swift-linux-fix-linking.patch +++ b/pkgs/development/compilers/swift/compiler/patches/swift-linux-fix-linking.patch @@ -1,21 +1,17 @@ +diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp +index c0ee9217e8..bf7737d6fa 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp -@@ -1475,7 +1475,17 @@ const char *ToolChain::getClangLinkerDriver( - - // If there is a linker driver in the toolchain folder, use that instead. - if (auto tool = llvm::sys::findProgramByName(LinkerDriver, {toolchainPath})) -- LinkerDriver = Args.MakeArgString(tool.get()); -+ return Args.MakeArgString(tool.get()); -+ } -+ -+ // For Nix, prefer linking using the wrapped system clang, instead of using -+ // the unwrapped clang packaged with swift. The latter is unable to link, but -+ // we still want to use it for other purposes (clang importer). -+ if (auto nixCC = llvm::sys::Process::GetEnv("NIX_CC")) { -+ llvm::SmallString<128> binDir(nixCC.getValue()); -+ llvm::sys::path::append(binDir, "bin"); -+ if (auto tool = llvm::sys::findProgramByName(LinkerDriver, {binDir.str()})) -+ return Args.MakeArgString(tool.get()); +@@ -1489,6 +1489,12 @@ + LinkerDriver = Args.MakeArgString(tool.get()); } ++ // For Nix, prefer linking using the wrapped Nixpkgs clang, instead of using ++ // the unwrapped clang packaged with swift. The latter is unable to link, but ++ // we still want to use it for other purposes (clang importer). ++ if (auto tool = llvm::sys::findProgramByName(LinkerDriver, {"@clang@/bin"})) ++ return Args.MakeArgString(tool.get()); ++ return LinkerDriver; + } + diff --git a/pkgs/development/compilers/swift/compiler/patches/swift-nix-resource-root.patch b/pkgs/development/compilers/swift/compiler/patches/swift-nix-resource-root.patch deleted file mode 100644 index b67286a5d1c3..000000000000 --- a/pkgs/development/compilers/swift/compiler/patches/swift-nix-resource-root.patch +++ /dev/null @@ -1,67 +0,0 @@ -Swift normally looks for the Clang resource dir in a subdir/symlink of its own -resource dir. We provide a symlink to the Swift build-time Clang as a default -there, but we also here patch two checks to try locate it via NIX_CC. - -The first (ClangImporter.cpp) happens when Swift code imports C modules. The -second (ToolChains.cpp) happens when Swift is used to link the final product. - ---- a/lib/ClangImporter/ClangImporter.cpp -+++ b/lib/ClangImporter/ClangImporter.cpp -@@ -73,6 +73,7 @@ - #include "llvm/Support/FileSystem.h" - #include "llvm/Support/Memory.h" - #include "llvm/Support/Path.h" -+#include "llvm/Support/Process.h" - #include "llvm/Support/VirtualFileSystem.h" - #include "llvm/Support/YAMLParser.h" - #include -@@ -786,6 +787,17 @@ importer::addCommonInvocationArguments( - - const std::string &overrideResourceDir = importerOpts.OverrideResourceDir; - if (overrideResourceDir.empty()) { -+ // Prefer the Clang resource directory from NIX_CC, to allow swapping in a -+ // different stdenv. -+ // TODO: Figure out how to provide a user override for this. Probably a -+ // niche use case, though, and for now a user can unset NIX_CC to work -+ // around it if necessary. -+ if (auto nixCC = llvm::sys::Process::GetEnv("NIX_CC")) { -+ llvm::SmallString<128> resourceDir(nixCC.getValue()); -+ llvm::sys::path::append(resourceDir, "resource-root"); -+ invocationArgStrs.push_back("-resource-dir"); -+ invocationArgStrs.push_back(std::string(resourceDir.str())); -+ } else { - llvm::SmallString<128> resourceDir(searchPathOpts.RuntimeResourcePath); - - // Adjust the path to refer to our copy of the Clang resource directory -@@ -801,6 +813,7 @@ importer::addCommonInvocationArguments( - // Set the Clang resource directory to the path we computed. - invocationArgStrs.push_back("-resource-dir"); - invocationArgStrs.push_back(std::string(resourceDir.str())); -+ } // nixCC - } else { - invocationArgStrs.push_back("-resource-dir"); - invocationArgStrs.push_back(overrideResourceDir); ---- a/lib/Driver/ToolChains.cpp -+++ b/lib/Driver/ToolChains.cpp -@@ -1393,10 +1393,20 @@ void ToolChain::getClangLibraryPath(const ArgList &Args, - SmallString<128> &LibPath) const { - const llvm::Triple &T = getTriple(); - -+ // Nix: We provide a `clang` symlink in the default Swift resource root, but -+ // prefer detecting the Clang resource root via NIX_CC, to allow swapping in -+ // a different stdenv. However, always honor a user-provided `-resource-dir`. -+ auto nixCC = llvm::sys::Process::GetEnv("NIX_CC"); -+ if (nixCC && !Args.hasArgNoClaim(options::OPT_resource_dir)) { -+ LibPath.assign(nixCC.getValue()); -+ llvm::sys::path::append(LibPath, "resource-root"); -+ } else { - getResourceDirPath(LibPath, Args, /*Shared=*/true); - // Remove platform name. - llvm::sys::path::remove_filename(LibPath); -- llvm::sys::path::append(LibPath, "clang", "lib", -+ llvm::sys::path::append(LibPath, "clang"); -+ } // nixCC -+ llvm::sys::path::append(LibPath, "lib", - T.isOSDarwin() ? "darwin" - : getPlatformNameForTriple(T)); - } diff --git a/pkgs/development/compilers/swift/swift-driver/default.nix b/pkgs/development/compilers/swift/swift-driver/default.nix index d84d5be2ca74..3da4e5bacdf9 100644 --- a/pkgs/development/compilers/swift/swift-driver/default.nix +++ b/pkgs/development/compilers/swift/swift-driver/default.nix @@ -10,6 +10,7 @@ XCTest, sqlite, ncurses, + clang, replaceVars, }: let @@ -40,9 +41,10 @@ stdenv.mkDerivation { ]; patches = [ - ./patches/nix-resource-root.patch ./patches/disable-catalyst.patch - ./patches/linux-fix-linking.patch + (replaceVars ./patches/linux-fix-linking.patch { + inherit clang; + }) # TODO: Replace with branch patch once merged: # https://github.com/apple/swift-driver/pull/1197 (fetchpatch { diff --git a/pkgs/development/compilers/swift/swift-driver/patches/linux-fix-linking.patch b/pkgs/development/compilers/swift/swift-driver/patches/linux-fix-linking.patch index 8f91b3a234b5..be4147d44f07 100644 --- a/pkgs/development/compilers/swift/swift-driver/patches/linux-fix-linking.patch +++ b/pkgs/development/compilers/swift/swift-driver/patches/linux-fix-linking.patch @@ -1,3 +1,5 @@ +diff --git a/Sources/SwiftDriver/Jobs/GenericUnixToolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/GenericUnixToolchain+LinkerSupport.swift +index a4a735f498..381522cc1f 100644 --- a/Sources/SwiftDriver/Jobs/GenericUnixToolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/GenericUnixToolchain+LinkerSupport.swift @@ -10,6 +10,7 @@ @@ -8,19 +10,17 @@ import SwiftOptions import func TSCBasic.lookupExecutablePath -@@ -120,7 +121,20 @@ extension GenericUnixToolchain { +@@ -120,7 +121,18 @@ // just using `clang` and avoid a dependency on the C++ runtime. let clangTool: Tool = parsedOptions.hasArgument(.enableExperimentalCxxInterop) ? .clangxx : .clang - var clangPath = try getToolPath(clangTool) + -+ // For Nix, prefer linking using the wrapped system clang, instead of using ++ // For Nix, prefer linking using the wrapped Nixpkgs clang, instead of using + // the unwrapped clang packaged with swift. The latter is unable to link, but + // we still want to use it for other purposes (clang importer). + var clangPath: AbsolutePath -+ let env = ProcessInfo.processInfo.environment -+ if let nixCC = env["NIX_CC"], -+ let binPath = try? AbsolutePath(validating: "\(nixCC)/bin"), ++ if let binPath = try? AbsolutePath(validating: "@clang@/bin"), + let tool = lookupExecutablePath(filename: parsedOptions.hasArgument(.enableExperimentalCxxInterop) + ? "clang++" : "clang", + searchPaths: [binPath]) { @@ -30,11 +30,11 @@ if let toolsDirPath = parsedOptions.getLastArgument(.toolsDirectory) { // FIXME: What if this isn't an absolute path? let toolsDir = try AbsolutePath(validating: toolsDirPath.asSingle) -@@ -136,6 +150,7 @@ extension GenericUnixToolchain { +@@ -136,6 +148,7 @@ commandLine.appendFlag("-B") commandLine.appendPath(toolsDir) } -+ } // nixCC ++ } // Nix // Executables on Linux get -pie if targetTriple.os == .linux && linkerOutputType == .executable { diff --git a/pkgs/development/compilers/swift/swift-driver/patches/nix-resource-root.patch b/pkgs/development/compilers/swift/swift-driver/patches/nix-resource-root.patch deleted file mode 100644 index 8c24db5aad1d..000000000000 --- a/pkgs/development/compilers/swift/swift-driver/patches/nix-resource-root.patch +++ /dev/null @@ -1,28 +0,0 @@ -Swift normally looks for the Clang resource dir in a subdir/symlink of its own -resource dir. We provide a symlink to the Swift build-time Clang as a default -there, but we also here patch a check to try locate it via NIX_CC. - ---- a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift -+++ b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift -@@ -10,6 +10,7 @@ - // - //===----------------------------------------------------------------------===// - -+import Foundation - import SwiftOptions - - import protocol TSCBasic.FileSystem -@@ -26,6 +27,13 @@ extension Toolchain { - for targetInfo: FrontendTargetInfo, - parsedOptions: inout ParsedOptions - ) throws -> VirtualPath { -+ let env = ProcessInfo.processInfo.environment -+ if let nixCC = env["NIX_CC"] { -+ return try VirtualPath(path: nixCC) -+ .appending(components: "resource-root", "lib", -+ targetInfo.target.triple.platformName(conflatingDarwin: true)!) -+ } -+ - return VirtualPath.lookup(targetInfo.runtimeResourcePath.path) - .appending(components: "clang", "lib", - targetInfo.target.triple.platformName(conflatingDarwin: true)!) diff --git a/pkgs/development/compilers/swift/wrapper/default.nix b/pkgs/development/compilers/swift/wrapper/default.nix index b291426bc9e4..88bb9a3c2139 100644 --- a/pkgs/development/compilers/swift/wrapper/default.nix +++ b/pkgs/development/compilers/swift/wrapper/default.nix @@ -4,6 +4,7 @@ swift, useSwiftDriver ? true, swift-driver, + clang, }: stdenv.mkDerivation ( @@ -28,6 +29,20 @@ stdenv.mkDerivation ( swiftStaticLibSubdir ; swiftDriver = lib.optionalString useSwiftDriver "${swift-driver}/bin/swift-driver"; + cc_wrapper = clang.override (prev: { + extraBuildCommands = + prev.extraBuildCommands + # We need to use the resource directory corresponding to Swift’s + # version of Clang instead of passing along the one from the + # `cc-wrapper` flags. + + '' + rm -r $out/resource-root + substituteInPlace $out/nix-support/cc-cflags \ + --replace-fail \ + "-resource-dir=$out/resource-root" \ + "-resource-dir=${lib.getLib swift}/lib/swift/clang" + ''; + }); env.darwinMinVersion = lib.optionalString stdenv.targetPlatform.isDarwin ( stdenv.targetPlatform.darwinMinVersion diff --git a/pkgs/development/compilers/swift/wrapper/wrapper.sh b/pkgs/development/compilers/swift/wrapper/wrapper.sh index bb9c07a5b444..a0f706dfbe6c 100644 --- a/pkgs/development/compilers/swift/wrapper/wrapper.sh +++ b/pkgs/development/compilers/swift/wrapper/wrapper.sh @@ -8,7 +8,7 @@ if (( "${NIX_DEBUG:-0}" >= 7 )); then set -x fi -cc_wrapper="${NIX_CC:-@default_cc_wrapper@}" +cc_wrapper="@cc_wrapper@" source $cc_wrapper/nix-support/utils.bash