diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index 200e01e32..c7b939012 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -2102,10 +2102,9 @@ extension Driver { // An option has been passed which requires a module, but the user hasn't // requested one. Generate a module, but treat it as an intermediate output. moduleOutputKind = .auxiliary - } else if compilerMode != .singleCompile && - parsedOptions.hasArgument(.emitObjcHeader, .emitObjcHeaderPath, - .emitModuleInterface, .emitModuleInterfacePath, - .emitPrivateModuleInterfacePath) { + } else if parsedOptions.hasArgument(.emitObjcHeader, .emitObjcHeaderPath, + .emitModuleInterface, .emitModuleInterfacePath, + .emitPrivateModuleInterfacePath) { // An option has been passed which requires whole-module knowledge, but we // don't have that. Generate a module, but treat it as an intermediate // output. diff --git a/Sources/SwiftDriver/Jobs/EmitModuleJob.swift b/Sources/SwiftDriver/Jobs/EmitModuleJob.swift index a1a45d1e9..373a0b793 100644 --- a/Sources/SwiftDriver/Jobs/EmitModuleJob.swift +++ b/Sources/SwiftDriver/Jobs/EmitModuleJob.swift @@ -145,7 +145,7 @@ extension Driver { case .singleCompile: return parsedOptions.hasFlag(positive: .emitModuleSeparatelyWMO, negative: .noEmitModuleSeparatelyWMO, - default: false) && + default: true) && compilerOutputType != .swiftModule // The main job already generates only the module files. default: diff --git a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift index bd5c96622..b11271c18 100644 --- a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift +++ b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift @@ -398,38 +398,39 @@ extension Driver { } else { addAllOutputsFor(input: nil) - // Outputs that only make sense when the whole module is processed - // together. - addOutputOfType( - outputType: .objcHeader, - finalOutputPath: objcGeneratedHeaderPath, - input: nil, - flag: "-emit-objc-header-path") + if !emitModuleSeparately { + // Outputs that only make sense when the whole module is processed + // together. + addOutputOfType( + outputType: .objcHeader, + finalOutputPath: objcGeneratedHeaderPath, + input: nil, + flag: "-emit-objc-header-path") - addOutputOfType( - outputType: .swiftInterface, - finalOutputPath: swiftInterfacePath, - input: nil, - flag: "-emit-module-interface-path") + addOutputOfType( + outputType: .swiftInterface, + finalOutputPath: swiftInterfacePath, + input: nil, + flag: "-emit-module-interface-path") - addOutputOfType( - outputType: .privateSwiftInterface, - finalOutputPath: swiftPrivateInterfacePath, - input: nil, - flag: "-emit-private-module-interface-path") + addOutputOfType( + outputType: .privateSwiftInterface, + finalOutputPath: swiftPrivateInterfacePath, + input: nil, + flag: "-emit-private-module-interface-path") - addOutputOfType( - outputType: .tbd, - finalOutputPath: tbdPath, - input: nil, - flag: "-emit-tbd-path") - - if let abiDescriptorPath = abiDescriptorPath, - !emitModuleSeparately { - addOutputOfType(outputType: .jsonABIBaseline, - finalOutputPath: abiDescriptorPath.fileHandle, - input: nil, - flag: "-emit-abi-descriptor-path") + addOutputOfType( + outputType: .tbd, + finalOutputPath: tbdPath, + input: nil, + flag: "-emit-tbd-path") + + if let abiDescriptorPath = abiDescriptorPath { + addOutputOfType(outputType: .jsonABIBaseline, + finalOutputPath: abiDescriptorPath.fileHandle, + input: nil, + flag: "-emit-abi-descriptor-path") + } } } diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index 94c227a1f..307e6c9e5 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -2081,20 +2081,29 @@ final class SwiftDriverTests: XCTestCase { } func testSingleThreadedWholeModuleOptimizationCompiles() throws { - var driver1 = try Driver(args: ["swiftc", "-whole-module-optimization", "foo.swift", "bar.swift", "-module-name", "Test", "-target", "x86_64-apple-macosx10.15", "-emit-module-interface", "-emit-objc-header-path", "Test-Swift.h", "-emit-private-module-interface-path", "Test.private.swiftinterface"]) + var driver1 = try Driver(args: ["swiftc", "-whole-module-optimization", "foo.swift", "bar.swift", "-emit-library", "-emit-module", "-module-name", "Test", "-target", "x86_64-apple-macosx10.15", "-emit-module-interface", "-emit-objc-header-path", "Test-Swift.h", "-emit-private-module-interface-path", "Test.private.swiftinterface", "-emit-tbd"]) let plannedJobs = try driver1.planBuild() - XCTAssertEqual(plannedJobs.count, 2) + XCTAssertEqual(plannedJobs.count, 3) + XCTAssertEqual(Set(plannedJobs.map { $0.kind }), Set([.compile, .emitModule, .link])) + XCTAssertEqual(plannedJobs[0].kind, .compile) - XCTAssertEqual(plannedJobs[0].outputs.count, 4) + XCTAssertEqual(plannedJobs[0].outputs.count, 1) XCTAssertTrue(matchTemporary(plannedJobs[0].outputs[0].file, "Test.o")) - XCTAssertEqual(plannedJobs[0].outputs[1].file, VirtualPath.relative(RelativePath("Test-Swift.h"))) - XCTAssertEqual(plannedJobs[0].outputs[2].file, VirtualPath.relative(RelativePath("Test.swiftinterface"))) - XCTAssertEqual(plannedJobs[0].outputs[3].file, VirtualPath.relative(RelativePath("Test.private.swiftinterface"))) XCTAssert(!plannedJobs[0].commandLine.contains(.flag("-primary-file"))) - XCTAssert(plannedJobs[0].commandLine.contains(.flag("-emit-module-interface-path"))) - XCTAssert(plannedJobs[0].commandLine.contains(.flag("-emit-private-module-interface-path"))) - XCTAssertEqual(plannedJobs[1].kind, .link) + let emitModuleJob = plannedJobs.first(where: {$0.kind == .emitModule})! + XCTAssertEqual(emitModuleJob.outputs.count, 8) + XCTAssertEqual(emitModuleJob.outputs[0].file, VirtualPath.relative(RelativePath("Test.swiftmodule"))) + XCTAssertEqual(emitModuleJob.outputs[1].file, VirtualPath.relative(RelativePath("Test.swiftdoc"))) + XCTAssertEqual(emitModuleJob.outputs[2].file, VirtualPath.relative(RelativePath("Test.swiftsourceinfo"))) + XCTAssertEqual(emitModuleJob.outputs[3].file, VirtualPath.relative(RelativePath("Test.swiftinterface"))) + XCTAssertEqual(emitModuleJob.outputs[4].file, VirtualPath.relative(RelativePath("Test.private.swiftinterface"))) + XCTAssertEqual(emitModuleJob.outputs[5].file, VirtualPath.relative(RelativePath("Test-Swift.h"))) + XCTAssertEqual(emitModuleJob.outputs[6].file, VirtualPath.relative(RelativePath("Test.tbd"))) + XCTAssertEqual(emitModuleJob.outputs[7].file, VirtualPath.relative(RelativePath("Test.abi.json"))) + XCTAssert(!emitModuleJob.commandLine.contains(.flag("-primary-file"))) + XCTAssert(emitModuleJob.commandLine.contains(.flag("-emit-module-interface-path"))) + XCTAssert(emitModuleJob.commandLine.contains(.flag("-emit-private-module-interface-path"))) } @@ -2231,16 +2240,21 @@ final class SwiftDriverTests: XCTestCase { "-num-threads", "4", "-output-file-map", file.path.pathString, "-emit-module-interface" ]) let plannedJobs = try driver1.planBuild().removingAutolinkExtractJobs() - XCTAssertEqual(plannedJobs.count, 2) + XCTAssertEqual(plannedJobs.count, 3) + XCTAssertEqual(Set(plannedJobs.map { $0.kind }), Set([.compile, .emitModule, .link])) + XCTAssertEqual(plannedJobs[0].kind, .compile) - XCTAssertEqual(plannedJobs[0].outputs.count, 4) + XCTAssertEqual(plannedJobs[0].outputs.count, 3) XCTAssertTrue(matchTemporary(plannedJobs[0].outputs[0].file, "foo.o")) XCTAssertTrue(matchTemporary(plannedJobs[0].outputs[1].file, "bar.o")) XCTAssertTrue(matchTemporary(plannedJobs[0].outputs[2].file, "wibble.o")) - XCTAssertEqual(plannedJobs[0].outputs[3].file, VirtualPath.absolute(AbsolutePath("/tmp/salty/Test.swiftinterface"))) XCTAssert(!plannedJobs[0].commandLine.contains(.flag("-primary-file"))) - XCTAssertEqual(plannedJobs[1].kind, .link) + let emitModuleJob = plannedJobs.first(where: {$0.kind == .emitModule})! + XCTAssertEqual(emitModuleJob.outputs[3].file, VirtualPath.absolute(AbsolutePath("/tmp/salty/Test.swiftinterface"))) + XCTAssert(!emitModuleJob.commandLine.contains(.flag("-primary-file"))) + + XCTAssertEqual(plannedJobs[2].kind, .link) } } } @@ -2300,7 +2314,7 @@ final class SwiftDriverTests: XCTestCase { "-emit-module-interface", "-driver-filelist-threshold=0" ]) let plannedJobs = try driver1.planBuild().removingAutolinkExtractJobs() - XCTAssertEqual(plannedJobs.count, 2) + XCTAssertEqual(plannedJobs.count, 3) XCTAssertEqual(plannedJobs[0].kind, .compile) XCTAssert(plannedJobs[0].commandLine.contains(.flag("-supplementary-output-file-map"))) } @@ -4943,12 +4957,12 @@ final class SwiftDriverTests: XCTestCase { do { var driver = try Driver(args: ["swiftc", "-embed-bitcode", "-c", "-parse-as-library", "-emit-module", "-whole-module-optimization", "embed-bitcode.swift", "-parse-stdlib", "-module-name", "Swift"]) let plannedJobs = try driver.planBuild().removingAutolinkExtractJobs() - XCTAssertEqual(plannedJobs.count, 2) + XCTAssertEqual(plannedJobs.count, 3) XCTAssertEqual(plannedJobs[0].kind, .compile) XCTAssertEqual(plannedJobs[0].inputs.count, 1) XCTAssertEqual(plannedJobs[0].inputs[0].file, .relative(RelativePath("embed-bitcode.swift"))) - XCTAssertEqual(plannedJobs[0].outputs.count, 5) + XCTAssertEqual(plannedJobs[0].outputs.count, 1) XCTAssertTrue(matchTemporary(plannedJobs[0].outputs[0].file, "Swift.bc")) XCTAssertEqual(plannedJobs[1].kind, .backend) @@ -4956,6 +4970,16 @@ final class SwiftDriverTests: XCTestCase { XCTAssertTrue(matchTemporary(plannedJobs[1].inputs[0].file, "Swift.bc")) XCTAssertEqual(plannedJobs[1].outputs.count, 1) XCTAssertEqual(plannedJobs[1].outputs[0].file, .relative(RelativePath("Swift.o"))) + + let emitModuleJob = plannedJobs[2] + XCTAssertEqual(emitModuleJob.kind, .emitModule) + XCTAssertEqual(emitModuleJob.inputs.count, 1) + XCTAssertEqual(plannedJobs[0].inputs[0].file, .relative(RelativePath("embed-bitcode.swift"))) + XCTAssertEqual(emitModuleJob.outputs.count, 4) + XCTAssertEqual(1, emitModuleJob.outputs.filter({$0.file == .relative(RelativePath("Swift.swiftmodule"))}).count) + XCTAssertEqual(1, emitModuleJob.outputs.filter({$0.file == .relative(RelativePath("Swift.swiftdoc"))}).count) + XCTAssertEqual(1, emitModuleJob.outputs.filter({$0.file == .relative(RelativePath("Swift.swiftsourceinfo"))}).count) + XCTAssertEqual(1, emitModuleJob.outputs.filter({$0.file == .relative(RelativePath("Swift.abi.json"))}).count) } try assertDriverDiagnostics(args: ["swiftc", "-embed-bitcode", "-emit-module", "embed-bitcode.swift"]) { driver, verify in