swiftPackages.swift{,-unwrapped,-driver}: ignore `$NIX_CC`

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.

Emily 809f7d03 1884f3de

Changed files
+64 -133
pkgs
+26 -13
pkgs/development/compilers/swift/compiler/default.nix
···
"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.
#
···
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" \
···
# 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
···
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"
'';
···
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 {
···
}
"
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 ''
···
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 ''
+11 -15
pkgs/development/compilers/swift/compiler/patches/swift-linux-fix-linking.patch
···
+
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(
+
@@ -1489,6 +1489,12 @@
+
LinkerDriver = Args.MakeArgString(tool.get());
+
}
-
// 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
+
+ // 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 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());
-
}
+
+ if (auto tool = llvm::sys::findProgramByName(LinkerDriver, {"@clang@/bin"}))
+
+ return Args.MakeArgString(tool.get());
+
+
+
return LinkerDriver;
+
}
-
return LinkerDriver;
-67
pkgs/development/compilers/swift/compiler/patches/swift-nix-resource-root.patch
···
-
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 <algorithm>
-
@@ -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));
-
}
+4 -2
pkgs/development/compilers/swift/swift-driver/default.nix
···
XCTest,
sqlite,
ncurses,
+
clang,
replaceVars,
}:
let
···
];
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 {
+7 -7
pkgs/development/compilers/swift/swift-driver/patches/linux-fix-linking.patch
···
+
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 @@
···
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]) {
···
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 {
-28
pkgs/development/compilers/swift/swift-driver/patches/nix-resource-root.patch
···
-
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)!)
+15
pkgs/development/compilers/swift/wrapper/default.nix
···
swift,
useSwiftDriver ? true,
swift-driver,
+
clang,
}:
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
+1 -1
pkgs/development/compilers/swift/wrapper/wrapper.sh
···
set -x
fi
-
cc_wrapper="${NIX_CC:-@default_cc_wrapper@}"
+
cc_wrapper="@cc_wrapper@"
source $cc_wrapper/nix-support/utils.bash