Skip to content

Commit 6c6309e

Browse files
[Preview] Fix preview support for swift caching build (#562)
Add support for swift caching build when swift compiler supports the new option that allows swift compiler performs an uncached build but loading module dependencies from CAS. It also does few adjustment to make sure preview build shares the same dependencies with regular build as caching build has a stricter rule for invalidation: * The VFS overlay used by preview is applied after swift driver invocation and onto the frontend invocation directly. This makes sure the VFS overlay doesn't invalidate all the module dependencies. * BridgingHeader PCH was disabled as a workaround when swift driver doesn't produce deterministic output path when planning for PCH jobs. Properly fix this issue by requesting the same path when planning both build and don't use this workaround in certain configurations. This should allow preview to build thunk correctly when swift caching is enabled for the regular build. rdar://152107465
1 parent d015784 commit 6c6309e

File tree

3 files changed

+43
-20
lines changed

3 files changed

+43
-20
lines changed

Sources/SWBCore/SpecImplementations/Tools/SwiftCompiler.swift

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ public struct SwiftDriverPayload: Serializable, TaskPayload, Encodable {
337337
public let uniqueID: String
338338
public let compilerLocation: LibSwiftDriver.CompilerLocation
339339
public let moduleName: String
340+
public let outputPrefix: String
340341
public let tempDirPath: Path
341342
public let explicitModulesTempDirPath: Path
342343
public let variant: String
@@ -352,10 +353,11 @@ public struct SwiftDriverPayload: Serializable, TaskPayload, Encodable {
352353
public let dependencyFilteringRootPath: Path?
353354
public let verifyScannerDependencies: Bool
354355

355-
internal init(uniqueID: String, compilerLocation: LibSwiftDriver.CompilerLocation, moduleName: String, tempDirPath: Path, explicitModulesTempDirPath: Path, variant: String, architecture: String, eagerCompilationEnabled: Bool, explicitModulesEnabled: Bool, commandLine: [String], ruleInfo: [String], isUsingWholeModuleOptimization: Bool, casOptions: CASOptions?, reportRequiredTargetDependencies: BooleanWarningLevel, linkerResponseFilePath: Path?, dependencyFilteringRootPath: Path?, verifyScannerDependencies: Bool) {
356+
internal init(uniqueID: String, compilerLocation: LibSwiftDriver.CompilerLocation, moduleName: String, outputPrefix: String, tempDirPath: Path, explicitModulesTempDirPath: Path, variant: String, architecture: String, eagerCompilationEnabled: Bool, explicitModulesEnabled: Bool, commandLine: [String], ruleInfo: [String], isUsingWholeModuleOptimization: Bool, casOptions: CASOptions?, reportRequiredTargetDependencies: BooleanWarningLevel, linkerResponseFilePath: Path?, dependencyFilteringRootPath: Path?, verifyScannerDependencies: Bool) {
356357
self.uniqueID = uniqueID
357358
self.compilerLocation = compilerLocation
358359
self.moduleName = moduleName
360+
self.outputPrefix = outputPrefix
359361
self.tempDirPath = tempDirPath
360362
self.explicitModulesTempDirPath = explicitModulesTempDirPath
361363
self.variant = variant
@@ -373,10 +375,11 @@ public struct SwiftDriverPayload: Serializable, TaskPayload, Encodable {
373375
}
374376

375377
public init(from deserializer: any Deserializer) throws {
376-
try deserializer.beginAggregate(17)
378+
try deserializer.beginAggregate(18)
377379
self.uniqueID = try deserializer.deserialize()
378380
self.compilerLocation = try deserializer.deserialize()
379381
self.moduleName = try deserializer.deserialize()
382+
self.outputPrefix = try deserializer.deserialize()
380383
self.tempDirPath = try deserializer.deserialize()
381384
self.explicitModulesTempDirPath = try deserializer.deserialize()
382385
self.variant = try deserializer.deserialize()
@@ -394,10 +397,11 @@ public struct SwiftDriverPayload: Serializable, TaskPayload, Encodable {
394397
}
395398

396399
public func serialize<T>(to serializer: T) where T : Serializer {
397-
serializer.serializeAggregate(17) {
400+
serializer.serializeAggregate(18) {
398401
serializer.serialize(self.uniqueID)
399402
serializer.serialize(self.compilerLocation)
400403
serializer.serialize(self.moduleName)
404+
serializer.serialize(self.outputPrefix)
401405
serializer.serialize(self.tempDirPath)
402406
serializer.serialize(self.explicitModulesTempDirPath)
403407
serializer.serialize(self.variant)
@@ -2502,7 +2506,7 @@ public final class SwiftCompilerSpec : CompilerSpec, SpecIdentifierType, SwiftDi
25022506
let explicitModuleBuildEnabled = await swiftExplicitModuleBuildEnabled(cbc.producer, cbc.scope, delegate)
25032507
let verifyScannerDependencies = explicitModuleBuildEnabled && cbc.scope.evaluate(BuiltinMacros.SWIFT_DEPENDENCY_REGISTRATION_MODE) == .verifySwiftDependencyScanner
25042508

2505-
return SwiftDriverPayload(uniqueID: uniqueID, compilerLocation: compilerLocation, moduleName: scope.evaluate(BuiltinMacros.SWIFT_MODULE_NAME), tempDirPath: tempDirPath, explicitModulesTempDirPath: explicitModulesTempDirPath, variant: variant, architecture: arch, eagerCompilationEnabled: eagerCompilationEnabled(args: args, scope: scope, compilationMode: compilationMode, isUsingWholeModuleOptimization: isUsingWholeModuleOptimization), explicitModulesEnabled: explicitModuleBuildEnabled, commandLine: commandLine, ruleInfo: ruleInfo, isUsingWholeModuleOptimization: isUsingWholeModuleOptimization, casOptions: casOptions, reportRequiredTargetDependencies: scope.evaluate(BuiltinMacros.DIAGNOSE_MISSING_TARGET_DEPENDENCIES), linkerResponseFilePath: linkerResponseFilePath, dependencyFilteringRootPath: cbc.producer.sdk?.path, verifyScannerDependencies: verifyScannerDependencies)
2509+
return SwiftDriverPayload(uniqueID: uniqueID, compilerLocation: compilerLocation, moduleName: scope.evaluate(BuiltinMacros.SWIFT_MODULE_NAME), outputPrefix: scope.evaluate(BuiltinMacros.TARGET_NAME) + compilationMode.moduleBaseNameSuffix, tempDirPath: tempDirPath, explicitModulesTempDirPath: explicitModulesTempDirPath, variant: variant, architecture: arch, eagerCompilationEnabled: eagerCompilationEnabled(args: args, scope: scope, compilationMode: compilationMode, isUsingWholeModuleOptimization: isUsingWholeModuleOptimization), explicitModulesEnabled: explicitModuleBuildEnabled, commandLine: commandLine, ruleInfo: ruleInfo, isUsingWholeModuleOptimization: isUsingWholeModuleOptimization, casOptions: casOptions, reportRequiredTargetDependencies: scope.evaluate(BuiltinMacros.DIAGNOSE_MISSING_TARGET_DEPENDENCIES), linkerResponseFilePath: linkerResponseFilePath, dependencyFilteringRootPath: cbc.producer.sdk?.path, verifyScannerDependencies: verifyScannerDependencies)
25062510
}
25072511

25082512
func constructSwiftResponseFileTask(path: Path) {
@@ -3397,10 +3401,12 @@ public final class SwiftCompilerSpec : CompilerSpec, SpecIdentifierType, SwiftDi
33973401
removeWithParameter(arg)
33983402
}
33993403

3400-
// We need to ignore precompiled headers due to:
3404+
// For some old version of swift driver, the output path for bridging header pch is not stable,
3405+
// we need to disable bridging header pch when caching or bridging header chaining is not enabled as a workaround:
34013406
// rdar://126212044 ([JIT] iOS test Failures: Thunk build failure, unable to read PCH file)
3402-
removeWithPrefix("-cache-compile-job")
3403-
commandLine.append("-disable-bridging-pch")
3407+
if !commandLine.contains("-cache-compile-job") || !commandLine.contains("-auto-bridging-header-chaining") {
3408+
commandLine.append("-disable-bridging-pch")
3409+
}
34043410

34053411
if payload.previewStyle == .dynamicReplacement {
34063412
for (arg, newValue) in [
@@ -3440,6 +3446,7 @@ public final class SwiftCompilerSpec : CompilerSpec, SpecIdentifierType, SwiftDi
34403446
}
34413447

34423448
let selectedInputPath: Path
3449+
let newVFSOverlayPath: Path?
34433450
if payload.previewStyle == .xojit {
34443451
// Also pass the auxiliary Swift files.
34453452
commandLine.append(contentsOf: originalInputs.map(\.str))
@@ -3448,7 +3455,8 @@ public final class SwiftCompilerSpec : CompilerSpec, SpecIdentifierType, SwiftDi
34483455
if let driverPayload = payload.driverPayload {
34493456
do {
34503457
// Inject the thunk source into the output file map
3451-
let map = SwiftOutputFileMap(files: [sourceFile.str: .init(object: outputPath.str)])
3458+
let pchPath = driverPayload.tempDirPath.join(driverPayload.outputPrefix + "-primary-Bridging-header.pch")
3459+
let map = SwiftOutputFileMap(files: [sourceFile.str: .init(object: outputPath.str), "": .init(pch: pchPath.str)])
34523460
let newOutputFileMap = driverPayload.tempDirPath.join(UUID().uuidString)
34533461
try fs.createDirectory(newOutputFileMap.dirname, recursive: true)
34543462
try fs.write(newOutputFileMap, contents: ByteString(JSONEncoder(outputFormatting: [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes]).encode(map)))
@@ -3457,19 +3465,20 @@ public final class SwiftCompilerSpec : CompilerSpec, SpecIdentifierType, SwiftDi
34573465
// rdar://127735418 ([JIT] Emit a vfsoverlay for JIT preview thunk compiler arguments so clients can specify the original file path when substituting contents)
34583466
let vfs = VFS()
34593467
vfs.addMapping(sourceFile, externalContents: inputPath)
3460-
let newVFSOverlayPath = driverPayload.tempDirPath.join("vfsoverlay-\(inputPath.basename).json")
3468+
newVFSOverlayPath = driverPayload.tempDirPath.join("vfsoverlay-\(inputPath.basename).json")
34613469
try fs.createDirectory(newOutputFileMap.dirname, recursive: true)
34623470
let overlay = try vfs.toVFSOverlay().propertyListItem.asJSONFragment().asString
3463-
try fs.write(newVFSOverlayPath, contents: ByteString(encodingAsUTF8: overlay))
3464-
3465-
commandLine.append(contentsOf: ["-vfsoverlay", newVFSOverlayPath.str])
3471+
try fs.write(newVFSOverlayPath!, contents: ByteString(encodingAsUTF8: overlay))
34663472
} catch {
34673473
return []
34683474
}
3475+
} else {
3476+
newVFSOverlayPath = nil
34693477
}
34703478
}
34713479
else {
34723480
selectedInputPath = inputPath
3481+
newVFSOverlayPath = nil
34733482
commandLine.append(contentsOf: [inputPath.str])
34743483
}
34753484

@@ -3516,6 +3525,21 @@ public final class SwiftCompilerSpec : CompilerSpec, SpecIdentifierType, SwiftDi
35163525
casOptions: driverPayload.casOptions
35173526
) {
35183527
commandLine = newCommandLine
3528+
// For swift caching jobs, add extra flags.
3529+
if commandLine.contains("-cache-compile-job") {
3530+
// Ideally, we should ask if swift-frontend supports the flag but we can only ask driver for an approximation.
3531+
if LibSwiftDriver.supportsDriverFlag(spelled: "-module-import-from-cas") {
3532+
commandLine.append("-module-import-from-cas")
3533+
}
3534+
// Then drop the cache build flag to do uncached preview compilation.
3535+
commandLine.removeAll {
3536+
$0 == "-cache-compile-job"
3537+
}
3538+
}
3539+
// Add vfsoverlay after the driver invocation as it can affect the module dependencies, causing modules from regular builds not being reused here.
3540+
if let vfsOverlay = newVFSOverlayPath {
3541+
commandLine.append(contentsOf: ["-vfsoverlay", vfsOverlay.str])
3542+
}
35193543
} else {
35203544
commandLine = []
35213545
}

Tests/SWBBuildSystemTests/PreviewsBuildOperationTests.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,6 @@ fileprivate struct PreviewsBuildOperationTests: CoreBasedTests {
227227
"\(srcRoot.str)/build/Debug-iphonesimulator",
228228
"-F",
229229
"\(srcRoot.str)/build/Debug-iphonesimulator",
230-
"-vfsoverlay",
231-
"\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/vfsoverlay-main.selection.preview-thunk.swift.json",
232230
"-no-color-diagnostics",
233231
"-g",
234232
"-debug-info-format=dwarf",
@@ -278,7 +276,9 @@ fileprivate struct PreviewsBuildOperationTests: CoreBasedTests {
278276
"-target-sdk-name",
279277
"iphonesimulator\(core.loadSDK(.iOSSimulator).defaultDeploymentTarget)",
280278
"-o",
281-
"\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/main.selection.preview-thunk.o"
279+
"\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/main.selection.preview-thunk.o",
280+
"-vfsoverlay",
281+
"\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/vfsoverlay-main.selection.preview-thunk.swift.json",
282282
]
283283
)
284284
#expect(previewInfo.thunkInfo?.thunkSourceFile == Path("\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/main.selection.preview-thunk.swift"))
@@ -531,8 +531,6 @@ fileprivate struct PreviewsBuildOperationTests: CoreBasedTests {
531531
"\(srcRoot.str)/build/Debug-iphonesimulator",
532532
"-F",
533533
"\(srcRoot.str)/build/Debug-iphonesimulator",
534-
"-vfsoverlay",
535-
"\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/vfsoverlay-File1.selection.preview-thunk.swift.json",
536534
"-no-color-diagnostics",
537535
"-g",
538536
"-debug-info-format=dwarf",
@@ -582,7 +580,9 @@ fileprivate struct PreviewsBuildOperationTests: CoreBasedTests {
582580
"-target-sdk-name",
583581
"iphonesimulator\(core.loadSDK(.iOSSimulator).defaultDeploymentTarget)",
584582
"-o",
585-
"\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/File1.selection.preview-thunk.o"
583+
"\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/File1.selection.preview-thunk.o",
584+
"-vfsoverlay",
585+
"\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/vfsoverlay-File1.selection.preview-thunk.swift.json",
586586
]
587587
)
588588
#expect(previewInfo.thunkInfo?.thunkSourceFile == Path("\(srcRoot.str)/build/ProjectName.build/Debug-iphonesimulator/AppTarget.build/Objects-normal/\(results.runDestinationTargetArchitecture)/File1.selection.preview-thunk.swift"))

Tests/SwiftBuildTests/GeneratePreviewInfoTests.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,14 +160,13 @@ fileprivate struct GeneratePreviewInfoTests: CoreBasedTests {
160160
.anySequence,
161161
"-sdk", "\(sdkroot)",
162162
.anySequence,
163-
"-vfsoverlay", "\(tmpDir.str)/Test/build/Test.build/Debug-iphoneos/App.build/Objects-normal/\(activeRunDestination.targetArchitecture)/vfsoverlay-TestFile4.canary.preview-thunk.swift.json",
164-
.anySequence,
165163
"-Onone",
166164
.anySequence,
167165
"-module-name", "App",
168166
"-target-sdk-version", "\(deploymentTarget)",
169167
"-target-sdk-name", "iphoneos\(deploymentTarget)",
170168
"-o", "\(tmpDir.str)/Test/build/Test.build/Debug-iphoneos/App.build/Objects-normal/\(activeRunDestination.targetArchitecture)/TestFile4.canary.preview-thunk.o",
169+
"-vfsoverlay", "\(tmpDir.str)/Test/build/Test.build/Debug-iphoneos/App.build/Objects-normal/\(activeRunDestination.targetArchitecture)/vfsoverlay-TestFile4.canary.preview-thunk.swift.json",
171170
.end
172171
])
173172
// Also spot-check that some options which were removed in SwiftCompilerSpec.generatePreviewInfo() for XOJIT are not present.

0 commit comments

Comments
 (0)