@@ -17,12 +17,27 @@ import SwiftExtensions
17
17
package import BuildServerProtocol
18
18
package import Foundation
19
19
package import LanguageServerProtocol
20
+ package import ToolchainRegistry
20
21
#else
21
22
import BuildServerProtocol
22
23
import Foundation
23
24
import LanguageServerProtocol
25
+ import ToolchainRegistry
24
26
#endif
25
27
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
+
26
41
/// A `BuildSystem` that provides compiler arguments from a `compile_commands.json` file.
27
42
package actor JSONCompilationDatabaseBuildSystem : BuiltInBuildSystem {
28
43
package static let dbName : String = " compile_commands.json "
@@ -36,6 +51,8 @@ package actor JSONCompilationDatabaseBuildSystem: BuiltInBuildSystem {
36
51
}
37
52
}
38
53
54
+ private let toolchainRegistry : ToolchainRegistry
55
+
39
56
private let connectionToSourceKitLSP : any Connection
40
57
41
58
package let configPath : URL
@@ -73,34 +90,55 @@ package actor JSONCompilationDatabaseBuildSystem: BuiltInBuildSystem {
73
90
74
91
package init (
75
92
configPath: URL ,
93
+ toolchainRegistry: ToolchainRegistry ,
76
94
connectionToSourceKitLSP: any Connection
77
95
) throws {
78
96
self . compdb = try JSONCompilationDatabase ( file: configPath)
97
+ self . toolchainRegistry = toolchainRegistry
79
98
self . connectionToSourceKitLSP = connectionToSourceKitLSP
80
-
81
99
self . configPath = configPath
82
100
}
83
101
84
102
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) ,
88
113
displayName: nil ,
89
114
baseDirectory: nil ,
90
115
tags: [ . test] ,
91
116
capabilities: BuildTargetCapabilities ( ) ,
92
117
// Be conservative with the languages that might be used in the target. SourceKit-LSP doesn't use this property.
93
118
languageIds: [ . c, . cpp, . objective_c, . objective_cpp, . swift] ,
94
- dependencies: [ ]
119
+ dependencies: [ ] ,
120
+ dataKind: . sourceKit,
121
+ data: SourceKitBuildTarget ( toolchain: toolchainUri) . encodeToLSPAny ( )
95
122
)
96
- ] )
123
+ }
124
+ return WorkspaceBuildTargetsResponse ( targets: targets)
97
125
}
98
126
99
127
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) )
102
139
}
103
- return BuildTargetSourcesResponse ( items: [ SourcesItem ( target: . dummy, sources: compdb. sourceItems) ] )
140
+
141
+ return BuildTargetSourcesResponse ( items: items)
104
142
}
105
143
106
144
package func didChangeWatchedFiles( notification: OnWatchedFilesDidChangeNotification ) {
@@ -116,12 +154,16 @@ package actor JSONCompilationDatabaseBuildSystem: BuiltInBuildSystem {
116
154
package func sourceKitOptions(
117
155
request: TextDocumentSourceKitOptionsRequest
118
156
) 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 {
120
162
return nil
121
163
}
122
164
return TextDocumentSourceKitOptionsResponse (
123
- compilerArguments: Array ( cmd . commandLine. dropFirst ( ) ) ,
124
- workingDirectory: cmd . directory
165
+ compilerArguments: Array ( command . commandLine. dropFirst ( ) ) ,
166
+ workingDirectory: command . directory
125
167
)
126
168
}
127
169
0 commit comments