Skip to content

Commit 4b99005

Browse files
Add test for explicit-module interface verification
1 parent 96bb4b9 commit 4b99005

File tree

2 files changed

+260
-0
lines changed

2 files changed

+260
-0
lines changed

Tests/SwiftDriverTests/CachingBuildTests.swift

+132
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,138 @@ final class CachingBuildTests: XCTestCase {
270270
}
271271
}
272272

273+
/// Test generation of explicit module build jobs for dependency modules when the driver
274+
/// is invoked with -explicit-module-build, -verify-emitted-module-interface and -enable-library-evolution.
275+
func testExplicitModuleVerifyInterfaceJobs() throws {
276+
try withTemporaryDirectory { path in
277+
let main = path.appending(component: "testExplicitModuleVerifyInterfaceJobs.swift")
278+
try localFileSystem.writeFileContents(main) {
279+
$0 <<< "import C;"
280+
$0 <<< "import E;"
281+
$0 <<< "import G;"
282+
}
283+
284+
let swiftModuleInterfacesPath: AbsolutePath =
285+
testInputsPath.appending(component: "ExplicitModuleBuilds")
286+
.appending(component: "Swift")
287+
let cHeadersPath: AbsolutePath =
288+
testInputsPath.appending(component: "ExplicitModuleBuilds")
289+
.appending(component: "CHeaders")
290+
let casPath = path.appending(component: "cas")
291+
let swiftInterfacePath: AbsolutePath = path.appending(component: "testExplicitModuleVerifyInterfaceJobs.swiftinterface")
292+
let privateSwiftInterfacePath: AbsolutePath = path.appending(component: "testExplicitModuleVerifyInterfaceJobs.private.swiftinterface")
293+
let sdkArgumentsForTesting = (try? Driver.sdkArgumentsForTesting()) ?? []
294+
var driver = try Driver(args: ["swiftc",
295+
"-target", "x86_64-apple-macosx11.0",
296+
"-I", cHeadersPath.nativePathString(escaped: true),
297+
"-I", swiftModuleInterfacesPath.nativePathString(escaped: true),
298+
"-emit-module-interface-path", swiftInterfacePath.nativePathString(escaped: true),
299+
"-emit-private-module-interface-path", privateSwiftInterfacePath.nativePathString(escaped: true),
300+
"-explicit-module-build", "-verify-emitted-module-interface",
301+
"-enable-library-evolution",
302+
"-cache-compile-job", "-cas-path", casPath.nativePathString(escaped: true),
303+
main.nativePathString(escaped: true)] + sdkArgumentsForTesting)
304+
305+
let jobs = try driver.planBuild()
306+
// Figure out which Triples to use.
307+
let dependencyGraph = try driver.gatherModuleDependencies()
308+
let mainModuleInfo = try dependencyGraph.moduleInfo(of: .swift("testExplicitModuleVerifyInterfaceJobs"))
309+
guard case .swift(_) = mainModuleInfo.details else {
310+
XCTFail("Main module does not have Swift details field")
311+
return
312+
}
313+
314+
for job in jobs {
315+
if (job.outputs.count == 0) {
316+
// This is the verify module job as it should be the only job scheduled to have no output.
317+
XCTAssertTrue(job.kind == .verifyModuleInterface)
318+
// Check the explicit module flags exists.
319+
XCTAssertTrue(job.commandLine.contains(.flag(String("-explicit-interface-module-build"))))
320+
XCTAssertTrue(job.commandLine.contains(.flag(String("-explicit-swift-module-map-file"))))
321+
XCTAssertTrue(job.commandLine.contains(.flag(String("-disable-implicit-swift-modules"))))
322+
XCTAssertTrue(job.commandLine.contains(.flag(String("-input-file-key"))))
323+
continue
324+
}
325+
let outputFilePath = job.outputs[0].file
326+
327+
// Swift dependencies
328+
if outputFilePath.extension != nil,
329+
outputFilePath.extension! == FileType.swiftModule.rawValue {
330+
if pathMatchesSwiftModule(path: outputFilePath, "A") {
331+
try checkCachingBuildJob(job: job, moduleId: .swift("A"),
332+
dependencyGraph: dependencyGraph)
333+
} else if pathMatchesSwiftModule(path: outputFilePath, "E") {
334+
try checkCachingBuildJob(job: job, moduleId: .swift("E"),
335+
dependencyGraph: dependencyGraph)
336+
} else if pathMatchesSwiftModule(path: outputFilePath, "G") {
337+
try checkCachingBuildJob(job: job, moduleId: .swift("G"),
338+
dependencyGraph: dependencyGraph)
339+
} else if pathMatchesSwiftModule(path: outputFilePath, "Swift") {
340+
try checkCachingBuildJob(job: job, moduleId: .swift("Swift"),
341+
dependencyGraph: dependencyGraph)
342+
} else if pathMatchesSwiftModule(path: outputFilePath, "_Concurrency") {
343+
try checkCachingBuildJob(job: job, moduleId: .swift("_Concurrency"),
344+
dependencyGraph: dependencyGraph)
345+
} else if pathMatchesSwiftModule(path: outputFilePath, "_StringProcessing") {
346+
try checkCachingBuildJob(job: job, moduleId: .swift("_StringProcessing"),
347+
dependencyGraph: dependencyGraph)
348+
} else if pathMatchesSwiftModule(path: outputFilePath, "SwiftOnoneSupport") {
349+
try checkCachingBuildJob(job: job, moduleId: .swift("SwiftOnoneSupport"),
350+
dependencyGraph: dependencyGraph)
351+
}
352+
// Clang Dependencies
353+
} else if let outputExtension = outputFilePath.extension,
354+
outputExtension == FileType.pcm.rawValue {
355+
let relativeOutputPathFileName = outputFilePath.basename
356+
if relativeOutputPathFileName.starts(with: "A-") {
357+
try checkCachingBuildJob(job: job, moduleId: .clang("A"),
358+
dependencyGraph: dependencyGraph)
359+
}
360+
else if relativeOutputPathFileName.starts(with: "B-") {
361+
try checkCachingBuildJob(job: job, moduleId: .clang("B"),
362+
dependencyGraph: dependencyGraph)
363+
}
364+
else if relativeOutputPathFileName.starts(with: "C-") {
365+
try checkCachingBuildJob(job: job, moduleId: .clang("C"),
366+
dependencyGraph: dependencyGraph)
367+
}
368+
else if relativeOutputPathFileName.starts(with: "G-") {
369+
try checkCachingBuildJob(job: job, moduleId: .clang("G"),
370+
dependencyGraph: dependencyGraph)
371+
}
372+
else if relativeOutputPathFileName.starts(with: "F-") {
373+
try checkCachingBuildJob(job: job, moduleId: .clang("F"),
374+
dependencyGraph: dependencyGraph)
375+
}
376+
else if relativeOutputPathFileName.starts(with: "SwiftShims-") {
377+
try checkCachingBuildJob(job: job, moduleId: .clang("SwiftShims"),
378+
dependencyGraph: dependencyGraph)
379+
}
380+
else if relativeOutputPathFileName.starts(with: "_SwiftConcurrencyShims-") {
381+
try checkCachingBuildJob(job: job, moduleId: .clang("_SwiftConcurrencyShims"),
382+
dependencyGraph: dependencyGraph)
383+
}
384+
else {
385+
XCTFail("Unexpected module dependency build job output: \(outputFilePath)")
386+
}
387+
} else {
388+
switch (outputFilePath) {
389+
case .relative(RelativePath("testExplicitModuleVerifyInterfaceJobs")):
390+
XCTAssertTrue(driver.isExplicitMainModuleJob(job: job))
391+
XCTAssertEqual(job.kind, .link)
392+
case .temporary(_):
393+
let baseName = "testExplicitModuleVerifyInterfaceJobs"
394+
XCTAssertTrue(matchTemporary(outputFilePath, basename: baseName, fileExtension: "o") ||
395+
matchTemporary(outputFilePath, basename: baseName, fileExtension: "autolink"))
396+
default:
397+
XCTFail("Unexpected module dependency build job output: \(outputFilePath)")
398+
}
399+
}
400+
}
401+
}
402+
}
403+
404+
273405
func testCacheBuildEndToEndBuild() throws {
274406
try withTemporaryDirectory { path in
275407
try localFileSystem.changeCurrentWorkingDirectory(to: path)

Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift

+128
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,134 @@ final class ExplicitModuleBuildTests: XCTestCase {
375375
}
376376
}
377377

378+
/// Test generation of explicit module build jobs for dependency modules when the driver
379+
/// is invoked with -explicit-module-build, -verify-emitted-module-interface and -enable-library-evolution.
380+
func testExplicitModuleVerifyInterfaceJobs() throws {
381+
try withTemporaryDirectory { path in
382+
let main = path.appending(component: "testExplicitModuleVerifyInterfaceJobs.swift")
383+
try localFileSystem.writeFileContents(main) {
384+
$0 <<< "import C;"
385+
$0 <<< "import E;"
386+
$0 <<< "import G;"
387+
}
388+
389+
let swiftModuleInterfacesPath: AbsolutePath =
390+
testInputsPath.appending(component: "ExplicitModuleBuilds")
391+
.appending(component: "Swift")
392+
let cHeadersPath: AbsolutePath =
393+
testInputsPath.appending(component: "ExplicitModuleBuilds")
394+
.appending(component: "CHeaders")
395+
let swiftInterfacePath: AbsolutePath = path.appending(component: "testExplicitModuleVerifyInterfaceJobs.swiftinterface")
396+
let privateSwiftInterfacePath: AbsolutePath = path.appending(component: "testExplicitModuleVerifyInterfaceJobs.private.swiftinterface")
397+
let sdkArgumentsForTesting = (try? Driver.sdkArgumentsForTesting()) ?? []
398+
var driver = try Driver(args: ["swiftc",
399+
"-target", "x86_64-apple-macosx11.0",
400+
"-I", cHeadersPath.nativePathString(escaped: true),
401+
"-I", swiftModuleInterfacesPath.nativePathString(escaped: true),
402+
"-emit-module-interface-path", swiftInterfacePath.nativePathString(escaped: true),
403+
"-emit-private-module-interface-path", privateSwiftInterfacePath.nativePathString(escaped: true),
404+
"-explicit-module-build", "-verify-emitted-module-interface",
405+
"-enable-library-evolution",
406+
main.nativePathString(escaped: true)] + sdkArgumentsForTesting)
407+
408+
let jobs = try driver.planBuild()
409+
// Figure out which Triples to use.
410+
let dependencyGraph = try driver.gatherModuleDependencies()
411+
let mainModuleInfo = try dependencyGraph.moduleInfo(of: .swift("testExplicitModuleVerifyInterfaceJobs"))
412+
guard case .swift(_) = mainModuleInfo.details else {
413+
XCTFail("Main module does not have Swift details field")
414+
return
415+
}
416+
417+
for job in jobs {
418+
if (job.outputs.count == 0) {
419+
// This is the verify module job as it should be the only job scheduled to have no output.
420+
XCTAssertTrue(job.kind == .verifyModuleInterface)
421+
// Check the explicit module flags exists.
422+
XCTAssertTrue(job.commandLine.contains(.flag(String("-explicit-interface-module-build"))))
423+
XCTAssertTrue(job.commandLine.contains(.flag(String("-explicit-swift-module-map-file"))))
424+
XCTAssertTrue(job.commandLine.contains(.flag(String("-disable-implicit-swift-modules"))))
425+
continue
426+
}
427+
let outputFilePath = job.outputs[0].file
428+
429+
// Swift dependencies
430+
if outputFilePath.extension != nil,
431+
outputFilePath.extension! == FileType.swiftModule.rawValue {
432+
if pathMatchesSwiftModule(path: outputFilePath, "A") {
433+
try checkExplicitModuleBuildJob(job: job, moduleId: .swift("A"),
434+
dependencyGraph: dependencyGraph)
435+
} else if pathMatchesSwiftModule(path: outputFilePath, "E") {
436+
try checkExplicitModuleBuildJob(job: job, moduleId: .swift("E"),
437+
dependencyGraph: dependencyGraph)
438+
} else if pathMatchesSwiftModule(path: outputFilePath, "G") {
439+
try checkExplicitModuleBuildJob(job: job, moduleId: .swift("G"),
440+
dependencyGraph: dependencyGraph)
441+
} else if pathMatchesSwiftModule(path: outputFilePath, "Swift") {
442+
try checkExplicitModuleBuildJob(job: job, moduleId: .swift("Swift"),
443+
dependencyGraph: dependencyGraph)
444+
} else if pathMatchesSwiftModule(path: outputFilePath, "_Concurrency") {
445+
try checkExplicitModuleBuildJob(job: job, moduleId: .swift("_Concurrency"),
446+
dependencyGraph: dependencyGraph)
447+
} else if pathMatchesSwiftModule(path: outputFilePath, "_StringProcessing") {
448+
try checkExplicitModuleBuildJob(job: job, moduleId: .swift("_StringProcessing"),
449+
dependencyGraph: dependencyGraph)
450+
} else if pathMatchesSwiftModule(path: outputFilePath, "SwiftOnoneSupport") {
451+
try checkExplicitModuleBuildJob(job: job, moduleId: .swift("SwiftOnoneSupport"),
452+
dependencyGraph: dependencyGraph)
453+
}
454+
// Clang Dependencies
455+
} else if let outputExtension = outputFilePath.extension,
456+
outputExtension == FileType.pcm.rawValue {
457+
let relativeOutputPathFileName = outputFilePath.basename
458+
if relativeOutputPathFileName.starts(with: "A-") {
459+
try checkExplicitModuleBuildJob(job: job, moduleId: .clang("A"),
460+
dependencyGraph: dependencyGraph)
461+
}
462+
else if relativeOutputPathFileName.starts(with: "B-") {
463+
try checkExplicitModuleBuildJob(job: job, moduleId: .clang("B"),
464+
dependencyGraph: dependencyGraph)
465+
}
466+
else if relativeOutputPathFileName.starts(with: "C-") {
467+
try checkExplicitModuleBuildJob(job: job, moduleId: .clang("C"),
468+
dependencyGraph: dependencyGraph)
469+
}
470+
else if relativeOutputPathFileName.starts(with: "G-") {
471+
try checkExplicitModuleBuildJob(job: job, moduleId: .clang("G"),
472+
dependencyGraph: dependencyGraph)
473+
}
474+
else if relativeOutputPathFileName.starts(with: "F-") {
475+
try checkExplicitModuleBuildJob(job: job, moduleId: .clang("F"),
476+
dependencyGraph: dependencyGraph)
477+
}
478+
else if relativeOutputPathFileName.starts(with: "SwiftShims-") {
479+
try checkExplicitModuleBuildJob(job: job, moduleId: .clang("SwiftShims"),
480+
dependencyGraph: dependencyGraph)
481+
}
482+
else if relativeOutputPathFileName.starts(with: "_SwiftConcurrencyShims-") {
483+
try checkExplicitModuleBuildJob(job: job, moduleId: .clang("_SwiftConcurrencyShims"),
484+
dependencyGraph: dependencyGraph)
485+
}
486+
else {
487+
XCTFail("Unexpected module dependency build job output: \(outputFilePath)")
488+
}
489+
} else {
490+
switch (outputFilePath) {
491+
case .relative(RelativePath("testExplicitModuleVerifyInterfaceJobs")):
492+
XCTAssertTrue(driver.isExplicitMainModuleJob(job: job))
493+
XCTAssertEqual(job.kind, .link)
494+
case .temporary(_):
495+
let baseName = "testExplicitModuleVerifyInterfaceJobs"
496+
XCTAssertTrue(matchTemporary(outputFilePath, basename: baseName, fileExtension: "o") ||
497+
matchTemporary(outputFilePath, basename: baseName, fileExtension: "autolink"))
498+
default:
499+
XCTFail("Unexpected module dependency build job output: \(outputFilePath)")
500+
}
501+
}
502+
}
503+
}
504+
}
505+
378506
/// Test generation of explicit module build jobs for dependency modules when the driver
379507
/// is invoked with -explicit-module-build and -pch-output-dir
380508
func testExplicitModuleBuildPCHOutputJobs() throws {

0 commit comments

Comments
 (0)