@@ -17,12 +17,27 @@ import SwiftExtensions
1717package import BuildServerProtocol
1818package import Foundation
1919package import LanguageServerProtocol
20+ package import ToolchainRegistry
2021#else
2122import BuildServerProtocol
2223import Foundation
2324import LanguageServerProtocol
25+ import ToolchainRegistry
2426#endif
2527
28+ fileprivate extension CompilationDatabaseCompileCommand {
29+ /// The first entry in the command line identifies the compiler that should be used to compile the file and can thus
30+ /// be used to infer the toolchain.
31+ ///
32+ /// Note that this compiler does not necessarily need to exist on disk. Eg. tools may just use `clang` as the compiler
33+ /// without specifying a path.
34+ ///
35+ /// The absence of a compiler means we have an empty command line, which should never happen.
36+ var compiler : String ? {
37+ return commandLine. first
38+ }
39+ }
40+
2641/// A `BuildSystem` that provides compiler arguments from a `compile_commands.json` file.
2742package actor JSONCompilationDatabaseBuildSystem : BuiltInBuildSystem {
2843 package static let dbName : String = " compile_commands.json "
@@ -36,6 +51,8 @@ package actor JSONCompilationDatabaseBuildSystem: BuiltInBuildSystem {
3651 }
3752 }
3853
54+ private let toolchainRegistry : ToolchainRegistry
55+
3956 private let connectionToSourceKitLSP : any Connection
4057
4158 package let configPath : URL
@@ -73,34 +90,55 @@ package actor JSONCompilationDatabaseBuildSystem: BuiltInBuildSystem {
7390
7491 package init (
7592 configPath: URL ,
93+ toolchainRegistry: ToolchainRegistry ,
7694 connectionToSourceKitLSP: any Connection
7795 ) throws {
7896 self . compdb = try JSONCompilationDatabase ( file: configPath)
97+ self . toolchainRegistry = toolchainRegistry
7998 self . connectionToSourceKitLSP = connectionToSourceKitLSP
80-
8199 self . configPath = configPath
82100 }
83101
84102 package func buildTargets( request: WorkspaceBuildTargetsRequest ) async throws -> WorkspaceBuildTargetsResponse {
85- return WorkspaceBuildTargetsResponse ( targets: [
86- BuildTarget (
87- id: . dummy,
103+ let compilers = Set ( compdb. commands. compactMap ( \. compiler) ) . sorted { $0 < $1 }
104+ let targets = try await compilers. asyncMap { compiler in
105+ let toolchainUri : URI ? =
106+ if let toolchainPath = await toolchainRegistry. toolchain ( withCompiler: URL ( fileURLWithPath: compiler) ) ? . path {
107+ URI ( toolchainPath)
108+ } else {
109+ nil
110+ }
111+ return BuildTarget (
112+ id: try BuildTargetIdentifier . createCompileCommands ( compiler: compiler) ,
88113 displayName: nil ,
89114 baseDirectory: nil ,
90115 tags: [ . test] ,
91116 capabilities: BuildTargetCapabilities ( ) ,
92117 // Be conservative with the languages that might be used in the target. SourceKit-LSP doesn't use this property.
93118 languageIds: [ . c, . cpp, . objective_c, . objective_cpp, . swift] ,
94- dependencies: [ ]
119+ dependencies: [ ] ,
120+ dataKind: . sourceKit,
121+ data: SourceKitBuildTarget ( toolchain: toolchainUri) . encodeToLSPAny ( )
95122 )
96- ] )
123+ }
124+ return WorkspaceBuildTargetsResponse ( targets: targets)
97125 }
98126
99127 package func buildTargetSources( request: BuildTargetSourcesRequest ) async throws -> BuildTargetSourcesResponse {
100- guard request. targets. contains ( . dummy) else {
101- return BuildTargetSourcesResponse ( items: [ ] )
128+ let items = request. targets. compactMap { ( target) -> SourcesItem ? in
129+ guard let targetCompiler = orLog ( " Compiler for target " , { try target. compileCommandsCompiler } ) else {
130+ return nil
131+ }
132+ let commandsWithRequestedCompilers = compdb. commands. lazy. filter { command in
133+ return targetCompiler == command. compiler
134+ }
135+ let sources = commandsWithRequestedCompilers. map {
136+ SourceItem ( uri: $0. uri, kind: . file, generated: false )
137+ }
138+ return SourcesItem ( target: target, sources: Array ( sources) )
102139 }
103- return BuildTargetSourcesResponse ( items: [ SourcesItem ( target: . dummy, sources: compdb. sourceItems) ] )
140+
141+ return BuildTargetSourcesResponse ( items: items)
104142 }
105143
106144 package func didChangeWatchedFiles( notification: OnWatchedFilesDidChangeNotification ) {
@@ -116,12 +154,16 @@ package actor JSONCompilationDatabaseBuildSystem: BuiltInBuildSystem {
116154 package func sourceKitOptions(
117155 request: TextDocumentSourceKitOptionsRequest
118156 ) async throws -> TextDocumentSourceKitOptionsResponse ? {
119- guard let cmd = compdb [ request. textDocument. uri] . first else {
157+ let targetCompiler = try request. target. compileCommandsCompiler
158+ let command = compdb [ request. textDocument. uri] . filter {
159+ $0. compiler == targetCompiler
160+ } . first
161+ guard let command else {
120162 return nil
121163 }
122164 return TextDocumentSourceKitOptionsResponse (
123- compilerArguments: Array ( cmd . commandLine. dropFirst ( ) ) ,
124- workingDirectory: cmd . directory
165+ compilerArguments: Array ( command . commandLine. dropFirst ( ) ) ,
166+ workingDirectory: command . directory
125167 )
126168 }
127169
0 commit comments