Skip to content

Commit 73cb713

Browse files
committed
Merge remote-tracking branch 'origin/main' into release/5.10
2 parents 94a4d53 + 058574d commit 73cb713

File tree

14 files changed

+97
-33
lines changed

14 files changed

+97
-33
lines changed

Sources/Build/BuildOperation.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
443443
buildEnvironment: self.buildParameters.buildEnvironment,
444444
toolSearchDirectories: [self.buildParameters.toolchain.swiftCompilerPath.parentDirectory],
445445
pkgConfigDirectories: self.pkgConfigDirectories,
446+
sdkRootPath: self.buildParameters.toolchain.sdkRootPath,
446447
pluginScriptRunner: pluginConfiguration.scriptRunner,
447448
observabilityScope: self.observabilityScope,
448449
fileSystem: self.fileSystem

Sources/Build/BuildPlan.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,7 @@ public class BuildPlan: SPMBuildCore.BuildPlan {
10031003
let results = try pkgConfigArgs(
10041004
for: target,
10051005
pkgConfigDirectories: buildParameters.pkgConfigDirectories,
1006+
sdkRootPath: buildParameters.toolchain.sdkRootPath,
10061007
fileSystem: fileSystem,
10071008
observabilityScope: observabilityScope
10081009
)

Sources/Commands/PackageTools/PluginCommand.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,8 @@ struct PluginCommand: SwiftCommand {
281281
let delegateQueue = DispatchQueue(label: "plugin-invocation")
282282

283283
// Run the command plugin.
284-
let buildEnvironment = try swiftTool.buildParameters().buildEnvironment
284+
let buildParameters = try swiftTool.buildParameters()
285+
let buildEnvironment = buildParameters.buildEnvironment
285286
let _ = try temp_await { plugin.invoke(
286287
action: .performCommand(package: package, arguments: arguments),
287288
buildEnvironment: buildEnvironment,
@@ -294,6 +295,7 @@ struct PluginCommand: SwiftCommand {
294295
readOnlyDirectories: readOnlyDirectories,
295296
allowNetworkConnections: allowNetworkConnections,
296297
pkgConfigDirectories: swiftTool.options.locations.pkgConfigDirectories,
298+
sdkRootPath: buildParameters.toolchain.sdkRootPath,
297299
fileSystem: swiftTool.fileSystem,
298300
observabilityScope: swiftTool.observabilityScope,
299301
callbackQueue: delegateQueue,

Sources/PackageLoading/Target+PkgConfig.swift

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import Basics
1414
import PackageModel
1515

1616
import class TSCBasic.Process
17+
import struct TSCBasic.RegEx
1718

1819
import enum TSCUtility.Platform
1920

@@ -63,6 +64,7 @@ public struct PkgConfigResult {
6364
public func pkgConfigArgs(
6465
for target: SystemLibraryTarget,
6566
pkgConfigDirectories: [AbsolutePath],
67+
sdkRootPath: AbsolutePath? = nil,
6668
brewPrefix: AbsolutePath? = .none,
6769
fileSystem: FileSystem,
6870
observabilityScope: ObservabilityScope
@@ -98,7 +100,14 @@ public func pkgConfigArgs(
98100
let filtered = try allowlist(pcFile: pkgConfigName, flags: (pkgConfig.cFlags, pkgConfig.libs))
99101

100102
// Remove any default flags which compiler adds automatically.
101-
let (cFlags, libs) = try removeDefaultFlags(cFlags: filtered.cFlags, libs: filtered.libs)
103+
var (cFlags, libs) = try removeDefaultFlags(cFlags: filtered.cFlags, libs: filtered.libs)
104+
105+
// Patch any paths containing an SDK to the current SDK
106+
// See https://github.com/apple/swift-package-manager/issues/6439
107+
if let sdkRootPath = sdkRootPath {
108+
cFlags = try patchSDKPaths(in: cFlags, to: sdkRootPath)
109+
libs = try patchSDKPaths(in: libs, to: sdkRootPath)
110+
}
102111

103112
// Set the error if there are any disallowed flags.
104113
var error: Swift.Error?
@@ -261,43 +270,64 @@ public func allowlist(
261270
return (filteredCFlags.allowed, filteredLibs.allowed, filteredCFlags.disallowed + filteredLibs.disallowed)
262271
}
263272

273+
/// Maps values of the given flag with the given transform, removing those where the transform returns `nil`.
274+
private func patch(flag: String, in flags: [String], transform: (String) -> String?) throws -> [String] {
275+
var result = [String]()
276+
var it = flags.makeIterator()
277+
while let current = it.next() {
278+
if current == flag {
279+
// Handle <flag><space><value> style.
280+
guard let value = it.next() else {
281+
throw InternalError("Expected associated value")
282+
}
283+
if let newValue = transform(value) {
284+
result.append(flag)
285+
result.append(newValue)
286+
}
287+
} else if current.starts(with: flag) {
288+
// Handle <flag><value> style
289+
let value = String(current.dropFirst(flag.count))
290+
if let newValue = transform(value) {
291+
result.append(flag + newValue)
292+
}
293+
} else {
294+
// Leave other flags as-is
295+
result.append(current)
296+
}
297+
}
298+
return result
299+
}
300+
301+
/// Removes the given flag from the given flags.
302+
private func remove(flag: String, with expectedValue: String, from flags: [String]) throws -> [String] {
303+
try patch(flag: flag, in: flags) { value in value == expectedValue ? nil : value }
304+
}
305+
264306
/// Remove the default flags which are already added by the compiler.
265307
///
266308
/// This behavior is similar to pkg-config cli tool and helps avoid conflicts between
267309
/// sdk and default search paths in macOS.
268310
public func removeDefaultFlags(cFlags: [String], libs: [String]) throws -> ([String], [String]) {
269-
/// removes a flag from given array of flags.
270-
func remove(flag: (String, String), from flags: [String]) throws -> [String] {
271-
var result = [String]()
272-
var it = flags.makeIterator()
273-
while let curr = it.next() {
274-
switch curr {
275-
case flag.0:
276-
// Check for <flag><space><value> style.
277-
guard let val = it.next() else {
278-
throw InternalError("Expected associated value")
279-
}
280-
// If we found a match, don't add these flags and just skip.
281-
if val == flag.1 { continue }
282-
// Otherwise add both the flags.
283-
result.append(curr)
284-
result.append(val)
285-
286-
case flag.0 + flag.1:
287-
// Check for <flag><value> style.
288-
continue
311+
return (
312+
try remove(flag: "-I", with: "/usr/include", from: cFlags),
313+
try remove(flag: "-L", with: "/usr/lib", from: libs)
314+
)
315+
}
289316

290-
default:
291-
// Otherwise just append this flag.
292-
result.append(curr)
317+
/// Replaces any path containing *.sdk with the current SDK to avoid conflicts.
318+
///
319+
/// See https://github.com/apple/swift-package-manager/issues/6439 for details.
320+
public func patchSDKPaths(in flags: [String], to sdkRootPath: AbsolutePath) throws -> [String] {
321+
let sdkRegex = try! RegEx(pattern: #"^.*\.sdk(\/.*|$)"#)
322+
323+
return try ["-I", "-L"].reduce(flags) { (flags, flag) in
324+
try patch(flag: flag, in: flags) { value in
325+
guard let groups = sdkRegex.matchGroups(in: value).first else {
326+
return value
293327
}
328+
return sdkRootPath.pathString + groups[0]
294329
}
295-
return result
296330
}
297-
return (
298-
try remove(flag: ("-I", "/usr/include"), from: cFlags),
299-
try remove(flag: ("-L", "/usr/lib"), from: libs)
300-
)
301331
}
302332

303333
extension ObservabilityMetadata {

Sources/PackageModel/Toolchain.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ public protocol Toolchain {
4343
/// Configuration from the used toolchain.
4444
var installedSwiftPMConfiguration: InstalledSwiftPMConfiguration { get }
4545

46+
/// The root path to the Swift SDK used by this toolchain.
47+
var sdkRootPath: AbsolutePath? { get }
48+
4649
/// Path of the `clang` compiler.
4750
func getClangCompiler() throws -> AbsolutePath
4851

Sources/SPMBuildCore/PluginContextSerializer.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ internal struct PluginContextSerializer {
2424
let fileSystem: FileSystem
2525
let buildEnvironment: BuildEnvironment
2626
let pkgConfigDirectories: [AbsolutePath]
27+
let sdkRootPath: AbsolutePath?
2728
var paths: [WireInput.Path] = []
2829
var pathsToIds: [AbsolutePath: WireInput.Path.Id] = [:]
2930
var targets: [WireInput.Target] = []
@@ -108,6 +109,7 @@ internal struct PluginContextSerializer {
108109
for result in try pkgConfigArgs(
109110
for: target,
110111
pkgConfigDirectories: pkgConfigDirectories,
112+
sdkRootPath: sdkRootPath,
111113
fileSystem: fileSystem,
112114
observabilityScope: observabilityScope
113115
) {

Sources/SPMBuildCore/PluginInvocation.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ extension PluginTarget {
5959
readOnlyDirectories: [AbsolutePath],
6060
allowNetworkConnections: [SandboxNetworkPermission],
6161
pkgConfigDirectories: [AbsolutePath],
62+
sdkRootPath: AbsolutePath?,
6263
fileSystem: FileSystem,
6364
observabilityScope: ObservabilityScope,
6465
callbackQueue: DispatchQueue,
@@ -79,7 +80,8 @@ extension PluginTarget {
7980
var serializer = PluginContextSerializer(
8081
fileSystem: fileSystem,
8182
buildEnvironment: buildEnvironment,
82-
pkgConfigDirectories: pkgConfigDirectories
83+
pkgConfigDirectories: pkgConfigDirectories,
84+
sdkRootPath: sdkRootPath
8385
)
8486
let pluginWorkDirId = try serializer.serialize(path: outputDirectory)
8587
let toolSearchDirIds = try toolSearchDirectories.map{ try serializer.serialize(path: $0) }
@@ -332,6 +334,7 @@ extension PackageGraph {
332334
buildEnvironment: BuildEnvironment,
333335
toolSearchDirectories: [AbsolutePath],
334336
pkgConfigDirectories: [AbsolutePath],
337+
sdkRootPath: AbsolutePath?,
335338
pluginScriptRunner: PluginScriptRunner,
336339
observabilityScope: ObservabilityScope,
337340
fileSystem: FileSystem,
@@ -479,6 +482,7 @@ extension PackageGraph {
479482
readOnlyDirectories: readOnlyDirectories,
480483
allowNetworkConnections: [],
481484
pkgConfigDirectories: pkgConfigDirectories,
485+
sdkRootPath: sdkRootPath,
482486
fileSystem: fileSystem,
483487
observabilityScope: observabilityScope,
484488
callbackQueue: delegateQueue,

Sources/XCBuildSupport/PIFBuilder.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ struct PIFBuilderParameters {
3434

3535
/// An array of paths to search for pkg-config `.pc` files.
3636
let pkgConfigDirectories: [AbsolutePath]
37+
38+
/// The toolchain's SDK root path.
39+
let sdkRootPath: AbsolutePath?
3740
}
3841

3942
/// PIF object builder for a package graph.
@@ -711,6 +714,7 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder {
711714
for result in try pkgConfigArgs(
712715
for: systemTarget,
713716
pkgConfigDirectories: parameters.pkgConfigDirectories,
717+
sdkRootPath: parameters.sdkRootPath,
714718
fileSystem: fileSystem,
715719
observabilityScope: observabilityScope
716720
) {

Sources/XCBuildSupport/XcodeBuildSystem.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,8 @@ extension PIFBuilderParameters {
321321
enableTestability: buildParameters.enableTestability,
322322
shouldCreateDylibForDynamicProducts: buildParameters.shouldCreateDylibForDynamicProducts,
323323
toolchainLibDir: (try? buildParameters.toolchain.toolchainLibDir) ?? .root,
324-
pkgConfigDirectories: buildParameters.pkgConfigDirectories
324+
pkgConfigDirectories: buildParameters.pkgConfigDirectories,
325+
sdkRootPath: buildParameters.toolchain.sdkRootPath
325326
)
326327
}
327328
}

Tests/BuildTests/MockBuildTestHelper.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct MockToolchain: PackageModel.Toolchain {
3131
let swiftResourcesPath: AbsolutePath? = nil
3232
let swiftStaticResourcesPath: AbsolutePath? = nil
3333
let isSwiftDevelopmentToolchain = false
34+
let sdkRootPath: AbsolutePath? = nil
3435
let swiftPluginServerPath: AbsolutePath? = nil
3536
let extraFlags = PackageModel.BuildFlags()
3637
let installedSwiftPMConfiguration = InstalledSwiftPMConfiguration.default

Tests/FunctionalTests/PluginTests.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ class PluginTests: XCTestCase {
472472
readOnlyDirectories: [package.path],
473473
allowNetworkConnections: [],
474474
pkgConfigDirectories: [],
475+
sdkRootPath: nil,
475476
fileSystem: localFileSystem,
476477
observabilityScope: observability.topScope,
477478
callbackQueue: delegateQueue,
@@ -742,6 +743,7 @@ class PluginTests: XCTestCase {
742743
readOnlyDirectories: [package.path],
743744
allowNetworkConnections: [],
744745
pkgConfigDirectories: [],
746+
sdkRootPath: try UserToolchain.default.sdkRootPath,
745747
fileSystem: localFileSystem,
746748
observabilityScope: observability.topScope,
747749
callbackQueue: delegateQueue,

Tests/PackageLoadingTests/PkgConfigAllowlistTests.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import Basics
1314
import PackageLoading
1415
import XCTest
1516

@@ -42,4 +43,12 @@ final class PkgConfigAllowlistTests: XCTestCase {
4243
XCTAssertEqual(result.0, ["-I", "/usr/include/Cellar/gtk+3/3.18.9/include/gtk-3.0", "-L/hello"])
4344
XCTAssertEqual(result.1, ["-L/usr/lib/Cellar/gtk+3/3.18.9/lib", "-lgtk-3", "-module-name", "-lcool", "ok", "name"])
4445
}
46+
47+
func testPathSDKPaths() throws {
48+
let flags = ["-I/opt/homebrew/Cellar/cairo/1.16.0_5/include/cairo", "-I/Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk/usr/include/ffi"]
49+
let sdk = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk"
50+
let result = try patchSDKPaths(in: flags, to: AbsolutePath(sdk))
51+
52+
XCTAssertEqual(result, ["-I/opt/homebrew/Cellar/cairo/1.16.0_5/include/cairo", "-I\(sdk)/usr/include/ffi"])
53+
}
4554
}

Tests/SPMBuildCoreTests/PluginInvocationTests.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ class PluginInvocationTests: XCTestCase {
195195
buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug),
196196
toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory],
197197
pkgConfigDirectories: [],
198+
sdkRootPath: UserToolchain.default.sdkRootPath,
198199
pluginScriptRunner: pluginRunner,
199200
observabilityScope: observability.topScope,
200201
fileSystem: fileSystem
@@ -900,6 +901,7 @@ class PluginInvocationTests: XCTestCase {
900901
buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug),
901902
toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory],
902903
pkgConfigDirectories: [],
904+
sdkRootPath: UserToolchain.default.sdkRootPath,
903905
pluginScriptRunner: pluginScriptRunner,
904906
observabilityScope: observability.topScope,
905907
fileSystem: localFileSystem
@@ -1243,6 +1245,7 @@ class PluginInvocationTests: XCTestCase {
12431245
buildEnvironment: BuildEnvironment(platform: .macOS, configuration: .debug),
12441246
toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory],
12451247
pkgConfigDirectories: [],
1248+
sdkRootPath: UserToolchain.default.sdkRootPath,
12461249
pluginScriptRunner: pluginScriptRunner,
12471250
observabilityScope: observability.topScope,
12481251
fileSystem: localFileSystem

Tests/XCBuildSupportTests/PIFBuilderTests.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2626,7 +2626,8 @@ extension PIFBuilderParameters {
26262626
enableTestability: false,
26272627
shouldCreateDylibForDynamicProducts: shouldCreateDylibForDynamicProducts,
26282628
toolchainLibDir: "/toolchain/lib",
2629-
pkgConfigDirectories: ["/pkg-config"]
2629+
pkgConfigDirectories: ["/pkg-config"],
2630+
sdkRootPath: "/some.sdk"
26302631
)
26312632
}
26322633
}

0 commit comments

Comments
 (0)