Skip to content

Commit c27d394

Browse files
committed
Add external dependency placeholder resolution test
1 parent 93f4293 commit c27d394

File tree

6 files changed

+274
-12
lines changed

6 files changed

+274
-12
lines changed

Sources/SwiftDriver/Explicit Module Builds/ExplicitModuleBuildHandler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public typealias ExternalDependencyArtifactMap =
129129
var mainModuleCommandLine: [Job.ArgTemplate] = []
130130
try resolveMainModuleDependencies(inputs: &mainModuleInputs,
131131
commandLine: &mainModuleCommandLine)
132-
132+
133133
return Array(swiftModuleBuildCache.values) + clangTargetModuleBuildCache.allJobs
134134
}
135135

Sources/SwiftDriver/Explicit Module Builds/InterModuleDependencyGraph.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ public struct SwiftModuleDetails: Codable {
7878
public var compiledModuleCandidates: [String]?
7979

8080
/// The path to the already-compiled module that must be used instead of
81-
/// generating a job to build this module.
81+
/// generating a job to build this module. In standard compilation, the dependency scanner
82+
/// may discover compiled module candidates to be used instead of re-compiling from interface.
83+
/// In contrast, this explicitCompiledModulePath is only to be used for precompiled modules
84+
/// external dependencies in Explicit Module Build mode
8285
public var explicitCompiledModulePath: String?
8386

8487
/// The bridging header, if any.

Sources/SwiftDriver/Explicit Module Builds/PlaceholderDependencyResolution.swift

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,15 @@ extension ExplicitModuleBuildHandler {
6464
mutating public func resolvePlaceholderDependency(placeholderModulePath: AbsolutePath,
6565
placeholderDependencyGraph: InterModuleDependencyGraph)
6666
throws {
67-
// For every other module in the placeholder dependency graph, generate a new module info
67+
// For every Swift module in the placeholder dependency graph, generate a new module info
6868
// containing only the pre-compiled module path, and insert it into the current module's
6969
// dependency graph, replacing equivalent (non pre-built) modules, if necessary.
70+
//
71+
// For every Clang module in the placeholder dependency graph, because PCM modules file names
72+
// encode the specific pcmArguments of their dependees, we cannot use pre-built files here
73+
// because we do not always know which target they corrspond to, nor do we have a way to map
74+
// from a certain target to a specific pcm file. Because of this, all PCM dependencies, direct
75+
// and transitive, have to be built for all modules.
7076
for (moduleId, moduleInfo) in placeholderDependencyGraph.modules {
7177
switch moduleId {
7278
case .swift(_):
@@ -75,7 +81,6 @@ extension ExplicitModuleBuildHandler {
7581
// If this module is any other swift module, then the compiled module path is
7682
// a part of the details field.
7783
// Otherwise (for most other dependencies), it is the modulePath of the moduleInfo node.
78-
// FIXME: Will the `else` case ever happen?
7984
let compiledModulePath : String
8085
if moduleId.moduleName == placeholderDependencyGraph.mainModuleName {
8186
compiledModulePath = placeholderModulePath.description
@@ -88,19 +93,12 @@ extension ExplicitModuleBuildHandler {
8893

8994
let swiftDetails =
9095
SwiftModuleDetails(compiledModulePath: compiledModulePath)
91-
print("For module: \(moduleId.moduleName) set the path to:\n\(compiledModulePath)")
9296
let newInfo = ModuleInfo(modulePath: moduleInfo.modulePath.description,
9397
sourceFiles: nil,
9498
directDependencies: moduleInfo.directDependencies,
9599
details: ModuleInfo.Details.swift(swiftDetails))
96100
try insertOrReplaceModule(moduleId: moduleId, moduleInfo: newInfo)
97-
print("New Info: \(newInfo)")
98101
case .clang(_):
99-
// Because PCM modules file names encode the specific pcmArguments of their dependees,
100-
// we cannot use pre-built files here because we do not always know which target
101-
// they corrspond to, nor do we have a way to map from a certain target to a specific
102-
// pcm file. Because of this, all PCM dependencies, direct and transitive, have to be
103-
// built for all modules.
104102
if dependencyGraph.modules[moduleId] == nil {
105103
dependencyGraph.modules[moduleId] = moduleInfo
106104
}

Sources/SwiftDriver/Jobs/EmitModuleJob.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ extension Driver {
4343
}
4444

4545
/// Form a job that emits a single module
46-
mutating func emitModuleJob() throws -> Job {
46+
@_spi(Testing) public mutating func emitModuleJob() throws -> Job {
4747
let moduleOutputPath = moduleOutputInfo.output!.outputPath
4848
var commandLine: [Job.ArgTemplate] = swiftCompilerPrefixArgs.map { Job.ArgTemplate.flag($0) }
4949
var inputs: [TypedVirtualPath] = []

Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,79 @@ final class ExplicitModuleBuildTests: XCTestCase {
166166
}
167167
}
168168

169+
func testModuleDependencyWithExternalCommandGeneration() throws {
170+
do {
171+
// Construct a faux external dependency input for module B
172+
let inputDependencyGraph =
173+
try JSONDecoder().decode(
174+
InterModuleDependencyGraph.self,
175+
from: ModuleDependenciesInputs.bPlaceHolderInput.data(using: .utf8)!)
176+
var targetDependencyMap :[ModuleDependencyId: (AbsolutePath, InterModuleDependencyGraph)] = [:]
177+
targetDependencyMap[ModuleDependencyId.swiftPlaceholder("B")] =
178+
(AbsolutePath("/Somewhere/B.swiftmodule"), inputDependencyGraph)
179+
180+
// Construct a module dependency graph that will contain .swiftPlaceholder("B")
181+
let moduleDependencyGraph =
182+
try JSONDecoder().decode(
183+
InterModuleDependencyGraph.self,
184+
from: ModuleDependenciesInputs.fastDependencyScannerPlaceholderOutput.data(using: .utf8)!)
185+
186+
// Construct the driver with explicit external dependency input
187+
var commandLine = ["swiftc", "-driver-print-module-dependencies-jobs",
188+
"test.swift", "-module-name", "A", "-g"]
189+
commandLine.append("-experimental-explicit-module-build")
190+
let executor = try SwiftDriverExecutor(diagnosticsEngine: DiagnosticsEngine(handlers: [Driver.stderrDiagnosticsHandler]),
191+
processSet: ProcessSet(),
192+
fileSystem: localFileSystem,
193+
env: ProcessEnv.vars)
194+
var driver = try Driver(args: commandLine, executor: executor,
195+
externalModuleDependencies: targetDependencyMap)
196+
197+
198+
// Plan explicit dependency jobs, resolving placeholders to actual dependencies.
199+
driver.explicitModuleBuildHandler = try ExplicitModuleBuildHandler(dependencyGraph: moduleDependencyGraph,
200+
toolchain: driver.toolchain,
201+
fileSystem: localFileSystem,
202+
externalDependencyArtifactMap: targetDependencyMap)
203+
let modulePrebuildJobs =
204+
try driver.explicitModuleBuildHandler!.generateExplicitModuleDependenciesBuildJobs()
205+
206+
// Verify that the dependency graph contains only 1 module to be built.
207+
for (moduleId, _) in driver.interModuleDependencyGraph!.modules {
208+
switch moduleId {
209+
case .swift(_):
210+
continue
211+
case .clang(_):
212+
continue
213+
case .swiftPlaceholder(_):
214+
XCTFail("Placeholder dependency found.")
215+
}
216+
}
217+
218+
// After module resolution all the dependencies are already satisfied.
219+
XCTAssertEqual(modulePrebuildJobs.count, 0)
220+
let mainModuleJob = try driver.emitModuleJob()
221+
XCTAssertEqual(mainModuleJob.inputs.count, 5)
222+
for input in mainModuleJob.inputs {
223+
switch (input.file) {
224+
case .relative(RelativePath("M/Swift.swiftmodule")):
225+
continue
226+
case .relative(RelativePath("S/SwiftOnoneSupport.swiftmodule")):
227+
continue
228+
case .relative(RelativePath("test.swift")):
229+
continue
230+
case .absolute(AbsolutePath("/Somewhere/B.swiftmodule")):
231+
continue
232+
case .absolute(let filePath):
233+
XCTAssertEqual(filePath.basename, "A-dependencies.json")
234+
continue
235+
default:
236+
XCTFail("Unexpected module input: \(input.file)")
237+
}
238+
}
239+
}
240+
}
241+
169242
/// Test generation of explicit module build jobs for dependency modules when the driver
170243
/// is invoked with -experimental-explicit-module-build
171244
func testExplicitModuleBuildJobs() throws {

Tests/SwiftDriverTests/Inputs/ExplicitModuleDependencyBuildInputs.swift

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,4 +242,192 @@ enum ModuleDependenciesInputs {
242242
}
243243
"""
244244
}
245+
246+
static var fastDependencyScannerPlaceholderOutput: String {
247+
"""
248+
{
249+
"mainModuleName": "A",
250+
"modules": [
251+
{
252+
"swift": "A"
253+
},
254+
{
255+
"modulePath": "A.swiftmodule",
256+
"sourceFiles": [
257+
"main.swift",
258+
"A.swift"
259+
],
260+
"directDependencies": [
261+
{
262+
"swiftPlaceholder": "B"
263+
},
264+
{
265+
"swift": "Swift"
266+
},
267+
{
268+
"swift": "SwiftOnoneSupport"
269+
}
270+
],
271+
"details": {
272+
"swift": {
273+
"extraPcmArgs": [
274+
"-Xcc",
275+
"-target",
276+
"-Xcc",
277+
"x86_64-apple-macosx10.10",
278+
"-Xcc",
279+
"-fapinotes-swift-version=5"
280+
]
281+
}
282+
}
283+
},
284+
{
285+
"swiftPlaceholder": "B"
286+
},
287+
{
288+
"modulePath": "/Volumes/Data/Current/Driver/ExplicitPMTest/.build/x86_64-apple-macosx/debug/B.swiftmodule",
289+
"details": {
290+
"swiftPlaceholder": {
291+
}
292+
}
293+
},
294+
{
295+
"swift": "Swift"
296+
},
297+
{
298+
"modulePath": "Swift.swiftmodule",
299+
"sourceFiles": [
300+
],
301+
"directDependencies": [
302+
],
303+
"details": {
304+
"swift": {
305+
"moduleInterfacePath": "Swift.swiftmodule/x86_64-apple-macos.swiftinterface",
306+
"contextHash": "30OCBGKPNG64V",
307+
"commandLine": [
308+
"-frontend",
309+
"-compile-module-from-interface",
310+
"-target",
311+
"x86_64-apple-macosx10.10",
312+
"-swift-version",
313+
"5",
314+
"-module-name",
315+
"Swift"
316+
],
317+
"compiledModuleCandidates": [
318+
],
319+
"extraPcmArgs": [
320+
"-Xcc",
321+
"-target",
322+
"-Xcc",
323+
"x86_64-apple-macosx10.9",
324+
"-Xcc",
325+
"-fapinotes-swift-version=5"
326+
]
327+
}
328+
}
329+
},
330+
{
331+
"swift": "SwiftOnoneSupport"
332+
},
333+
{
334+
"modulePath": "SwiftOnoneSupport.swiftmodule",
335+
"sourceFiles": [
336+
],
337+
"directDependencies": [
338+
{
339+
"swift": "Swift"
340+
}
341+
],
342+
"details": {
343+
"swift": {
344+
"moduleInterfacePath": "SwiftOnoneSupport.swiftmodule/x86_64-apple-macos.swiftinterface",
345+
"contextHash": "3GKS4RKE3GDZA",
346+
"commandLine": [
347+
"-frontend",
348+
"-compile-module-from-interface",
349+
"-target",
350+
"x86_64-apple-macosx10.10",
351+
"-swift-version",
352+
"5",
353+
"-module-name",
354+
"SwiftOnoneSupport"
355+
]
356+
}
357+
}
358+
}
359+
]
360+
}
361+
"""
362+
}
363+
364+
static var bPlaceHolderInput: String {
365+
"""
366+
{
367+
"mainModuleName": "B",
368+
"modules": [
369+
{
370+
"swift": "B"
371+
},
372+
{
373+
"modulePath": "B.swiftmodule",
374+
"sourceFiles": [
375+
"/B/B.swift"
376+
],
377+
"directDependencies": [
378+
{
379+
"swift": "Swift"
380+
},
381+
{
382+
"swift": "SwiftOnoneSupport"
383+
}
384+
],
385+
"details": {
386+
"swift": {
387+
"extraPcmArgs": [
388+
"-Xcc",
389+
"-target",
390+
"-Xcc",
391+
"x86_64-apple-macosx10.10",
392+
"-Xcc",
393+
"-fapinotes-swift-version=5"
394+
]
395+
}
396+
}
397+
},
398+
{
399+
"swift" : "Swift"
400+
},
401+
{
402+
"modulePath" : "Swift.swiftmodule",
403+
"directDependencies" : [
404+
],
405+
"details" : {
406+
"swift" : {
407+
"explicitCompiledModulePath" : "M/Swift.swiftmodule"
408+
}
409+
}
410+
},
411+
{
412+
"swift" : "SwiftOnoneSupport"
413+
},
414+
{
415+
"modulePath" : "SwiftOnoneSupport.swiftmodule",
416+
"directDependencies" : [
417+
{
418+
"swift" : "Swift"
419+
}
420+
],
421+
"details" : {
422+
"swift" : {
423+
"explicitCompiledModulePath" : "S/SwiftOnoneSupport.swiftmodule"
424+
}
425+
}
426+
}
427+
]
428+
}
429+
"""
430+
}
245431
}
432+
433+

0 commit comments

Comments
 (0)