@@ -31,9 +31,23 @@ public struct ExplicitModuleBuildHandler {
31
31
/// The toolchain to be used for frontend job generation.
32
32
private let toolchain : Toolchain
33
33
34
- public init ( dependencyGraph: InterModuleDependencyGraph , toolchain: Toolchain ) throws {
34
+ /// The file system which we should interact with.
35
+ private let fileSystem : FileSystem
36
+
37
+ /// Path to the directory that will contain the temporary files.
38
+ /// e.g. Explicit Swift module artifact files
39
+ private let temporaryDirectory : AbsolutePath
40
+
41
+ public init ( dependencyGraph: InterModuleDependencyGraph , toolchain: Toolchain ,
42
+ fileSystem: FileSystem ) throws {
35
43
self . dependencyGraph = dependencyGraph
36
44
self . toolchain = toolchain
45
+ self . fileSystem = fileSystem
46
+ self . temporaryDirectory = try withTemporaryDirectory ( removeTreeOnDeinit: false ) { path in
47
+ // FIXME: TSC removes empty directories even when removeTreeOnDeinit is false. This seems like a bug.
48
+ try fileSystem. writeFileContents ( path. appending ( component: " .keep-directory " ) ) { $0 <<< " " }
49
+ return path
50
+ }
37
51
}
38
52
39
53
/// Generate build jobs for all dependencies of the main module.
@@ -207,6 +221,19 @@ public struct ExplicitModuleBuildHandler {
207
221
)
208
222
}
209
223
224
+ /// Store the output file artifacts for a given module in a JSON file, return the file's path.
225
+ private func serializeModuleDependencies( for moduleId: ModuleDependencyId ,
226
+ dependencyArtifacts: [ SwiftModuleArtifactInfo ]
227
+ ) throws -> AbsolutePath {
228
+ let dependencyFilePath =
229
+ temporaryDirectory. appending ( component: " \( moduleId. moduleName) -dependencies.json " )
230
+ let encoder = JSONEncoder ( )
231
+ encoder. outputFormatting = [ . prettyPrinted]
232
+ let contents = try encoder. encode ( dependencyArtifacts)
233
+ try fileSystem. writeFileContents ( dependencyFilePath, bytes: ByteString ( contents) )
234
+ return dependencyFilePath
235
+ }
236
+
210
237
/// For the specified module, update the given command line flags and inputs
211
238
/// to use explicitly-built module dependencies.
212
239
///
@@ -217,27 +244,43 @@ public struct ExplicitModuleBuildHandler {
217
244
inputs: inout [ TypedVirtualPath ] ,
218
245
commandLine: inout [ Job . ArgTemplate ]
219
246
) throws {
247
+
220
248
// Prohibit the frontend from implicitly building textual modules into binary modules.
221
249
commandLine. appendFlags ( " -disable-implicit-swift-modules " , " -Xcc " , " -Xclang " , " -Xcc " ,
222
250
" -fno-implicit-modules " )
251
+ var swiftDependencyArtifacts : [ SwiftModuleArtifactInfo ] = [ ]
223
252
try addModuleDependencies ( moduleId: moduleId, pcmArgs: pcmArgs, inputs: & inputs,
224
- commandLine: & commandLine)
253
+ commandLine: & commandLine,
254
+ swiftDependencyArtifacts: & swiftDependencyArtifacts)
255
+
256
+ if ( swiftDependencyArtifacts. isEmpty) {
257
+ let dependencyFile = try serializeModuleDependencies ( for: moduleId,
258
+ dependencyArtifacts: swiftDependencyArtifacts)
259
+ commandLine. appendFlag ( " -explicit-swift-module-map-file " )
260
+ commandLine. appendPath ( dependencyFile)
261
+ inputs. append ( TypedVirtualPath ( file: try VirtualPath ( path: dependencyFile. pathString) ,
262
+ type: . jsonSwiftArtifacts) )
263
+ }
225
264
}
226
265
227
266
/// Add a specific module dependency as an input and a corresponding command
228
267
/// line flag. Dispatches to clang and swift-specific variants.
229
268
mutating private func addModuleDependencies( moduleId: ModuleDependencyId ,
230
269
pcmArgs: [ String ] ,
231
270
inputs: inout [ TypedVirtualPath ] ,
232
- commandLine: inout [ Job . ArgTemplate ] ) throws {
271
+ commandLine: inout [ Job . ArgTemplate ] ,
272
+ swiftDependencyArtifacts: inout [ SwiftModuleArtifactInfo ]
273
+ ) throws {
233
274
for dependencyId in try dependencyGraph. moduleInfo ( of: moduleId) . directDependencies {
234
275
switch dependencyId {
235
276
case . swift:
236
277
try addSwiftModuleDependency ( moduleId: moduleId, dependencyId: dependencyId,
237
- pcmArgs: pcmArgs, inputs: & inputs, commandLine: & commandLine)
278
+ pcmArgs: pcmArgs, inputs: & inputs, commandLine: & commandLine,
279
+ swiftDependencyArtifacts: & swiftDependencyArtifacts)
238
280
case . clang:
239
281
try addClangModuleDependency ( moduleId: moduleId, dependencyId: dependencyId,
240
- pcmArgs: pcmArgs, inputs: & inputs, commandLine: & commandLine)
282
+ pcmArgs: pcmArgs, inputs: & inputs, commandLine: & commandLine,
283
+ swiftDependencyArtifacts: & swiftDependencyArtifacts)
241
284
}
242
285
}
243
286
}
@@ -250,7 +293,9 @@ public struct ExplicitModuleBuildHandler {
250
293
dependencyId: ModuleDependencyId ,
251
294
pcmArgs: [ String ] ,
252
295
inputs: inout [ TypedVirtualPath ] ,
253
- commandLine: inout [ Job . ArgTemplate ] ) throws {
296
+ commandLine: inout [ Job . ArgTemplate ] ,
297
+ swiftDependencyArtifacts: inout [ SwiftModuleArtifactInfo ]
298
+ ) throws {
254
299
// Generate a build job for the dependency module, if not already generated
255
300
if swiftModuleBuildCache [ dependencyId] == nil {
256
301
try genSwiftModuleBuildJob ( moduleId: dependencyId)
@@ -261,13 +306,17 @@ public struct ExplicitModuleBuildHandler {
261
306
let dependencyInfo = try dependencyGraph. moduleInfo ( of: dependencyId)
262
307
let swiftModulePath = TypedVirtualPath ( file: try VirtualPath ( path: dependencyInfo. modulePath) ,
263
308
type: . swiftModule)
264
- commandLine. appendFlags ( " -swift-module-file " )
265
- commandLine. appendPath ( swiftModulePath. file)
266
- inputs. append ( swiftModulePath)
309
+
310
+ // Collect the requried information about this module
311
+ // TODO: add .swiftdoc and .swiftsourceinfo for this module.
312
+ swiftDependencyArtifacts. append (
313
+ SwiftModuleArtifactInfo ( name: dependencyId. moduleName,
314
+ modulePath: swiftModulePath. file. description) )
267
315
268
316
// Process all transitive dependencies as direct
269
- try addModuleDependencies ( moduleId: dependencyId, pcmArgs: pcmArgs, inputs: & inputs,
270
- commandLine: & commandLine)
317
+ try addModuleDependencies ( moduleId: dependencyId, pcmArgs: pcmArgs,
318
+ inputs: & inputs, commandLine: & commandLine,
319
+ swiftDependencyArtifacts: & swiftDependencyArtifacts)
271
320
}
272
321
273
322
/// Add a specific Clang module dependency as an input and a corresponding command
@@ -278,7 +327,9 @@ public struct ExplicitModuleBuildHandler {
278
327
dependencyId: ModuleDependencyId ,
279
328
pcmArgs: [ String ] ,
280
329
inputs: inout [ TypedVirtualPath ] ,
281
- commandLine: inout [ Job . ArgTemplate ] ) throws {
330
+ commandLine: inout [ Job . ArgTemplate ] ,
331
+ swiftDependencyArtifacts: inout [ SwiftModuleArtifactInfo ]
332
+ ) throws {
282
333
// Generate a build job for the dependency module at the given target, if not already generated
283
334
if clangTargetModuleBuildCache [ ( dependencyId, pcmArgs) ] == nil {
284
335
try genClangModuleBuildJob ( moduleId: dependencyId, pcmArgs: pcmArgs)
@@ -302,8 +353,9 @@ public struct ExplicitModuleBuildHandler {
302
353
inputs. append ( clangModuleMapPath)
303
354
304
355
// Process all transitive dependencies as direct
305
- try addModuleDependencies ( moduleId: dependencyId, pcmArgs: pcmArgs, inputs: & inputs,
306
- commandLine: & commandLine)
356
+ try addModuleDependencies ( moduleId: dependencyId, pcmArgs: pcmArgs,
357
+ inputs: & inputs, commandLine: & commandLine,
358
+ swiftDependencyArtifacts: & swiftDependencyArtifacts)
307
359
}
308
360
}
309
361
0 commit comments