Skip to content

Commit ad8a328

Browse files
committed
[Explicit Module Builds] Specify which Clang module dependencies are bridging header dependencies
When passing in '-explicit-swift-module-map-file', specify which Clang modules are dependencies of textual headers of the main module and binary Swift module dependencies. This relies on a new entry-point in 'libSwiftScan': 'swiftscan_swift_binary_detail_get_header_dependency_module_dependencies'. The compiler will then use this information to determine which Clang modules require an explicit '-fmodule-map-file' ClangImporter input.
1 parent 412c92a commit ad8a328

File tree

8 files changed

+182
-54
lines changed

8 files changed

+182
-54
lines changed

Sources/CSwiftScan/include/swiftscan_header.h

+2
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ typedef struct {
155155
(*swiftscan_swift_binary_detail_get_is_framework)(swiftscan_module_details_t);
156156
swiftscan_string_ref_t
157157
(*swiftscan_swift_binary_detail_get_module_cache_key)(swiftscan_module_details_t);
158+
swiftscan_string_set_t *
159+
(*swiftscan_swift_binary_detail_get_header_dependency_module_dependencies)(swiftscan_module_details_t);
158160

159161
//=== Swift Placeholder Module Details query APIs -------------------------===//
160162
swiftscan_string_ref_t

Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift

+44-17
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
253253
inputs: inout [TypedVirtualPath],
254254
commandLine: inout [Job.ArgTemplate]) throws {
255255
// Prohibit the frontend from implicitly building textual modules into binary modules.
256-
var swiftDependencyArtifacts: [SwiftModuleArtifactInfo] = []
257-
var clangDependencyArtifacts: [ClangModuleArtifactInfo] = []
256+
var swiftDependencyArtifacts: Set<SwiftModuleArtifactInfo> = []
257+
var clangDependencyArtifacts: Set<ClangModuleArtifactInfo> = []
258258
try addModuleDependencies(of: moduleId,
259259
clangDependencyArtifacts: &clangDependencyArtifacts,
260260
swiftDependencyArtifacts: &swiftDependencyArtifacts)
@@ -276,8 +276,6 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
276276
inputs.append(TypedVirtualPath(file: headerDep.path, type: .pch))
277277
}
278278
}
279-
280-
// Clang module dependencies are specified on the command line explicitly
281279
for moduleArtifactInfo in clangDependencyArtifacts {
282280
let clangModulePath =
283281
TypedVirtualPath(file: moduleArtifactInfo.clangModulePath.path,
@@ -311,8 +309,9 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
311309

312310
private mutating func addModuleDependency(of moduleId: ModuleDependencyId,
313311
dependencyId: ModuleDependencyId,
314-
clangDependencyArtifacts: inout [ClangModuleArtifactInfo],
315-
swiftDependencyArtifacts: inout [SwiftModuleArtifactInfo]
312+
clangDependencyArtifacts: inout Set<ClangModuleArtifactInfo>,
313+
swiftDependencyArtifacts: inout Set<SwiftModuleArtifactInfo>,
314+
bridgingHeaderDeps: Set<ModuleDependencyId>? = nil
316315
) throws {
317316
switch dependencyId {
318317
case .swift:
@@ -325,7 +324,7 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
325324
isFramework = swiftModuleDetails.isFramework ?? false
326325
// Accumulate the required information about this dependency
327326
// TODO: add .swiftdoc and .swiftsourceinfo for this module.
328-
swiftDependencyArtifacts.append(
327+
swiftDependencyArtifacts.insert(
329328
SwiftModuleArtifactInfo(name: dependencyId.moduleName,
330329
modulePath: TextualVirtualPath(path: swiftModulePath.fileHandle),
331330
isFramework: isFramework,
@@ -335,11 +334,12 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
335334
let dependencyClangModuleDetails =
336335
try dependencyGraph.clangModuleDetails(of: dependencyId)
337336
// Accumulate the required information about this dependency
338-
clangDependencyArtifacts.append(
337+
clangDependencyArtifacts.insert(
339338
ClangModuleArtifactInfo(name: dependencyId.moduleName,
340339
modulePath: TextualVirtualPath(path: dependencyInfo.modulePath.path),
341340
moduleMapPath: dependencyClangModuleDetails.moduleMapPath,
342-
moduleCacheKey: dependencyClangModuleDetails.moduleCacheKey))
341+
moduleCacheKey: dependencyClangModuleDetails.moduleCacheKey,
342+
isBridgingHeaderDependency: bridgingHeaderDeps?.contains(dependencyId) ?? true))
343343
case .swiftPrebuiltExternal:
344344
let prebuiltModuleDetails = try dependencyGraph.swiftPrebuiltDetails(of: dependencyId)
345345
let compiledModulePath = prebuiltModuleDetails.compiledModulePath
@@ -348,7 +348,7 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
348348
.init(file: compiledModulePath.path, type: .swiftModule)
349349
// Accumulate the required information about this dependency
350350
// TODO: add .swiftdoc and .swiftsourceinfo for this module.
351-
swiftDependencyArtifacts.append(
351+
swiftDependencyArtifacts.insert(
352352
SwiftModuleArtifactInfo(name: dependencyId.moduleName,
353353
modulePath: TextualVirtualPath(path: swiftModulePath.fileHandle),
354354
headerDependencies: prebuiltModuleDetails.headerDependencyPaths,
@@ -359,19 +359,46 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
359359
}
360360
}
361361

362+
/// Collect the Set of all Clang module dependencies which are dependencies of either
363+
/// the `moduleId` bridging header or dependencies of bridging headers
364+
/// of any prebuilt binary Swift modules in the dependency graph.
365+
private func collectHeaderModuleDeps(of moduleId: ModuleDependencyId) throws -> Set<ModuleDependencyId>? {
366+
var bridgingHeaderDeps: Set<ModuleDependencyId>? = nil
367+
guard let moduleDependencies = reachabilityMap[moduleId] else {
368+
fatalError("Expected reachability information for the module: \(moduleId.moduleName).")
369+
}
370+
if let dependencySourceBridingHeaderDeps =
371+
try dependencyGraph.moduleInfo(of: moduleId).bridgingHeaderModuleDependencies {
372+
bridgingHeaderDeps = Set(dependencySourceBridingHeaderDeps)
373+
} else {
374+
bridgingHeaderDeps = Set<ModuleDependencyId>()
375+
}
376+
// Collect all binary Swift module dependnecies' header input module dependencies
377+
for dependencyId in moduleDependencies {
378+
if case .swiftPrebuiltExternal(_) = dependencyId {
379+
let prebuiltDependencyDetails = try dependencyGraph.swiftPrebuiltDetails(of: dependencyId)
380+
for headerDependency in prebuiltDependencyDetails.headerDependencyModuleDependencies ?? [] {
381+
bridgingHeaderDeps!.insert(headerDependency)
382+
}
383+
}
384+
}
385+
return bridgingHeaderDeps
386+
}
387+
362388
/// Add a specific module dependency as an input and a corresponding command
363389
/// line flag.
364390
private mutating func addModuleDependencies(of moduleId: ModuleDependencyId,
365-
clangDependencyArtifacts: inout [ClangModuleArtifactInfo],
366-
swiftDependencyArtifacts: inout [SwiftModuleArtifactInfo]
391+
clangDependencyArtifacts: inout Set<ClangModuleArtifactInfo>,
392+
swiftDependencyArtifacts: inout Set<SwiftModuleArtifactInfo>
367393
) throws {
368394
guard let moduleDependencies = reachabilityMap[moduleId] else {
369395
fatalError("Expected reachability information for the module: \(moduleId.moduleName).")
370396
}
371397
for dependencyId in moduleDependencies {
372398
try addModuleDependency(of: moduleId, dependencyId: dependencyId,
373399
clangDependencyArtifacts: &clangDependencyArtifacts,
374-
swiftDependencyArtifacts: &swiftDependencyArtifacts)
400+
swiftDependencyArtifacts: &swiftDependencyArtifacts,
401+
bridgingHeaderDeps: try collectHeaderModuleDeps(of: moduleId))
375402
}
376403
}
377404

@@ -437,8 +464,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
437464
public mutating func resolveBridgingHeaderDependencies(inputs: inout [TypedVirtualPath],
438465
commandLine: inout [Job.ArgTemplate]) throws {
439466
let mainModuleId: ModuleDependencyId = .swift(dependencyGraph.mainModuleName)
440-
var swiftDependencyArtifacts: [SwiftModuleArtifactInfo] = []
441-
var clangDependencyArtifacts: [ClangModuleArtifactInfo] = []
467+
var swiftDependencyArtifacts: Set<SwiftModuleArtifactInfo> = []
468+
var clangDependencyArtifacts: Set<ClangModuleArtifactInfo> = []
442469
let mainModuleDetails = try dependencyGraph.swiftModuleDetails(of: mainModuleId)
443470

444471
var addedDependencies: Set<ModuleDependencyId> = []
@@ -498,8 +525,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
498525

499526
/// Serialize the output file artifacts for a given module in JSON format.
500527
private func serializeModuleDependencies(for moduleId: ModuleDependencyId,
501-
swiftDependencyArtifacts: [SwiftModuleArtifactInfo],
502-
clangDependencyArtifacts: [ClangModuleArtifactInfo]
528+
swiftDependencyArtifacts: Set<SwiftModuleArtifactInfo>,
529+
clangDependencyArtifacts: Set<ClangModuleArtifactInfo>
503530
) throws -> Data {
504531
// The module dependency map in CAS needs to be stable.
505532
// Sort the dependencies by name.

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift

+16-25
Original file line numberDiff line numberDiff line change
@@ -164,24 +164,14 @@ public struct SwiftPrebuiltExternalModuleDetails: Codable, Hashable {
164164
/// The paths to the binary module's header dependencies
165165
public var headerDependencyPaths: [TextualVirtualPath]?
166166

167+
/// Clang module dependencies of the textual header input
168+
public var headerDependencyModuleDependencies: [ModuleDependencyId]?
169+
167170
/// A flag to indicate whether or not this module is a framework.
168171
public var isFramework: Bool?
169172

170173
/// The module cache key of the pre-built module.
171174
public var moduleCacheKey: String?
172-
173-
public init(compiledModulePath: TextualVirtualPath,
174-
moduleDocPath: TextualVirtualPath? = nil,
175-
moduleSourceInfoPath: TextualVirtualPath? = nil,
176-
headerDependencies: [TextualVirtualPath]? = nil,
177-
isFramework: Bool, moduleCacheKey: String? = nil) throws {
178-
self.compiledModulePath = compiledModulePath
179-
self.moduleDocPath = moduleDocPath
180-
self.moduleSourceInfoPath = moduleSourceInfoPath
181-
self.headerDependencyPaths = headerDependencies
182-
self.isFramework = isFramework
183-
self.moduleCacheKey = moduleCacheKey
184-
}
185175
}
186176

187177
/// Details specific to Clang modules.
@@ -201,18 +191,6 @@ public struct ClangModuleDetails: Codable, Hashable {
201191

202192
/// The module cache key of the output module.
203193
public var moduleCacheKey: String?
204-
205-
public init(moduleMapPath: TextualVirtualPath,
206-
contextHash: String,
207-
commandLine: [String],
208-
capturedPCMArgs: Set<[String]>?,
209-
moduleCacheKey: String? = nil) {
210-
self.moduleMapPath = moduleMapPath
211-
self.contextHash = contextHash
212-
self.commandLine = commandLine
213-
self.capturedPCMArgs = capturedPCMArgs
214-
self.moduleCacheKey = moduleCacheKey
215-
}
216194
}
217195

218196
public struct ModuleInfo: Codable, Hashable {
@@ -302,6 +280,19 @@ extension ModuleInfo.Details: Codable {
302280
}
303281
}
304282

283+
extension ModuleInfo {
284+
var bridgingHeaderModuleDependencies: [ModuleDependencyId]? {
285+
switch details {
286+
case .swift(let swiftDetails):
287+
return swiftDetails.bridgingHeaderDependencies
288+
case .swiftPrebuiltExternal(let swiftPrebuiltDetails):
289+
return swiftPrebuiltDetails.headerDependencyModuleDependencies
290+
default:
291+
return nil
292+
}
293+
}
294+
}
295+
305296
/// Describes the complete set of dependencies for a Swift module, including
306297
/// all of the Swift and C modules and source files it depends on.
307298
public struct InterModuleDependencyGraph: Codable {

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift

+7
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ public class InterModuleDependencyOracle {
132132
return swiftScan.hasBinarySwiftModuleIsFramework
133133
}
134134

135+
@_spi(Testing) public func supportsBinaryModuleHeaderModuleDependencies() throws -> Bool {
136+
guard let swiftScan = swiftScanLibInstance else {
137+
fatalError("Attempting to query supported scanner API with no scanner instance.")
138+
}
139+
return swiftScan.hasBinarySwiftModuleHeaderModuleDependencies
140+
}
141+
135142
@_spi(Testing) public func supportsScannerDiagnostics() throws -> Bool {
136143
guard let swiftScan = swiftScanLibInstance else {
137144
fatalError("Attempting to query supported scanner API with no scanner instance.")

Sources/SwiftDriver/ExplicitModuleBuilds/SerializableModuleArtifacts.swift

+20-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
/// - Swift Module Path
1616
/// - Swift Doc Path
1717
/// - Swift Source Info Path
18-
@_spi(Testing) public struct SwiftModuleArtifactInfo: Codable {
18+
@_spi(Testing) public struct SwiftModuleArtifactInfo: Codable, Hashable {
1919
/// The module's name
2020
public let moduleName: String
2121
/// The path for the module's .swiftmodule file
@@ -48,7 +48,7 @@
4848
/// - Clang Module (name)
4949
/// - Clang Module (PCM) Path
5050
/// - Clang Module Map Path
51-
@_spi(Testing) public struct ClangModuleArtifactInfo: Codable {
51+
@_spi(Testing) public struct ClangModuleArtifactInfo: Codable, Hashable {
5252
/// The module's name
5353
public let moduleName: String
5454
/// The path for the module's .pcm file
@@ -57,24 +57,28 @@
5757
public let clangModuleMapPath: TextualVirtualPath
5858
/// A flag to indicate whether this module is a framework
5959
public let isFramework: Bool
60+
/// A flag to indicate whether this module is a dependency
61+
/// of the main module's bridging header
62+
public let isBridgingHeaderDependency: Bool
6063
/// The cache key for the module.
6164
public let clangModuleCacheKey: String?
6265

6366
init(name: String, modulePath: TextualVirtualPath, moduleMapPath: TextualVirtualPath,
64-
moduleCacheKey: String? = nil) {
67+
moduleCacheKey: String? = nil, isBridgingHeaderDependency: Bool = true) {
6568
self.moduleName = name
6669
self.clangModulePath = modulePath
6770
self.clangModuleMapPath = moduleMapPath
6871
self.isFramework = false
72+
self.isBridgingHeaderDependency = isBridgingHeaderDependency
6973
self.clangModuleCacheKey = moduleCacheKey
7074
}
7175
}
7276

73-
enum ModuleDependencyArtifactInfo: Codable {
77+
@_spi(Testing) public enum ModuleDependencyArtifactInfo: Codable {
7478
case clang(ClangModuleArtifactInfo)
7579
case swift(SwiftModuleArtifactInfo)
7680

77-
func encode(to encoder: Encoder) throws {
81+
@_spi(Testing) public func encode(to encoder: Encoder) throws {
7882
var container = encoder.singleValueContainer()
7983
switch self {
8084
case .swift(let swiftInfo):
@@ -83,6 +87,17 @@ enum ModuleDependencyArtifactInfo: Codable {
8387
try container.encode(clangInfo)
8488
}
8589
}
90+
91+
@_spi(Testing) public init(from decoder: Decoder) throws {
92+
let container = try decoder.singleValueContainer()
93+
do {
94+
let thing = try container.decode(SwiftModuleArtifactInfo.self)
95+
self = .swift(thing)
96+
} catch {
97+
let thing = try container.decode(ClangModuleArtifactInfo.self)
98+
self = .clang(thing)
99+
}
100+
}
86101
}
87102

88103
/// Describes a given module's batch dependency scanning input info

Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift

+13-6
Original file line numberDiff line numberDiff line change
@@ -249,15 +249,22 @@ private extension SwiftScan {
249249
} else {
250250
isFramework = false
251251
}
252+
253+
let headerDependencyModuleDependencies: [ModuleDependencyId]? =
254+
hasBinarySwiftModuleHeaderModuleDependencies ?
255+
try getOptionalStringArrayDetail(from: moduleDetailsRef,
256+
using: api.swiftscan_swift_binary_detail_get_header_dependency_module_dependencies)?.map { .clang($0) } : nil
257+
252258
let moduleCacheKey = supportsCaching ? try getOptionalStringDetail(from: moduleDetailsRef,
253259
using: api.swiftscan_swift_binary_detail_get_module_cache_key) : nil
254260

255-
return try SwiftPrebuiltExternalModuleDetails(compiledModulePath: compiledModulePath,
256-
moduleDocPath: moduleDocPath,
257-
moduleSourceInfoPath: moduleSourceInfoPath,
258-
headerDependencies: headerDependencies,
259-
isFramework: isFramework,
260-
moduleCacheKey: moduleCacheKey)
261+
return SwiftPrebuiltExternalModuleDetails(compiledModulePath: compiledModulePath,
262+
moduleDocPath: moduleDocPath,
263+
moduleSourceInfoPath: moduleSourceInfoPath,
264+
headerDependencyPaths: headerDependencies,
265+
headerDependencyModuleDependencies: headerDependencyModuleDependencies,
266+
isFramework: isFramework,
267+
moduleCacheKey: moduleCacheKey)
261268
}
262269

263270
/// Construct a `SwiftPlaceholderModuleDetails` from a `swiftscan_module_details_t` reference

Sources/SwiftDriver/SwiftScan/SwiftScan.swift

+9
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,10 @@ internal extension swiftscan_diagnostic_severity_t {
268268
api.swiftscan_swift_binary_detail_get_is_framework != nil
269269
}
270270

271+
@_spi(Testing) public var hasBinarySwiftModuleHeaderModuleDependencies : Bool {
272+
api.swiftscan_swift_binary_detail_get_header_dependency_module_dependencies != nil
273+
}
274+
271275
@_spi(Testing) public var canLoadStoreScannerCache : Bool {
272276
api.swiftscan_scanner_cache_load != nil &&
273277
api.swiftscan_scanner_cache_serialize != nil &&
@@ -534,6 +538,11 @@ private extension swiftscan_functions_t {
534538
self.swiftscan_swift_binary_detail_get_is_framework =
535539
try loadOptional("swiftscan_swift_binary_detail_get_is_framework")
536540

541+
// Clang module dependencies of header input of binary module dependencies
542+
self.swiftscan_swift_binary_detail_get_header_dependency_module_dependencies =
543+
try loadOptional("swiftscan_swift_binary_detail_get_header_dependency_module_dependencies")
544+
545+
// Bridging PCH build command-line
537546
self.swiftscan_swift_textual_detail_get_bridging_pch_command_line =
538547
try loadOptional("swiftscan_swift_textual_detail_get_bridging_pch_command_line")
539548

0 commit comments

Comments
 (0)