Skip to content

Conversation

owenv
Copy link
Contributor

@owenv owenv commented Sep 11, 2025

Add a swift package bsp command which builds on the Swift Build BSP interface to provide preparation + compiler args for packages as an out of process build server.

@owenv
Copy link
Contributor Author

owenv commented Sep 11, 2025

This is very much a WIP right now, it just exposes the bare minimum functionality so we can discuss API design

func run(_ swiftCommandState: SwiftCommandState) async throws {
// Dup stdout and redirect the fd to stderr so that a careless print()
// will not break our connection stream.
let realStdout = dup(STDOUT_FILENO)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We depend on Swift System, right? I suggest using FileDescriptor.duplicate cover API and not going straight down to POSIX.

IIRC there's also some oddities with the Windows versions of dup which System should be able to help smooth over.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, we’re doing this in SourceKit-LSP and it hasn’t caused any issues so far.

Comment on lines +772 to +773
indexRegularBuildProductsPath: ddPathPrefix + "/Index/Products",
indexRegularBuildIntermediatesPath: ddPathPrefix + "/Index/Intermediates.noindex",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name is a little confusing here, but FWIW this is actually meant to be swapped for the index arena 😅 - the build products/intermediate paths would be the index arena and the "index regular" paths the regular build. It's also only used for adding an overlay to fallback to the build, which we don't necessarily need.


guard let buildSystem = try await swiftCommandState.createBuildSystem() as? SwiftBuildSystem else {
print("Build server requires --build-system swiftbuild")
Self.exit()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should exit with whatever error SwiftArgumentParser exits with when validate() fails

}
)

// Park the main function by sleeping for 10 years.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaner solution?

await withCheckedContinuation { continuation in
    clientConnection.start(
       receiveHandler: server,
        closeHandler: {
            continuation.resume()
        }
    )
}

@owenv owenv force-pushed the owenv/bsp branch 2 times, most recently from 36c58fd to fda8c7b Compare September 12, 2025 00:27
func run(_ swiftCommandState: SwiftCommandState) async throws {
// Dup stdout and redirect the fd to stderr so that a careless print()
// will not break our connection stream.
let realStdout = dup(STDOUT_FILENO)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, we’re doing this in SourceKit-LSP and it hasn’t caused any issues so far.

case let request as RequestAndReply<BuildTargetPrepareRequest>:
await request.reply {
for target in request.params.targets.filter({ $0.isSwiftPMBuildServerTargetID }) {
// Error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn’t an error. SourceKit-LSP will eg. ask for the package manifest target to be prepared, it’s just that there’s nothing to do, so the BSP server can return immediately.

Comment on lines +164 to +165
await request.reply {
await waitForBuildSystemUpdates(request: request.params)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you also need to wait for updates of the underlying build server?

// TODO: this is overly conservative
return true
case .changed:
// TODO: check for changes to version specific manifests too
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, I added support for version-specific package manifests in SourceKit-LSP’s built-in SwiftPM build server in swiftlang/sourcekit-lsp#2259.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants