Skip to content

Commit

Permalink
Support using SourceKit-LSP for projects that are cross-compiled
Browse files Browse the repository at this point in the history
We previously always assumed that the project was being built for the host.

Fixes swiftlang#786
Fixes swiftlang#1475
rdar://129662080
rdar://113099964
  • Loading branch information
ahoppen authored and lokesh-tr committed Jul 4, 2024
1 parent 9da4edc commit 935120b
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 13 deletions.
15 changes: 9 additions & 6 deletions Documentation/Configuration File.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ The structure of the file is currently not guaranteed to be stable. Options may
`config.json` is a JSON file with the following structure. All keys are optional and unknown keys are ignored.

- `swiftPM`: Dictionary with the following keys, defining options for SwiftPM workspaces
- `configuration: "debug"|"release"`: The configuration to build the project for during background indexing and the configuration whose build folder should be used for Swift modules if background indexing is disabled
- `scratchPath: string`: Build artifacts directory path. If nil, the build system may choose a default value
- `cCompilerFlags: string[]`: Extra arguments passed to the compiler for C files
- `cxxCompilerFlags: string[]`: Extra arguments passed to the compiler for C++ files
- `swiftCompilerFlags: string[]`: Extra arguments passed to the compiler for Swift files
- `linkerFlags: string[]`: Extra arguments passed to the linker
- `configuration: "debug"|"release"`: The configuration to build the project for during background indexing and the configuration whose build folder should be used for Swift modules if background indexing is disabled. Equivalent to SwiftPM's `--configuration` option.
- `scratchPath: string`: Build artifacts directory path. If nil, the build system may choose a default value. Equivalent to SwiftPM's `--scratch-path` option.
- `swiftSDKsDirectory: string`: Equivalent to SwiftPM's `--swift-sdks-path` option
- `swiftSDK: string`: Equivalent to SwiftPM's `--swift-sdk` option
- `triple: string`: Equivalent to SwiftPM's `--triple` option
- `cCompilerFlags: string[]`: Extra arguments passed to the compiler for C files. Equivalent to SwiftPM's `-Xcc` option.
- `cxxCompilerFlags: string[]`: Extra arguments passed to the compiler for C++ files. Equivalent to SwiftPM's `-Xcxx` option.
- `swiftCompilerFlags: string[]`: Extra arguments passed to the compiler for Swift files. Equivalent to SwiftPM's `-Xswiftc` option.
- `linkerFlags: string[]`: Extra arguments passed to the linker. Equivalent to SwiftPM's `-Xlinker` option.
- `compilationDatabase`: Dictionary with the following keys, defining options for workspaces with a compilation database
- `searchPaths: string[]`: Additional paths to search for a compilation database, relative to a workspace root.
- `fallbackBuildSystem`: Dictionary with the following keys, defining options for files that aren't managed by any build system
Expand Down
29 changes: 29 additions & 0 deletions Sources/SKCore/SourceKitLSPOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,52 @@ import struct TSCBasic.AbsolutePath
public struct SourceKitLSPOptions: Sendable, Codable {
public struct SwiftPMOptions: Sendable, Codable {
/// Build configuration (debug|release).
///
/// Equivalent to SwiftPM's `--configuration` option.
public var configuration: BuildConfiguration?

/// Build artifacts directory path. If nil, the build system may choose a default value.
///
/// Equivalent to SwiftPM's `--scratch-path` option.
public var scratchPath: String?

/// Equivalent to SwiftPM's `--swift-sdks-path` option
public var swiftSDKsDirectory: String?

/// Equivalent to SwiftPM's `--swift-sdk` option
public var swiftSDK: String?

/// Equivalent to SwiftPM's `--triple` option
public var triple: String?

/// Equivalent to SwiftPM's `-Xcc` option
public var cCompilerFlags: [String]?

/// Equivalent to SwiftPM's `-Xcxx` option
public var cxxCompilerFlags: [String]?

/// Equivalent to SwiftPM's `-Xswiftc` option
public var swiftCompilerFlags: [String]?

/// Equivalent to SwiftPM's `-Xlinker` option
public var linkerFlags: [String]?

public init(
configuration: BuildConfiguration? = nil,
scratchPath: String? = nil,
swiftSDKsDirectory: String? = nil,
swiftSDK: String? = nil,
triple: String? = nil,
cCompilerFlags: [String]? = nil,
cxxCompilerFlags: [String]? = nil,
swiftCompilerFlags: [String]? = nil,
linkerFlags: [String]? = nil
) {
self.configuration = configuration
self.scratchPath = scratchPath
self.swiftSDKsDirectory = swiftSDKsDirectory
self.swiftSDK = swiftSDK
self.triple = triple
self.cCompilerFlags = cCompilerFlags
self.cxxCompilerFlags = cxxCompilerFlags
self.swiftCompilerFlags = swiftCompilerFlags
Expand All @@ -53,6 +79,9 @@ public struct SourceKitLSPOptions: Sendable, Codable {
return SwiftPMOptions(
configuration: override?.configuration ?? base.configuration,
scratchPath: override?.scratchPath ?? base.scratchPath,
swiftSDKsDirectory: override?.swiftSDKsDirectory ?? base.swiftSDKsDirectory,
swiftSDK: override?.swiftSDK ?? base.swiftSDK,
triple: override?.triple ?? base.triple,
cCompilerFlags: override?.cCompilerFlags ?? base.cCompilerFlags,
cxxCompilerFlags: override?.cxxCompilerFlags ?? base.cxxCompilerFlags,
swiftCompilerFlags: override?.swiftCompilerFlags ?? base.swiftCompilerFlags,
Expand Down
36 changes: 29 additions & 7 deletions Sources/SKSwiftPMWorkspace/SwiftPMBuildSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,29 @@ public actor SwiftPMBuildSystem {
throw Error.cannotDetermineHostToolchain
}

let swiftSDK = try SwiftSDK.hostSwiftSDK(AbsolutePath(destinationToolchainBinDir))
let swiftPMToolchain = try UserToolchain(swiftSDK: swiftSDK)
let hostSDK = try SwiftSDK.hostSwiftSDK(AbsolutePath(destinationToolchainBinDir))
let hostSwiftPMToolchain = try UserToolchain(swiftSDK: hostSDK)

var destinationSDK: SwiftSDK
if let swiftSDK = options.swiftSDK {
let bundleStore = try SwiftSDKBundleStore(
swiftSDKsDirectory: fileSystem.getSharedSwiftSDKsDirectory(
explicitDirectory: options.swiftSDKsDirectory.map { try AbsolutePath(validating: $0) }
),
fileSystem: fileSystem,
observabilityScope: observabilitySystem.topScope,
outputHandler: { _ in }
)
destinationSDK = try bundleStore.selectBundle(matching: swiftSDK, hostTriple: hostSwiftPMToolchain.targetTriple)
} else {
destinationSDK = hostSDK
}

if let triple = options.triple {
destinationSDK = hostSDK
destinationSDK.targetTriple = try Triple(triple)
}
let destinationSwiftPMToolchain = try UserToolchain(swiftSDK: destinationSDK)

var location = try Workspace.Location(
forRootPackage: AbsolutePath(packageRoot),
Expand All @@ -244,7 +265,7 @@ public actor SwiftPMBuildSystem {
fileSystem: fileSystem,
location: location,
configuration: configuration,
customHostToolchain: swiftPMToolchain
customHostToolchain: hostSwiftPMToolchain
)

let buildConfiguration: PackageModel.BuildConfiguration
Expand All @@ -265,20 +286,21 @@ public actor SwiftPMBuildSystem {
self.toolsBuildParameters = try BuildParameters(
destination: .host,
dataPath: location.scratchDirectory.appending(
component: swiftPMToolchain.targetTriple.platformBuildPathComponent
component: hostSwiftPMToolchain.targetTriple.platformBuildPathComponent
),
configuration: buildConfiguration,
toolchain: swiftPMToolchain,
toolchain: hostSwiftPMToolchain,
flags: buildFlags
)

self.destinationBuildParameters = try BuildParameters(
destination: .target,
dataPath: location.scratchDirectory.appending(
component: swiftPMToolchain.targetTriple.platformBuildPathComponent
component: destinationSwiftPMToolchain.targetTriple.platformBuildPathComponent
),
configuration: buildConfiguration,
toolchain: swiftPMToolchain,
toolchain: destinationSwiftPMToolchain,
triple: destinationSDK.targetTriple,
flags: buildFlags
)

Expand Down
49 changes: 49 additions & 0 deletions Tests/SourceKitLSPTests/SwiftPMIntegration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,53 @@ final class SwiftPMIntegrationTests: XCTestCase {
]
)
}

func testWasm() async throws {
let project = try await SwiftPMTestProject(
files: [
"/.sourcekit-lsp/config.json": """
{
"swiftPM": {
"triple": "wasm32-unknown-none-wasm"
}
}
""",
"Test.swift": """
#if arch(wasm32)
let _: UnsafeRawPointer = 1
#endif
""",
],
manifest: """
let package = Package(
name: "WasmTest",
targets: [
.executableTarget(
name: "wasmTest",
cSettings: [.unsafeFlags(["-fdeclspec"])],
swiftSettings: [
.enableExperimentalFeature("Embedded"),
.interoperabilityMode(.Cxx),
.unsafeFlags(["-wmo", "-disable-cmo", "-Xfrontend", "-gnone"]),
],
linkerSettings: [.unsafeFlags(["-Xclang-linker", "-nostdlib", "-Xlinker", "--no-entry"])]
)
]
)
"""
)

let (uri, _) = try project.openDocument("Test.swift")
let diagnostics = try await project.testClient.send(
DocumentDiagnosticsRequest(textDocument: TextDocumentIdentifier(uri))
)
guard case .full(let diagnostics) = diagnostics else {
XCTFail("Expected full diagnostics report")
return
}
XCTAssertEqual(
diagnostics.items.map(\.message),
["Cannot convert value of type 'Int' to specified type 'UnsafeRawPointer'"]
)
}
}

0 comments on commit 935120b

Please sign in to comment.