Skip to content

Commit 524f795

Browse files
committed
Add external dependency placeholder resolution test
1 parent 1c7e032 commit 524f795

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
@@ -156,6 +156,79 @@ final class ExplicitModuleBuildTests: XCTestCase {
156156
}
157157
}
158158

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

Tests/SwiftDriverTests/Inputs/ExplicitModuleDependencyBuildInputs.swift

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

0 commit comments

Comments
 (0)