Skip to content

Commit 9324590

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 bfb57ed commit 9324590

File tree

13 files changed

+272
-59
lines changed

13 files changed

+272
-59
lines changed

Sources/CSwiftScan/include/swiftscan_header.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
#include <stddef.h>
1818
#include <stdint.h>
1919

20-
#define SWIFTSCAN_VERSION_MAJOR 1
21-
#define SWIFTSCAN_VERSION_MINOR 0
20+
#define SWIFTSCAN_VERSION_MAJOR 2
21+
#define SWIFTSCAN_VERSION_MINOR 1
2222

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

@@ -143,6 +143,12 @@ typedef struct {
143143
(*swiftscan_swift_textual_detail_get_swift_overlay_dependencies)(swiftscan_module_details_t);
144144
swiftscan_string_ref_t
145145
(*swiftscan_swift_textual_detail_get_module_cache_key)(swiftscan_module_details_t);
146+
swiftscan_string_ref_t
147+
(*swiftscan_swift_textual_detail_get_user_module_version)(swiftscan_module_details_t);
148+
swiftscan_string_ref_t
149+
(*swiftscan_swift_textual_detail_get_chained_bridging_header_path)(swiftscan_module_details_t);
150+
swiftscan_string_ref_t
151+
(*swiftscan_swift_textual_detail_get_chained_bridging_header_content)(swiftscan_module_details_t);
146152

147153
//=== Swift Binary Module Details query APIs ------------------------------===//
148154
swiftscan_string_ref_t

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 87 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -336,17 +336,38 @@ 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+
!inputFiles.contains { $0.type == .swift },
350+
"should not be queried before scanning")
351+
let chainedBridgingHeader = try? explicitDependencyBuildPlanner?.getChainedBridgingHeaderFile()
352+
return try? computeImportedObjCHeader(&parsedOptions, compilerMode: compilerMode,
353+
chainedBridgingHeader: chainedBridgingHeader) ?? originalObjCHeaderFile
354+
}()
355+
356+
/// The directory to emit PCH file.
357+
lazy var bridgingPrecompiledHeaderOutputDir: VirtualPath? = {
358+
return try? computePrecompiledBridgingHeaderDir(&parsedOptions,
359+
compilerMode: compilerMode)
360+
}()
341361

342362
/// The path to the pch for the imported Objective-C header.
343363
lazy var bridgingPrecompiledHeader: VirtualPath.Handle? = {
344364
let contextHash = try? explicitDependencyBuildPlanner?.getMainModuleContextHash()
345-
return Self.computeBridgingPrecompiledHeader(&parsedOptions,
346-
compilerMode: compilerMode,
347-
importedObjCHeader: importedObjCHeader,
348-
outputFileMap: outputFileMap,
349-
contextHash: contextHash)
365+
return computeBridgingPrecompiledHeader(&parsedOptions,
366+
compilerMode: compilerMode,
367+
importedObjCHeader: importedObjCHeader,
368+
outputFileMap: outputFileMap,
369+
outputDirectory: bridgingPrecompiledHeaderOutputDir,
370+
contextHash: contextHash)
350371
}()
351372

352373
/// Path to the dependencies file.
@@ -1053,8 +1074,6 @@ public struct Driver {
10531074
parsedOptions: parsedOptions,
10541075
recordedInputModificationDates: recordedInputModificationDates)
10551076

1056-
self.importedObjCHeader = try Self.computeImportedObjCHeader(&parsedOptions, compilerMode: compilerMode, diagnosticEngine: diagnosticEngine)
1057-
10581077
self.supportedFrontendFlags =
10591078
try Self.computeSupportedCompilerArgs(of: self.toolchain,
10601079
libSwiftScan: self.swiftScanLibInstance,
@@ -1079,16 +1098,38 @@ public struct Driver {
10791098
diagnosticsEngine.emit(.warning("-cache-compile-job cannot be used without explicit module build, turn off caching"),
10801099
location: nil)
10811100
self.enableCaching = false
1082-
} else if importedObjCHeader != nil, !parsedOptions.hasFlag(positive: .enableBridgingPch, negative: .disableBridgingPch, default: true) {
1083-
diagnosticsEngine.emit(.warning("-cache-compile-job cannot be used with -disable-bridging-pch, turn off caching"),
1084-
location: nil)
1085-
self.enableCaching = false
10861101
} else {
10871102
self.enableCaching = true
10881103
}
10891104
} else {
10901105
self.enableCaching = false
10911106
}
1107+
1108+
// PCH related options.
1109+
if parsedOptions.hasArgument(.importObjcHeader) {
1110+
// Check for conflicting options.
1111+
if parsedOptions.hasArgument(.importUnderlyingModule) {
1112+
diagnosticEngine.emit(.error_framework_bridging_header)
1113+
}
1114+
1115+
if parsedOptions.hasArgument(.emitModuleInterface, .emitModuleInterfacePath) {
1116+
diagnosticEngine.emit(.error_bridging_header_module_interface)
1117+
}
1118+
}
1119+
var maybeNeedPCH = parsedOptions.hasFlag(positive: .enableBridgingPch, negative: .disableBridgingPch, default: true)
1120+
if enableCaching && !maybeNeedPCH {
1121+
diagnosticsEngine.emit(.warning("-cache-compile-job cannot be used with -disable-bridging-pch, turn on PCH generation"),
1122+
location: nil)
1123+
maybeNeedPCH = true
1124+
}
1125+
self.producePCHJob = maybeNeedPCH
1126+
1127+
if let objcHeaderPathArg = parsedOptions.getLastArgument(.importObjcHeader) {
1128+
self.originalObjCHeaderFile = try? VirtualPath.intern(path: objcHeaderPathArg.asSingle)
1129+
} else {
1130+
self.originalObjCHeaderFile = nil
1131+
}
1132+
10921133
self.useClangIncludeTree = !parsedOptions.hasArgument(.noClangIncludeTree) && !env.keys.contains("SWIFT_CACHING_USE_CLANG_CAS_FS")
10931134
self.scannerPrefixMap = try Self.computeScanningPrefixMapper(&parsedOptions)
10941135
if let sdkMapping = parsedOptions.getLastArgument(.scannerPrefixMapSdk)?.asSingle {
@@ -3068,36 +3109,47 @@ extension Driver {
30683109
// Imported Objective-C header.
30693110
extension Driver {
30703111
/// Compute the path of the imported Objective-C header.
3071-
static func computeImportedObjCHeader(
3112+
func computeImportedObjCHeader(
30723113
_ parsedOptions: inout ParsedOptions,
30733114
compilerMode: CompilerMode,
3074-
diagnosticEngine: DiagnosticsEngine
3075-
) throws -> VirtualPath.Handle? {
3076-
guard let objcHeaderPathArg = parsedOptions.getLastArgument(.importObjcHeader) else {
3077-
return nil
3115+
chainedBridgingHeader: ChainedBridgingHeaderFile?) throws -> VirtualPath.Handle? {
3116+
// handle chained bridging header.
3117+
if let chainedHeader = chainedBridgingHeader, !chainedHeader.path.isEmpty {
3118+
let path = try VirtualPath(path: chainedHeader.path)
3119+
let dirExists = try fileSystem.exists(path.parentDirectory)
3120+
if !dirExists, let dirToCreate = path.parentDirectory.absolutePath {
3121+
try fileSystem.createDirectory(dirToCreate, recursive: true)
3122+
}
3123+
try fileSystem.writeFileContents(path,
3124+
bytes: ByteString(encodingAsUTF8: chainedHeader.content),
3125+
atomically: true)
3126+
return path.intern()
30783127
}
3128+
return originalObjCHeaderFile
3129+
}
30793130

3080-
// Check for conflicting options.
3081-
if parsedOptions.hasArgument(.importUnderlyingModule) {
3082-
diagnosticEngine.emit(.error_framework_bridging_header)
3131+
/// Compute the path to the bridging precompiled header directory path.
3132+
func computePrecompiledBridgingHeaderDir(
3133+
_ parsedOptions: inout ParsedOptions,
3134+
compilerMode: CompilerMode) throws -> VirtualPath? {
3135+
if let input = originalObjCHeaderFile,
3136+
let outputPath = try? outputFileMap?.existingOutput(inputFile: input, outputType: .pch) {
3137+
return VirtualPath.lookup(outputPath).parentDirectory
30833138
}
3084-
3085-
if parsedOptions.hasArgument(.emitModuleInterface, .emitModuleInterfacePath) {
3086-
diagnosticEngine.emit(.error_bridging_header_module_interface)
3139+
if let outputDir = parsedOptions.getLastArgument(.pchOutputDir)?.asSingle {
3140+
return try VirtualPath(path: outputDir)
30873141
}
3088-
3089-
return try VirtualPath.intern(path: objcHeaderPathArg.asSingle)
3142+
return nil
30903143
}
30913144

30923145
/// Compute the path of the generated bridging PCH for the Objective-C header.
3093-
static func computeBridgingPrecompiledHeader(_ parsedOptions: inout ParsedOptions,
3094-
compilerMode: CompilerMode,
3095-
importedObjCHeader: VirtualPath.Handle?,
3096-
outputFileMap: OutputFileMap?,
3097-
contextHash: String?) -> VirtualPath.Handle? {
3098-
guard compilerMode.supportsBridgingPCH,
3099-
let input = importedObjCHeader,
3100-
parsedOptions.hasFlag(positive: .enableBridgingPch, negative: .disableBridgingPch, default: true) else {
3146+
func computeBridgingPrecompiledHeader(_ parsedOptions: inout ParsedOptions,
3147+
compilerMode: CompilerMode,
3148+
importedObjCHeader: VirtualPath.Handle?,
3149+
outputFileMap: OutputFileMap?,
3150+
outputDirectory: VirtualPath?,
3151+
contextHash: String?) -> VirtualPath.Handle? {
3152+
guard compilerMode.supportsBridgingPCH, producePCHJob, let input = importedObjCHeader else {
31013153
return nil
31023154
}
31033155

@@ -3112,8 +3164,8 @@ extension Driver {
31123164
} else {
31133165
pchFile = baseName.appendingFileTypeExtension(.pch)
31143166
}
3115-
if let outputDirectory = parsedOptions.getLastArgument(.pchOutputDir)?.asSingle {
3116-
return try? VirtualPath(path: outputDirectory).appending(component: pchFile).intern()
3167+
if let outputDirectory = outputDirectory {
3168+
return outputDirectory.appending(component: pchFile).intern()
31173169
} else {
31183170
return try? VirtualPath.temporary(RelativePath(validating: pchFile)).intern()
31193171
}

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
@@ -451,6 +457,17 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
451457
return mainModuleDetails.contextHash
452458
}
453459

460+
/// Get the chained bridging header info
461+
public func getChainedBridgingHeaderFile() throws -> ChainedBridgingHeaderFile? {
462+
let mainModuleId: ModuleDependencyId = .swift(dependencyGraph.mainModuleName)
463+
let mainModuleDetails = try dependencyGraph.swiftModuleDetails(of: mainModuleId)
464+
guard let path = mainModuleDetails.chainedBridgingHeaderPath,
465+
let content = mainModuleDetails.chainedBridgingHeaderContent else{
466+
return nil
467+
}
468+
return ChainedBridgingHeaderFile(path: path, content: content)
469+
}
470+
454471
/// Resolve all module dependencies of the main module and add them to the lists of
455472
/// inputs and command line flags.
456473
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,
@@ -140,6 +140,11 @@ public struct SwiftModuleDetails: Codable, Hashable {
140140

141141
/// The module cache key of the output module.
142142
public var moduleCacheKey: String?
143+
144+
/// Chained bridging header path
145+
public var chainedBridgingHeaderPath: String?
146+
/// Chained bridging header content
147+
public var chainedBridgingHeaderContent: String?
143148
}
144149

145150
/// Details specific to Swift placeholder dependencies.

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import protocol TSCBasic.FileSystem
1414
import struct TSCBasic.AbsolutePath
15+
import struct TSCBasic.RelativePath
1516
import struct TSCBasic.Diagnostic
1617
import var TSCBasic.localFileSystem
1718
import var TSCBasic.stdoutStream
@@ -141,6 +142,29 @@ public extension Driver {
141142
}
142143
}
143144

145+
if isFrontendArgSupported(.autoBridgingHeaderChaining) {
146+
if parsedOptions.hasFlag(positive: .autoBridgingHeaderChaining,
147+
negative: .noAutoBridgingHeaderChaining,
148+
default: false) || isCachingEnabled {
149+
commandLine.appendFlag(.autoBridgingHeaderChaining)
150+
} else {
151+
commandLine.appendFlag(.noAutoBridgingHeaderChaining)
152+
}
153+
}
154+
155+
// Provide a directory to path to scanner for where the chained bridging header will be.
156+
// Prefer writing next to pch output, otherwise next to module output path before fallback to temp directory for non-caching build.
157+
if isFrontendArgSupported(.scannerOutputDir) {
158+
if let outputDir = try? computePrecompiledBridgingHeaderDir(&parsedOptions,
159+
compilerMode: compilerMode) {
160+
commandLine.appendFlag(.scannerOutputDir)
161+
commandLine.appendPath(outputDir)
162+
} else {
163+
commandLine.appendFlag(.scannerOutputDir)
164+
commandLine.appendPath(VirtualPath.temporary(try RelativePath(validating: "scanner")))
165+
}
166+
}
167+
144168
// Pass on the input files
145169
commandLine.append(contentsOf: inputFiles.filter { $0.type == .swift }.map { .path($0.file) })
146170
return (inputs, commandLine)

Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift

Lines changed: 17 additions & 7 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
}
@@ -953,8 +965,7 @@ extension Driver {
953965
return [:]
954966
}
955967
// Resolve command-line first.
956-
let resolver = try ArgsResolver(fileSystem: fileSystem)
957-
let arguments: [String] = try resolver.resolveArgumentList(for: commandLine)
968+
let arguments: [String] = try executor.resolver.resolveArgumentList(for: commandLine)
958969

959970
return try inputs.reduce(into: [:]) { keys, input in
960971
keys[input.0] = try cas.computeCacheKey(commandLine: arguments, index: input.1)
@@ -968,8 +979,7 @@ extension Driver {
968979
return nil
969980
}
970981
// Resolve command-line first.
971-
let resolver = try ArgsResolver(fileSystem: fileSystem)
972-
let arguments: [String] = try resolver.resolveArgumentList(for: commandLine)
982+
let arguments: [String] = try executor.resolver.resolveArgumentList(for: commandLine)
973983
return try cas.computeCacheKey(commandLine: arguments, index: index)
974984
}
975985
}

Sources/SwiftDriver/Jobs/VerifyModuleInterfaceJob.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ extension Driver {
3535
var inputs: [TypedVirtualPath] = [interfaceInput]
3636
commandLine.appendFlags("-frontend", "-typecheck-module-from-interface")
3737
try addPathArgument(interfaceInput.file, to: &commandLine)
38-
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .verifyModuleInterface)
38+
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .verifyModuleInterface, bridgingHeaderHandling: .ignored)
3939
// FIXME: MSVC runtime flags
4040

4141
// Output serialized diagnostics for this job, if specifically requested

Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ private extension SwiftScan {
184184
let isFramework = api.swiftscan_swift_textual_detail_get_is_framework(moduleDetailsRef)
185185
let moduleCacheKey = supportsCaching ? try getOptionalStringDetail(from: moduleDetailsRef,
186186
using: api.swiftscan_swift_textual_detail_get_module_cache_key) : nil
187+
let chainedBridgingHeaderPath = supportsChainedBridgingHeader ?
188+
try getOptionalStringDetail(from: moduleDetailsRef, using: api.swiftscan_swift_textual_detail_get_chained_bridging_header_path) : nil
189+
let chainedBridgingHeaderContent = supportsChainedBridgingHeader ?
190+
try getOptionalStringDetail(from: moduleDetailsRef, using: api.swiftscan_swift_textual_detail_get_chained_bridging_header_content) : nil
187191

188192
// Decode all dependencies of this module
189193
let swiftOverlayDependencies: [ModuleDependencyId]?
@@ -204,7 +208,9 @@ private extension SwiftScan {
204208
contextHash: contextHash,
205209
isFramework: isFramework,
206210
swiftOverlayDependencies: swiftOverlayDependencies,
207-
moduleCacheKey: moduleCacheKey)
211+
moduleCacheKey: moduleCacheKey,
212+
chainedBridgingHeaderPath: chainedBridgingHeaderPath,
213+
chainedBridgingHeaderContent: chainedBridgingHeaderContent)
208214
}
209215

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

0 commit comments

Comments
 (0)