From 916d85707d4392e3faa64ece68ce06b7f5c8501d Mon Sep 17 00:00:00 2001 From: Steven Wu Date: Thu, 6 Mar 2025 10:19:04 -0800 Subject: [PATCH] [PCH][OutputFileMap] GeneratePCH output should use single output entry The build system has been emitting the output path of generating PCH job in the module level entry in the output file map, while swift-driver is expecting the entry in an entry that accosiated with imported bridging header. This patch unifies the behavior by picking the implementation of the swift-build, where it is a module level entry. This works better for future when bridging header can be chained, thus creating PCH job even there isn't a imported objc header explicitly provided. rdar://146395316 --- Sources/SwiftDriver/Driver/Driver.swift | 5 ++- Tests/SwiftDriverTests/SwiftDriverTests.swift | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index ef544451a..704442d0d 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -3133,8 +3133,7 @@ extension Driver { func computePrecompiledBridgingHeaderDir( _ parsedOptions: inout ParsedOptions, compilerMode: CompilerMode) throws -> VirtualPath? { - if let input = originalObjCHeaderFile, - let outputPath = try? outputFileMap?.existingOutput(inputFile: input, outputType: .pch) { + if let outputPath = try? outputFileMap?.existingOutputForSingleInput(outputType: .pch) { return VirtualPath.lookup(outputPath).parentDirectory } if let outputDir = parsedOptions.getLastArgument(.pchOutputDir)?.asSingle { @@ -3154,7 +3153,7 @@ extension Driver { return nil } - if let outputPath = try? outputFileMap?.existingOutput(inputFile: input, outputType: .pch) { + if let outputPath = try? outputFileMap?.existingOutputForSingleInput(outputType: .pch) { return outputPath } diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index dea028256..1ae33d985 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -1433,6 +1433,38 @@ final class SwiftDriverTests: XCTestCase { } } + func testEmitPCHWithOutputFileMap() throws { + try withTemporaryDirectory { path in + let outputFileMap = path.appending(component: "outputFileMap.json") + try localFileSystem.writeFileContents(outputFileMap, bytes: """ + { + "": { + "pch": "/build/Foo-bridging-header.pch" + } + } + """ + ) + var driver = try Driver(args: ["swiftc", "foo.swift", "bar.swift", "-module-name", "Foo", "-emit-module", + "-serialize-diagnostics", "-experimental-emit-module-separately", + "-import-objc-header", "bridging.h", "-enable-bridging-pch", + "-output-file-map", outputFileMap.description]) + let plannedJobs = try driver.planBuild().removingAutolinkExtractJobs() + XCTAssertTrue(driver.diagnosticEngine.diagnostics.isEmpty) + + // Test the output path is correct for GeneratePCH job. + XCTAssertEqual(plannedJobs.count, 4) + XCTAssertEqual(plannedJobs[0].kind, .generatePCH) + try XCTAssertJobInvocationMatches(plannedJobs[0], .flag("-o"), .path(.absolute(.init(validating: "/build/Foo-bridging-header.pch")))) + + // Plan a build with no bridging header and make sure no diagnostics is emitted (pch in output file map is still accepted) + driver = try Driver(args: ["swiftc", "foo.swift", "bar.swift", "-module-name", "Foo", "-emit-module", + "-serialize-diagnostics", "-experimental-emit-module-separately", + "-output-file-map", outputFileMap.description]) + let _ = try driver.planBuild() + XCTAssertTrue(driver.diagnosticEngine.diagnostics.isEmpty) + } + } + func testReferenceDependencies() throws { var driver = try Driver(args: ["swiftc", "foo.swift", "-incremental"]) let plannedJobs = try driver.planBuild()