Skip to content

Pass through the toolchain to use for manifest loading #7639

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 12 additions & 29 deletions Sources/PackageLoading/ManifestLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,6 @@ public final class ManifestLoader: ManifestLoaderProtocol {
public var delegate: Delegate?

private let databaseCacheDir: AbsolutePath?
private let sdkRootCache = ThreadSafeBox<AbsolutePath>()

private let useInMemoryCache: Bool
private let memoryCache = ThreadSafeKeyValueStore<CacheKey, ManifestJSONParser.Result>()
Expand Down Expand Up @@ -1114,35 +1113,12 @@ public final class ManifestLoader: ManifestLoaderProtocol {
}
}

/// Returns path to the sdk, if possible.
private func sdkRoot() -> AbsolutePath? {
if let sdkRoot = self.sdkRootCache.get() {
return sdkRoot
}

var sdkRootPath: AbsolutePath? = nil
// Find SDKROOT on macOS using xcrun.
#if os(macOS)
let foundPath = try? AsyncProcess.checkNonZeroExit(
args: "/usr/bin/xcrun", "--sdk", "macosx", "--show-sdk-path")
guard let sdkRoot = foundPath?.spm_chomp(), !sdkRoot.isEmpty else {
return nil
}
if let path = try? AbsolutePath(validating: sdkRoot) {
sdkRootPath = path
self.sdkRootCache.put(path)
}
#endif

return sdkRootPath
}

/// Returns the interpreter flags for a manifest.
public func interpreterFlags(
for toolsVersion: ToolsVersion
package static func interpreterFlags(
for toolsVersion: ToolsVersion,
toolchain: some Toolchain
) -> [String] {
var cmd = [String]()
let modulesPath = self.toolchain.swiftPMLibrariesLocation.manifestModulesPath
let modulesPath = toolchain.swiftPMLibrariesLocation.manifestModulesPath
cmd += ["-swift-version", toolsVersion.swiftLanguageVersion.rawValue]
// if runtimePath is set to "PackageFrameworks" that means we could be developing SwiftPM in Xcode
// which produces a framework for dynamic package products.
Expand All @@ -1152,14 +1128,21 @@ public final class ManifestLoader: ManifestLoaderProtocol {
cmd += ["-I", modulesPath.pathString]
}
#if os(macOS)
if let sdkRoot = self.toolchain.sdkRootPath ?? self.sdkRoot() {
if let sdkRoot = toolchain.sdkRootPath {
cmd += ["-sdk", sdkRoot.pathString]
}
#endif
cmd += ["-package-description-version", toolsVersion.description]
return cmd
}

/// Returns the interpreter flags for a manifest.
public func interpreterFlags(
for toolsVersion: ToolsVersion
) -> [String] {
return Self.interpreterFlags(for: toolsVersion, toolchain: toolchain)
}

/// Returns path to the manifest database inside the given cache directory.
private static func manifestCacheDBPath(_ cacheDir: AbsolutePath) -> AbsolutePath {
return cacheDir.appending("manifest.db")
Expand Down
3 changes: 3 additions & 0 deletions Sources/PackageModel/Toolchain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public protocol Toolchain {
/// The root path to the Swift SDK used by this toolchain.
var sdkRootPath: AbsolutePath? { get }

/// The manifest and library locations used by this toolchain.
var swiftPMLibrariesLocation: ToolchainConfiguration.SwiftPMLibrariesLocation { get }

/// Path of the `clang` compiler.
func getClangCompiler() throws -> AbsolutePath

Expand Down
2 changes: 2 additions & 0 deletions Sources/SourceKitLSPAPI/BuildDescription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import class Build.SwiftModuleBuildDescription
import struct PackageGraph.ResolvedModule
import struct PackageGraph.ModulesGraph
import enum PackageGraph.BuildTriple
internal import class PackageModel.UserToolchain

public typealias BuildTriple = PackageGraph.BuildTriple

Expand Down Expand Up @@ -133,6 +134,7 @@ public struct BuildDescription {
return PluginTargetBuildDescription(
target: target,
toolsVersion: package.manifest.toolsVersion,
toolchain: buildPlan.toolsBuildParameters.toolchain,
isPartOfRootPackage: modulesGraph.rootPackages.map(\.id).contains(package.id)
)
}
Expand Down
17 changes: 5 additions & 12 deletions Sources/SourceKitLSPAPI/PluginTargetBuildDescription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@ import struct PackageGraph.ResolvedModule

private import class PackageLoading.ManifestLoader
internal import struct PackageModel.ToolsVersion
internal import class PackageModel.UserToolchain
internal import protocol PackageModel.Toolchain
import enum PackageGraph.BuildTriple

struct PluginTargetBuildDescription: BuildTarget {
private let target: ResolvedModule
private let toolsVersion: ToolsVersion
private let toolchain: any Toolchain
let isPartOfRootPackage: Bool

init(target: ResolvedModule, toolsVersion: ToolsVersion, isPartOfRootPackage: Bool) {
init(target: ResolvedModule, toolsVersion: ToolsVersion, toolchain: any Toolchain, isPartOfRootPackage: Bool) {
assert(target.type == .plugin)
self.target = target
self.toolsVersion = toolsVersion
self.toolchain = toolchain
self.isPartOfRootPackage = isPartOfRootPackage
}

Expand All @@ -47,16 +49,7 @@ struct PluginTargetBuildDescription: BuildTarget {

func compileArguments(for fileURL: URL) throws -> [String] {
// FIXME: This is very odd and we should clean this up by merging `ManifestLoader` and `DefaultPluginScriptRunner` again.
let environment = Environment.current
let loader = ManifestLoader(
toolchain: try UserToolchain(
swiftSDK: .hostSwiftSDK(
environment: environment
),
environment: environment
)
)
var args = loader.interpreterFlags(for: self.toolsVersion)
var args = ManifestLoader.interpreterFlags(for: self.toolsVersion, toolchain: toolchain)
// Note: we ignore the `fileURL` here as the expectation is that we get a commandline for the entire target in case of Swift. Plugins are always assumed to only consist of Swift files.
args += sources.map { $0.path }
return args
Expand Down
3 changes: 3 additions & 0 deletions Sources/_InternalTestSupport/MockBuildTestHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public struct MockToolchain: PackageModel.Toolchain {
public let extraFlags = PackageModel.BuildFlags()
public let installedSwiftPMConfiguration = InstalledSwiftPMConfiguration.default
public let providedLibraries = [ProvidedLibrary]()
public let swiftPMLibrariesLocation = ToolchainConfiguration.SwiftPMLibrariesLocation(
manifestLibraryPath: AbsolutePath("/fake/manifestLib/path"), pluginLibraryPath: AbsolutePath("/fake/pluginLibrary/path")
)

public func getClangCompiler() throws -> AbsolutePath {
"/fake/path/to/clang"
Expand Down
18 changes: 15 additions & 3 deletions Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ final class SourceKitLSPAPITests: XCTestCase {
func testBasicSwiftPackage() throws {
let fs = InMemoryFileSystem(emptyFiles:
"/Pkg/Sources/exe/main.swift",
"/Pkg/Sources/lib/lib.swift"
"/Pkg/Sources/lib/lib.swift",
"/Pkg/Plugins/plugin/plugin.swift"
)

let observability = ObservabilitySystem.makeForTesting()
Expand All @@ -38,6 +39,7 @@ final class SourceKitLSPAPITests: XCTestCase {
targets: [
TargetDescription(name: "exe", dependencies: ["lib"]),
TargetDescription(name: "lib", dependencies: []),
TargetDescription(name: "plugin", type: .plugin, pluginCapability: .buildTool)
]),
],
observabilityScope: observability.topScope
Expand Down Expand Up @@ -81,6 +83,15 @@ final class SourceKitLSPAPITests: XCTestCase {
],
isPartOfRootPackage: true
)
try description.checkArguments(
for: "plugin",
graph: graph,
partialArguments: [
"-I", "/fake/manifestLib/path"
],
isPartOfRootPackage: true,
destination: .tools
)
}
}

Expand All @@ -89,9 +100,10 @@ extension SourceKitLSPAPI.BuildDescription {
for targetName: String,
graph: ModulesGraph,
partialArguments: [String],
isPartOfRootPackage: Bool
isPartOfRootPackage: Bool,
destination: BuildTriple = .destination
) throws -> Bool {
let target = try XCTUnwrap(graph.module(for: targetName, destination: .destination))
let target = try XCTUnwrap(graph.module(for: targetName, destination: destination))
let buildTarget = try XCTUnwrap(self.getBuildTarget(for: target, in: graph))

guard let file = buildTarget.sources.first else {
Expand Down