Skip to content

Commit 07dc10d

Browse files
committed
Handle swift-sdk search paths
- Fixes a bug where includeSearchPaths and librarySearchPaths defined in a swift-sdk.json file were not properly respected. Updates UserToolchain to support these by adding matching properties and updates SwiftTargetBuildDescription as well as ClangTargetBuildDescription to pass these toolchain search paths to the compilers and linkers as expected.
1 parent 706d1f1 commit 07dc10d

File tree

7 files changed

+103
-4
lines changed

7 files changed

+103
-4
lines changed

Sources/Build/BuildDescription/ClangTargetBuildDescription.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,12 @@ public final class ClangTargetBuildDescription {
293293
// User arguments (from -Xcxx) should follow generated arguments to allow user overrides
294294
args += self.buildParameters.flags.cxxCompilerFlags
295295
}
296+
297+
// Pass default include paths from the toolchain.
298+
for includeSearchPath in self.buildParameters.toolchain.includeSearchPaths {
299+
args += ["-I", includeSearchPath.pathString]
300+
}
301+
296302
return args
297303
}
298304

Sources/Build/BuildDescription/ProductBuildDescription.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,11 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
318318
// User arguments (from -Xlinker) should follow generated arguments to allow user overrides
319319
args += self.buildParameters.flags.linkerFlags.asSwiftcLinkerFlags()
320320

321+
// Pass default library paths from the toolchain.
322+
for librarySearchPath in self.buildParameters.toolchain.librarySearchPaths {
323+
args += ["-L", librarySearchPath.pathString]
324+
}
325+
321326
// Add toolchain's libdir at the very end (even after the user -Xlinker arguments).
322327
//
323328
// This will allow linking to libraries shipped in the toolchain.

Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,11 @@ public final class SwiftTargetBuildDescription {
512512
// // User arguments (from -Xcxx) should follow generated arguments to allow user overrides
513513
// args += self.buildParameters.flags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
514514

515+
// Pass default include paths from the toolchain.
516+
for includeSearchPath in self.buildParameters.toolchain.includeSearchPaths {
517+
args += ["-I", includeSearchPath.pathString]
518+
}
519+
515520
// suppress warnings if the package is remote
516521
if self.package.isRemote {
517522
args += ["-suppress-warnings"]
@@ -611,6 +616,11 @@ public final class SwiftTargetBuildDescription {
611616
result += try self.buildSettingsFlags()
612617
result += try self.macroArguments()
613618

619+
// Pass default include paths from the toolchain.
620+
for includeSearchPath in self.buildParameters.toolchain.includeSearchPaths {
621+
result += ["-I", includeSearchPath.pathString]
622+
}
623+
614624
return result
615625
}
616626

@@ -680,6 +690,11 @@ public final class SwiftTargetBuildDescription {
680690
// // User arguments (from -Xcxx) should follow generated arguments to allow user overrides
681691
// result += self.buildParameters.flags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
682692

693+
// Pass default include paths from the toolchain.
694+
for includeSearchPath in self.buildParameters.toolchain.includeSearchPaths {
695+
result += ["-I", includeSearchPath.pathString]
696+
}
697+
683698
result += try self.macroArguments()
684699
return result
685700
}

Sources/PackageModel/Toolchain.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ public protocol Toolchain {
2828
/// Path containing the macOS Swift stdlib.
2929
var macosSwiftStdlib: AbsolutePath { get throws }
3030

31+
/// An array of paths to search for headers and modules at compile time.
32+
var includeSearchPaths: [AbsolutePath] { get }
33+
34+
/// An array of paths to search for libraries at link time.
35+
var librarySearchPaths: [AbsolutePath] { get }
36+
3137
/// Path of the `clang` compiler.
3238
func getClangCompiler() throws -> AbsolutePath
3339

Sources/PackageModel/UserToolchain.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ public final class UserToolchain: Toolchain {
3434
/// Path of the `swiftc` compiler.
3535
public let swiftCompilerPath: AbsolutePath
3636

37+
/// An array of paths to search for headers and modules at compile time.
38+
public let includeSearchPaths: [AbsolutePath]
39+
40+
/// An array of paths to search for libraries at link time.
41+
public let librarySearchPaths: [AbsolutePath]
42+
3743
/// Additional flags to be passed to the build tools.
3844
public var extraFlags: BuildFlags
3945

@@ -482,6 +488,7 @@ public final class UserToolchain: Toolchain {
482488
}
483489

484490
self.triple = triple
491+
485492
self.extraFlags = BuildFlags(
486493
cCompilerFlags: destination.toolset.knownTools[.cCompiler]?.extraCLIOptions ?? [],
487494
cxxCompilerFlags: destination.toolset.knownTools[.cxxCompiler]?.extraCLIOptions ?? [],
@@ -492,6 +499,9 @@ public final class UserToolchain: Toolchain {
492499
linkerFlags: destination.toolset.knownTools[.linker]?.extraCLIOptions ?? [],
493500
xcbuildFlags: destination.toolset.knownTools[.xcbuild]?.extraCLIOptions ?? [])
494501

502+
self.includeSearchPaths = destination.pathsConfiguration.includeSearchPaths ?? []
503+
self.librarySearchPaths = destination.pathsConfiguration.includeSearchPaths ?? []
504+
495505
self.librarianPath = try UserToolchain.determineLibrarian(
496506
triple: triple,
497507
binDirectories: destination.toolset.rootPaths,

Tests/BuildTests/BuildPlanTests.swift

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3551,10 +3551,7 @@ final class BuildPlanTests: XCTestCase {
35513551
runTimeTriple: runtimeTriple,
35523552
properties: .init(
35533553
sdkRootPath: "/fake/sdk",
3554-
swiftStaticResourcesPath: "/usr/lib/swift_static/none",
3555-
includeSearchPaths: ["/usr/lib/swift_static/none"],
3556-
librarySearchPaths: ["/usr/lib/swift_static/none"],
3557-
toolsetPaths: []),
3554+
swiftStaticResourcesPath: "/usr/lib/swift_static/none"),
35583555
toolset: toolSet,
35593556
destinationDirectory: nil)
35603557
let toolchain = try UserToolchain(destination: destination)
@@ -3666,6 +3663,64 @@ final class BuildPlanTests: XCTestCase {
36663663
XCTAssertCount(1, exeLinkArguments, cliFlag(tool: .linker))
36673664
}
36683665

3666+
func testUserToolchainWithSDKSearchPaths() throws {
3667+
let fileSystem = InMemoryFileSystem(emptyFiles:
3668+
"/Pkg/Sources/exe/main.swift",
3669+
"/Pkg/Sources/cLib/cLib.c",
3670+
"/Pkg/Sources/cLib/include/cLib.h"
3671+
)
3672+
3673+
let observability = ObservabilitySystem.makeForTesting()
3674+
let graph = try loadPackageGraph(
3675+
fileSystem: fileSystem,
3676+
manifests: [
3677+
Manifest.createRootManifest(
3678+
displayName: "Pkg",
3679+
path: "/Pkg",
3680+
targets: [
3681+
TargetDescription(name: "exe", dependencies: ["cLib"]),
3682+
TargetDescription(name: "cLib", dependencies: []),
3683+
]),
3684+
],
3685+
observabilityScope: observability.topScope
3686+
)
3687+
XCTAssertNoDiagnostics(observability.diagnostics)
3688+
3689+
let runtimeTriple = try UserToolchain.default.triple
3690+
let sdkIncludeSearchPath = "/usr/lib/swift_static/none/include"
3691+
let sdkLibrarySearchPath = "/usr/lib/swift_static/none/lib"
3692+
let destination = try Destination(
3693+
runTimeTriple: runtimeTriple,
3694+
properties: .init(
3695+
sdkRootPath: "/fake/sdk",
3696+
includeSearchPaths: [sdkIncludeSearchPath],
3697+
librarySearchPaths: [sdkLibrarySearchPath]))
3698+
let toolchain = try UserToolchain(destination: destination)
3699+
let buildParameters = mockBuildParameters(toolchain: toolchain)
3700+
let result = try BuildPlanResult(plan: BuildPlan(
3701+
buildParameters: buildParameters,
3702+
graph: graph,
3703+
fileSystem: fileSystem,
3704+
observabilityScope: observability.topScope))
3705+
result.checkProductsCount(1)
3706+
result.checkTargetsCount(2)
3707+
3708+
// Compile C Target
3709+
let cLibCompileArguments = try result.target(for: "cLib").clangTarget().basicArguments(isCXX: false)
3710+
let cLibCompileArgumentsPattern: [StringPattern] = ["-I", "\(sdkIncludeSearchPath)"]
3711+
XCTAssertMatch(cLibCompileArguments, cLibCompileArgumentsPattern)
3712+
3713+
// Compile Swift Target
3714+
let exeCompileArguments = try result.target(for: "exe").swiftTarget().compileArguments()
3715+
let exeCompileArgumentsPattern: [StringPattern] = ["-I", "\(sdkIncludeSearchPath)"]
3716+
XCTAssertMatch(exeCompileArguments, exeCompileArgumentsPattern)
3717+
3718+
// Link Product
3719+
let exeLinkArguments = try result.buildProduct(for: "exe").linkArguments()
3720+
let exeLinkArgumentsPattern: [StringPattern] = ["-L", "\(sdkIncludeSearchPath)"]
3721+
XCTAssertMatch(exeLinkArguments, exeLinkArgumentsPattern)
3722+
}
3723+
36693724
func testExecBuildTimeDependency() throws {
36703725
let PkgA = AbsolutePath("/PkgA")
36713726

Tests/BuildTests/MockBuildTestHelper.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ struct MockToolchain: PackageModel.Toolchain {
2828
let librarianPath = AbsolutePath("/fake/path/to/ar")
2929
#endif
3030
let swiftCompilerPath = AbsolutePath("/fake/path/to/swiftc")
31+
let includeSearchPaths = [AbsolutePath]()
32+
let librarySearchPaths = [AbsolutePath]()
3133
let isSwiftDevelopmentToolchain = false
3234
let swiftPluginServerPath: AbsolutePath? = nil
3335
let extraFlags = PackageModel.BuildFlags()

0 commit comments

Comments
 (0)