Skip to content

Commit 28c76e9

Browse files
[BridgingHeader] Support automatic bridging header chaining
Teach swift driver to handle bridging header chaining and pass the correct arguments to swift-frontend.
1 parent bfc9c09 commit 28c76e9

File tree

11 files changed

+226
-47
lines changed

11 files changed

+226
-47
lines changed

Sources/CSwiftScan/include/swiftscan_header.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include <stdint.h>
1919

2020
#define SWIFTSCAN_VERSION_MAJOR 1
21-
#define SWIFTSCAN_VERSION_MINOR 0
21+
#define SWIFTSCAN_VERSION_MINOR 1
2222

2323
//=== Public Scanner Data Types -------------------------------------------===//
2424

@@ -145,6 +145,12 @@ typedef struct {
145145
(*swiftscan_swift_textual_detail_get_swift_overlay_dependencies)(swiftscan_module_details_t);
146146
swiftscan_string_ref_t
147147
(*swiftscan_swift_textual_detail_get_module_cache_key)(swiftscan_module_details_t);
148+
swiftscan_string_ref_t
149+
(*swiftscan_swift_textual_detail_get_user_module_version)(swiftscan_module_details_t);
150+
swiftscan_string_ref_t
151+
(*swiftscan_swift_textual_detail_get_chained_bridging_header_path)(swiftscan_module_details_t);
152+
swiftscan_string_ref_t
153+
(*swiftscan_swift_textual_detail_get_chained_bridging_header_content)(swiftscan_module_details_t);
148154

149155
//=== Swift Binary Module Details query APIs ------------------------------===//
150156
swiftscan_string_ref_t

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 63 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -336,17 +336,30 @@ public struct Driver {
336336
}
337337
}
338338

339+
/// If PCH job is needed.
340+
let producePCHJob: Bool
341+
342+
/// Original ObjC Header passed from command-line
343+
let originalObjCHeaderFile: VirtualPath.Handle?
344+
339345
/// The path to the imported Objective-C header.
340-
let importedObjCHeader: VirtualPath.Handle?
346+
lazy var importedObjCHeader: VirtualPath.Handle? = {
347+
assert(explicitDependencyBuildPlanner != nil ||
348+
!parsedOptions.hasArgument(.driverExplicitModuleBuild),
349+
"should not be queried before scanning")
350+
let chainedBridgingHeader = try? explicitDependencyBuildPlanner?.getChainedBridgingHeaderFile()
351+
return try? computeImportedObjCHeader(&parsedOptions, compilerMode: compilerMode,
352+
chainedBridgingHeader: chainedBridgingHeader)
353+
}()
341354

342355
/// The path to the pch for the imported Objective-C header.
343356
lazy var bridgingPrecompiledHeader: VirtualPath.Handle? = {
344357
let contextHash = try? explicitDependencyBuildPlanner?.getMainModuleContextHash()
345-
return Self.computeBridgingPrecompiledHeader(&parsedOptions,
346-
compilerMode: compilerMode,
347-
importedObjCHeader: importedObjCHeader,
348-
outputFileMap: outputFileMap,
349-
contextHash: contextHash)
358+
return computeBridgingPrecompiledHeader(&parsedOptions,
359+
compilerMode: compilerMode,
360+
importedObjCHeader: importedObjCHeader,
361+
outputFileMap: outputFileMap,
362+
contextHash: contextHash)
350363
}()
351364

352365
/// Path to the dependencies file.
@@ -866,8 +879,6 @@ public struct Driver {
866879
parsedOptions: parsedOptions,
867880
recordedInputModificationDates: recordedInputModificationDates)
868881

869-
self.importedObjCHeader = try Self.computeImportedObjCHeader(&parsedOptions, compilerMode: compilerMode, diagnosticEngine: diagnosticEngine)
870-
871882
self.supportedFrontendFlags =
872883
try Self.computeSupportedCompilerArgs(of: self.toolchain,
873884
libSwiftScan: self.swiftScanLibInstance,
@@ -892,16 +903,38 @@ public struct Driver {
892903
diagnosticsEngine.emit(.warning("-cache-compile-job cannot be used without explicit module build, turn off caching"),
893904
location: nil)
894905
self.enableCaching = false
895-
} else if importedObjCHeader != nil, !parsedOptions.hasFlag(positive: .enableBridgingPch, negative: .disableBridgingPch, default: true) {
896-
diagnosticsEngine.emit(.warning("-cache-compile-job cannot be used with -disable-bridging-pch, turn off caching"),
897-
location: nil)
898-
self.enableCaching = false
899906
} else {
900907
self.enableCaching = true
901908
}
902909
} else {
903910
self.enableCaching = false
904911
}
912+
913+
// PCH related options.
914+
if parsedOptions.hasArgument(.importObjcHeader) {
915+
// Check for conflicting options.
916+
if parsedOptions.hasArgument(.importUnderlyingModule) {
917+
diagnosticEngine.emit(.error_framework_bridging_header)
918+
}
919+
920+
if parsedOptions.hasArgument(.emitModuleInterface, .emitModuleInterfacePath) {
921+
diagnosticEngine.emit(.error_bridging_header_module_interface)
922+
}
923+
}
924+
var maybeNeedPCH = parsedOptions.hasFlag(positive: .enableBridgingPch, negative: .disableBridgingPch, default: true)
925+
if enableCaching && !maybeNeedPCH {
926+
diagnosticsEngine.emit(.warning("-cache-compile-job cannot be used with -disable-bridging-pch, turn on PCH generation"),
927+
location: nil)
928+
maybeNeedPCH = true
929+
}
930+
self.producePCHJob = maybeNeedPCH
931+
932+
if let objcHeaderPathArg = parsedOptions.getLastArgument(.importObjcHeader) {
933+
self.originalObjCHeaderFile = try? VirtualPath.intern(path: objcHeaderPathArg.asSingle)
934+
} else {
935+
self.originalObjCHeaderFile = nil
936+
}
937+
905938
self.useClangIncludeTree = !parsedOptions.hasArgument(.noClangIncludeTree) && !env.keys.contains("SWIFT_CACHING_USE_CLANG_CAS_FS")
906939
self.scannerPrefixMap = try Self.computeScanningPrefixMapper(&parsedOptions)
907940
if let sdkMapping = parsedOptions.getLastArgument(.scannerPrefixMapSdk)?.asSingle {
@@ -2898,36 +2931,31 @@ extension Driver {
28982931
// Imported Objective-C header.
28992932
extension Driver {
29002933
/// Compute the path of the imported Objective-C header.
2901-
static func computeImportedObjCHeader(
2934+
func computeImportedObjCHeader(
29022935
_ parsedOptions: inout ParsedOptions,
29032936
compilerMode: CompilerMode,
2904-
diagnosticEngine: DiagnosticsEngine
2937+
chainedBridgingHeader: ChainedBridgingHeaderFile?,
29052938
) throws -> VirtualPath.Handle? {
2906-
guard let objcHeaderPathArg = parsedOptions.getLastArgument(.importObjcHeader) else {
2907-
return nil
2908-
}
2909-
2910-
// Check for conflicting options.
2911-
if parsedOptions.hasArgument(.importUnderlyingModule) {
2912-
diagnosticEngine.emit(.error_framework_bridging_header)
2913-
}
2914-
2915-
if parsedOptions.hasArgument(.emitModuleInterface, .emitModuleInterfacePath) {
2916-
diagnosticEngine.emit(.error_bridging_header_module_interface)
2939+
// handle chained bridging header.
2940+
if let chainedHeader = chainedBridgingHeader, !chainedHeader.path.isEmpty {
2941+
let path = try VirtualPath(path: chainedHeader.path)
2942+
if !enableCaching {
2943+
try fileSystem.writeFileContents(path,
2944+
bytes: ByteString(encodingAsUTF8: chainedHeader.content),
2945+
atomically: true)
2946+
}
2947+
return path.intern()
29172948
}
2918-
2919-
return try VirtualPath.intern(path: objcHeaderPathArg.asSingle)
2949+
return originalObjCHeaderFile
29202950
}
29212951

29222952
/// Compute the path of the generated bridging PCH for the Objective-C header.
2923-
static func computeBridgingPrecompiledHeader(_ parsedOptions: inout ParsedOptions,
2924-
compilerMode: CompilerMode,
2925-
importedObjCHeader: VirtualPath.Handle?,
2926-
outputFileMap: OutputFileMap?,
2927-
contextHash: String?) -> VirtualPath.Handle? {
2928-
guard compilerMode.supportsBridgingPCH,
2929-
let input = importedObjCHeader,
2930-
parsedOptions.hasFlag(positive: .enableBridgingPch, negative: .disableBridgingPch, default: true) else {
2953+
func computeBridgingPrecompiledHeader(_ parsedOptions: inout ParsedOptions,
2954+
compilerMode: CompilerMode,
2955+
importedObjCHeader: VirtualPath.Handle?,
2956+
outputFileMap: OutputFileMap?,
2957+
contextHash: String?) -> VirtualPath.Handle? {
2958+
guard compilerMode.supportsBridgingPCH, producePCHJob, let input = importedObjCHeader else {
29312959
return nil
29322960
}
29332961

Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ public struct ExternalTargetModuleDetails {
2727
let isFramework: Bool
2828
}
2929

30+
/// A chained bridging header file.
31+
public struct ChainedBridgingHeaderFile {
32+
let path: String
33+
let content: String
34+
}
35+
3036
public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalTargetModuleDetails]
3137

3238
/// In Explicit Module Build mode, this planner is responsible for generating and providing
@@ -471,6 +477,17 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
471477
return mainModuleDetails.contextHash
472478
}
473479

480+
/// Get the chained bridging header info
481+
public func getChainedBridgingHeaderFile() throws -> ChainedBridgingHeaderFile? {
482+
let mainModuleId: ModuleDependencyId = .swift(dependencyGraph.mainModuleName)
483+
let mainModuleDetails = try dependencyGraph.swiftModuleDetails(of: mainModuleId)
484+
guard let path = mainModuleDetails.chainedBridgingHeaderPath,
485+
let content = mainModuleDetails.chainedBridgingHeaderContent else{
486+
return nil
487+
}
488+
return ChainedBridgingHeaderFile(path: path, content: content)
489+
}
490+
474491
/// Resolve all module dependencies of the main module and add them to the lists of
475492
/// inputs and command line flags.
476493
public mutating func resolveBridgingHeaderDependencies(inputs: inout [TypedVirtualPath],

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public struct SwiftModuleDetails: Codable, Hashable {
124124
/// Options to the compile command
125125
public var commandLine: [String]? = []
126126

127-
/// Options to the compile command
127+
/// Options to the compile bridging header command
128128
public var bridgingPchCommandLine: [String]? = []
129129

130130
/// The context hash for this module that encodes the producing interface's path,
@@ -145,6 +145,11 @@ public struct SwiftModuleDetails: Codable, Hashable {
145145

146146
/// The module cache key of the output module.
147147
public var moduleCacheKey: String?
148+
149+
/// Chained bridging header path
150+
public var chainedBridgingHeaderPath: String?
151+
/// Chained bridging header content
152+
public var chainedBridgingHeaderContent: String?
148153
}
149154

150155
/// Details specific to Swift placeholder dependencies.

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,25 @@ public extension Driver {
141141
}
142142
}
143143

144+
if isFrontendArgSupported(.experimentalBridgingHeaderChaining) {
145+
try commandLine.appendLast(.experimentalBridgingHeaderChaining, from: &parsedOptions)
146+
}
147+
148+
// Provide a directory to path to scanner for where the chained bridging header will be.
149+
// Prefer writing next to pch output, otherwise next to module output path before fallback to temp directory for non-caching build.
150+
if isFrontendArgSupported(.scannerOutputDir) {
151+
if let outputDir = parsedOptions.getLastArgument(.pchOutputDir)?.asSingle {
152+
commandLine.appendFlag(.scannerOutputDir)
153+
commandLine.appendFlag(outputDir)
154+
} else if let outputModule = moduleOutputInfo.output {
155+
commandLine.appendFlag(.scannerOutputDir)
156+
commandLine.appendFlag(VirtualPath.lookup(outputModule.outputPath).parentDirectory.name)
157+
} else if !enableCaching, let tempDir = try? fileSystem.tempDirectory {
158+
commandLine.appendFlag(.scannerOutputDir)
159+
commandLine.appendFlag(tempDir.pathString)
160+
}
161+
}
162+
144163
// Pass on the input files
145164
commandLine.append(contentsOf: inputFiles.filter { $0.type == .swift }.map { .path($0.file) })
146165
return (inputs, commandLine)

Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -451,9 +451,9 @@ extension Driver {
451451
try commandLine.appendAll(.Xcc, from: &parsedOptions)
452452
}
453453

454-
if let importedObjCHeader = importedObjCHeader,
454+
let objcHeaderFile = (kind == .scanDependencies) ? originalObjCHeaderFile : importedObjCHeader
455+
if let importedObjCHeader = objcHeaderFile,
455456
bridgingHeaderHandling != .ignored {
456-
commandLine.appendFlag(.importObjcHeader)
457457
if bridgingHeaderHandling == .precompiled,
458458
let pch = bridgingPrecompiledHeader {
459459
// For explicit module build, we directly pass the compiled pch as
@@ -462,15 +462,27 @@ extension Driver {
462462
// of a lookup failure.
463463
if parsedOptions.contains(.pchOutputDir) &&
464464
!parsedOptions.contains(.driverExplicitModuleBuild) {
465+
commandLine.appendFlag(.importObjcHeader)
465466
try addPathArgument(VirtualPath.lookup(importedObjCHeader), to:&commandLine, remap: jobNeedPathRemap)
466467
try commandLine.appendLast(.pchOutputDir, from: &parsedOptions)
467468
if !compilerMode.isSingleCompilation {
468469
commandLine.appendFlag(.pchDisableValidation)
469470
}
470471
} else {
471-
try addPathArgument(VirtualPath.lookup(pch), to:&commandLine, remap: jobNeedPathRemap)
472+
if isFrontendArgSupported(.importPch) {
473+
commandLine.appendFlag(.importPch)
474+
try addPathArgument(VirtualPath.lookup(pch), to:&commandLine, remap: jobNeedPathRemap)
475+
if let originalHeader = originalObjCHeaderFile {
476+
commandLine.appendFlag(.importObjcHeader)
477+
try addPathArgument(VirtualPath.lookup(originalHeader), to:&commandLine, remap: jobNeedPathRemap)
478+
}
479+
} else {
480+
commandLine.appendFlag(.importObjcHeader)
481+
try addPathArgument(VirtualPath.lookup(pch), to:&commandLine, remap: jobNeedPathRemap)
482+
}
472483
}
473484
} else {
485+
commandLine.appendFlag(.importObjcHeader)
474486
try addPathArgument(VirtualPath.lookup(importedObjCHeader), to:&commandLine, remap: jobNeedPathRemap)
475487
}
476488
}

Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ private extension SwiftScan {
188188
let isFramework = api.swiftscan_swift_textual_detail_get_is_framework(moduleDetailsRef)
189189
let moduleCacheKey = supportsCaching ? try getOptionalStringDetail(from: moduleDetailsRef,
190190
using: api.swiftscan_swift_textual_detail_get_module_cache_key) : nil
191+
let chainedBridgingHeaderPath = supportsChainedBridgingHeader ?
192+
try getOptionalStringDetail(from: moduleDetailsRef, using: api.swiftscan_swift_textual_detail_get_chained_bridging_header_path) : nil
193+
let chainedBridgingHeaderContent = supportsChainedBridgingHeader ?
194+
try getOptionalStringDetail(from: moduleDetailsRef, using: api.swiftscan_swift_textual_detail_get_chained_bridging_header_content) : nil
191195

192196
// Decode all dependencies of this module
193197
let swiftOverlayDependencies: [ModuleDependencyId]?
@@ -209,7 +213,9 @@ private extension SwiftScan {
209213
extraPcmArgs: extraPcmArgs,
210214
isFramework: isFramework,
211215
swiftOverlayDependencies: swiftOverlayDependencies,
212-
moduleCacheKey: moduleCacheKey)
216+
moduleCacheKey: moduleCacheKey,
217+
chainedBridgingHeaderPath: chainedBridgingHeaderPath,
218+
chainedBridgingHeaderContent: chainedBridgingHeaderContent)
213219
}
214220

215221
/// Construct a `SwiftPrebuiltExternalModuleDetails` from a `swiftscan_module_details_t` reference

Sources/SwiftDriver/SwiftScan/SwiftScan.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ private extension String {
294294
return api.swiftscan_swift_textual_detail_get_bridging_pch_command_line != nil
295295
}
296296

297+
@_spi(Testing) public var supportsChainedBridgingHeader : Bool {
298+
return api.swiftscan_swift_textual_detail_get_chained_bridging_header_path != nil &&
299+
api.swiftscan_swift_textual_detail_get_chained_bridging_header_content != nil
300+
}
297301

298302
@_spi(Testing) public var canQueryPerScanDiagnostics : Bool {
299303
return api.swiftscan_dependency_graph_get_diagnostics != nil &&
@@ -507,6 +511,10 @@ private extension swiftscan_functions_t {
507511
// Bridging PCH build command-line
508512
self.swiftscan_swift_textual_detail_get_bridging_pch_command_line =
509513
loadOptional("swiftscan_swift_textual_detail_get_bridging_pch_command_line")
514+
self.swiftscan_swift_textual_detail_get_chained_bridging_header_path =
515+
loadOptional("swiftscan_swift_textual_detail_get_chained_bridging_header_path")
516+
self.swiftscan_swift_textual_detail_get_chained_bridging_header_content =
517+
loadOptional("swiftscan_swift_textual_detail_get_chained_bridging_header_content")
510518

511519
// Caching related APIs.
512520
self.swiftscan_swift_textual_detail_get_module_cache_key =

0 commit comments

Comments
 (0)