Skip to content

Commit 7f4c42c

Browse files
authored
Merge pull request #1296 from artemcm/BridgingHeaderDepScan
[Dependency Scanning] Pass the bridging header path to scanning action invocations
2 parents 3a2ccf4 + 176fb0a commit 7f4c42c

File tree

7 files changed

+143
-46
lines changed

7 files changed

+143
-46
lines changed

Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift

Lines changed: 107 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
248248
// Prohibit the frontend from implicitly building textual modules into binary modules.
249249
var swiftDependencyArtifacts: [SwiftModuleArtifactInfo] = []
250250
var clangDependencyArtifacts: [ClangModuleArtifactInfo] = []
251-
try addModuleDependencies(moduleId: moduleId, pcmArgs: pcmArgs,
251+
try addModuleDependencies(of: moduleId, pcmArgs: pcmArgs,
252252
clangDependencyArtifacts: &clangDependencyArtifacts,
253253
swiftDependencyArtifacts: &swiftDependencyArtifacts)
254254

@@ -285,54 +285,64 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
285285
}
286286
}
287287

288+
private mutating func addModuleDependency(of moduleId: ModuleDependencyId,
289+
dependencyId: ModuleDependencyId, pcmArgs: [String],
290+
clangDependencyArtifacts: inout [ClangModuleArtifactInfo],
291+
swiftDependencyArtifacts: inout [SwiftModuleArtifactInfo]
292+
) throws {
293+
switch dependencyId {
294+
case .swift:
295+
let dependencyInfo = try dependencyGraph.moduleInfo(of: dependencyId)
296+
let swiftModulePath: TypedVirtualPath
297+
let isFramework: Bool
298+
swiftModulePath = .init(file: dependencyInfo.modulePath.path,
299+
type: .swiftModule)
300+
isFramework = try dependencyGraph.swiftModuleDetails(of: dependencyId).isFramework ?? false
301+
// Accumulate the required information about this dependency
302+
// TODO: add .swiftdoc and .swiftsourceinfo for this module.
303+
swiftDependencyArtifacts.append(
304+
SwiftModuleArtifactInfo(name: dependencyId.moduleName,
305+
modulePath: TextualVirtualPath(path: swiftModulePath.fileHandle),
306+
isFramework: isFramework))
307+
case .clang:
308+
let dependencyInfo = try dependencyGraph.moduleInfo(of: dependencyId)
309+
let dependencyClangModuleDetails =
310+
try dependencyGraph.clangModuleDetails(of: dependencyId)
311+
// Accumulate the required information about this dependency
312+
clangDependencyArtifacts.append(
313+
ClangModuleArtifactInfo(name: dependencyId.moduleName,
314+
modulePath: TextualVirtualPath(path: dependencyInfo.modulePath.path),
315+
moduleMapPath: dependencyClangModuleDetails.moduleMapPath))
316+
case .swiftPrebuiltExternal:
317+
let prebuiltModuleDetails = try dependencyGraph.swiftPrebuiltDetails(of: dependencyId)
318+
let compiledModulePath = prebuiltModuleDetails.compiledModulePath
319+
let isFramework = prebuiltModuleDetails.isFramework ?? false
320+
let swiftModulePath: TypedVirtualPath =
321+
.init(file: compiledModulePath.path, type: .swiftModule)
322+
// Accumulate the required information about this dependency
323+
// TODO: add .swiftdoc and .swiftsourceinfo for this module.
324+
swiftDependencyArtifacts.append(
325+
SwiftModuleArtifactInfo(name: dependencyId.moduleName,
326+
modulePath: TextualVirtualPath(path: swiftModulePath.fileHandle),
327+
isFramework: isFramework))
328+
case .swiftPlaceholder:
329+
fatalError("Unresolved placeholder dependencies at planning stage: \(dependencyId) of \(moduleId)")
330+
}
331+
}
332+
288333
/// Add a specific module dependency as an input and a corresponding command
289334
/// line flag.
290-
private mutating func addModuleDependencies(moduleId: ModuleDependencyId, pcmArgs: [String],
335+
private mutating func addModuleDependencies(of moduleId: ModuleDependencyId, pcmArgs: [String],
291336
clangDependencyArtifacts: inout [ClangModuleArtifactInfo],
292337
swiftDependencyArtifacts: inout [SwiftModuleArtifactInfo]
293338
) throws {
294339
guard let moduleDependencies = reachabilityMap[moduleId] else {
295340
fatalError("Expected reachability information for the module: \(moduleId.moduleName).")
296341
}
297342
for dependencyId in moduleDependencies {
298-
switch dependencyId {
299-
case .swift:
300-
let dependencyInfo = try dependencyGraph.moduleInfo(of: dependencyId)
301-
let swiftModulePath: TypedVirtualPath
302-
let isFramework: Bool
303-
swiftModulePath = .init(file: dependencyInfo.modulePath.path,
304-
type: .swiftModule)
305-
isFramework = try dependencyGraph.swiftModuleDetails(of: dependencyId).isFramework ?? false
306-
// Accumulate the required information about this dependency
307-
// TODO: add .swiftdoc and .swiftsourceinfo for this module.
308-
swiftDependencyArtifacts.append(
309-
SwiftModuleArtifactInfo(name: dependencyId.moduleName,
310-
modulePath: TextualVirtualPath(path: swiftModulePath.fileHandle),
311-
isFramework: isFramework))
312-
case .clang:
313-
let dependencyInfo = try dependencyGraph.moduleInfo(of: dependencyId)
314-
let dependencyClangModuleDetails =
315-
try dependencyGraph.clangModuleDetails(of: dependencyId)
316-
// Accumulate the required information about this dependency
317-
clangDependencyArtifacts.append(
318-
ClangModuleArtifactInfo(name: dependencyId.moduleName,
319-
modulePath: TextualVirtualPath(path: dependencyInfo.modulePath.path),
320-
moduleMapPath: dependencyClangModuleDetails.moduleMapPath))
321-
case .swiftPrebuiltExternal:
322-
let prebuiltModuleDetails = try dependencyGraph.swiftPrebuiltDetails(of: dependencyId)
323-
let compiledModulePath = prebuiltModuleDetails.compiledModulePath
324-
let isFramework = prebuiltModuleDetails.isFramework ?? false
325-
let swiftModulePath: TypedVirtualPath =
326-
.init(file: compiledModulePath.path, type: .swiftModule)
327-
// Accumulate the required information about this dependency
328-
// TODO: add .swiftdoc and .swiftsourceinfo for this module.
329-
swiftDependencyArtifacts.append(
330-
SwiftModuleArtifactInfo(name: dependencyId.moduleName,
331-
modulePath: TextualVirtualPath(path: swiftModulePath.fileHandle),
332-
isFramework: isFramework))
333-
case .swiftPlaceholder:
334-
fatalError("Unresolved placeholder dependencies at planning stage: \(dependencyId) of \(moduleId)")
335-
}
343+
try addModuleDependency(of: moduleId, dependencyId: dependencyId, pcmArgs: pcmArgs,
344+
clangDependencyArtifacts: &clangDependencyArtifacts,
345+
swiftDependencyArtifacts: &swiftDependencyArtifacts)
336346
}
337347
}
338348

@@ -370,6 +380,63 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
370380
commandLine: &commandLine)
371381
}
372382

383+
/// Resolve all module dependencies of the main module and add them to the lists of
384+
/// inputs and command line flags.
385+
public mutating func resolveBridgingHeaderDependencies(inputs: inout [TypedVirtualPath],
386+
commandLine: inout [Job.ArgTemplate]) throws {
387+
let mainModuleId: ModuleDependencyId = .swift(dependencyGraph.mainModuleName)
388+
// Prohibit the frontend from implicitly building textual modules into binary modules.
389+
commandLine.appendFlags("-disable-implicit-swift-modules",
390+
"-Xcc", "-fno-implicit-modules",
391+
"-Xcc", "-fno-implicit-module-maps")
392+
393+
var swiftDependencyArtifacts: [SwiftModuleArtifactInfo] = []
394+
var clangDependencyArtifacts: [ClangModuleArtifactInfo] = []
395+
let mainModuleDetails = try dependencyGraph.swiftModuleDetails(of: mainModuleId)
396+
397+
var addedDependencies: Set<ModuleDependencyId> = []
398+
var dependenciesWorklist = mainModuleDetails.bridgingHeaderDependencies ?? []
399+
400+
while !dependenciesWorklist.isEmpty {
401+
guard let bridgingHeaderDepID = dependenciesWorklist.popLast() else {
402+
break
403+
}
404+
guard !addedDependencies.contains(bridgingHeaderDepID) else {
405+
continue
406+
}
407+
addedDependencies.insert(bridgingHeaderDepID)
408+
try addModuleDependency(of: mainModuleId, dependencyId: bridgingHeaderDepID, pcmArgs: [],
409+
clangDependencyArtifacts: &clangDependencyArtifacts,
410+
swiftDependencyArtifacts: &swiftDependencyArtifacts)
411+
try addModuleDependencies(of: bridgingHeaderDepID, pcmArgs: [],
412+
clangDependencyArtifacts: &clangDependencyArtifacts,
413+
swiftDependencyArtifacts: &swiftDependencyArtifacts)
414+
let depInfo = try dependencyGraph.moduleInfo(of: bridgingHeaderDepID)
415+
dependenciesWorklist.append(contentsOf: depInfo.directDependencies ?? [])
416+
}
417+
418+
// Clang module dependencies are specified on the command line explicitly
419+
for moduleArtifactInfo in clangDependencyArtifacts {
420+
let clangModulePath =
421+
TypedVirtualPath(file: moduleArtifactInfo.clangModulePath.path,
422+
type: .pcm)
423+
let clangModuleMapPath =
424+
TypedVirtualPath(file: moduleArtifactInfo.clangModuleMapPath.path,
425+
type: .clangModuleMap)
426+
inputs.append(clangModulePath)
427+
inputs.append(clangModuleMapPath)
428+
}
429+
430+
let dependencyFile =
431+
try serializeModuleDependencies(for: mainModuleId,
432+
swiftDependencyArtifacts: swiftDependencyArtifacts,
433+
clangDependencyArtifacts: clangDependencyArtifacts)
434+
commandLine.appendFlag("-explicit-swift-module-map-file")
435+
commandLine.appendPath(dependencyFile)
436+
inputs.append(TypedVirtualPath(file: dependencyFile.intern(),
437+
type: .jsonSwiftArtifacts))
438+
}
439+
373440
/// Store the output file artifacts for a given module in a JSON file, return the file's path.
374441
private func serializeModuleDependencies(for moduleId: ModuleDependencyId,
375442
swiftDependencyArtifacts: [SwiftModuleArtifactInfo],

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ public struct SwiftModuleDetails: Codable {
9797
/// The source files referenced by the bridging header.
9898
public var bridgingSourceFiles: [TextualVirtualPath]? = []
9999

100+
/// Modules that the bridging header specifically depends on
101+
public var bridgingHeaderDependencies: [ModuleDependencyId]? = []
102+
100103
/// Options to the compile command
101104
public var commandLine: [String]? = []
102105

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public extension Driver {
107107
commandLine.appendFlag("-frontend")
108108
commandLine.appendFlag("-scan-dependencies")
109109
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs,
110-
bridgingHeaderHandling: .ignored,
110+
bridgingHeaderHandling: .parsed,
111111
moduleDependencyGraphUse: .dependencyScan)
112112
// FIXME: MSVC runtime flags
113113

@@ -337,7 +337,7 @@ public extension Driver {
337337
commandLine.appendFlag("-scan-dependencies")
338338
commandLine.appendFlag("-import-prescan")
339339
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs,
340-
bridgingHeaderHandling: .ignored,
340+
bridgingHeaderHandling: .parsed,
341341
moduleDependencyGraphUse: .dependencyScan)
342342
// FIXME: MSVC runtime flags
343343

Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ extension Driver {
5353
commandLine: inout [Job.ArgTemplate],
5454
inputs: inout [TypedVirtualPath],
5555
bridgingHeaderHandling: BridgingHeaderHandling = .precompiled,
56-
moduleDependencyGraphUse: ModuleDependencyGraphUse = .computed
56+
moduleDependencyGraphUse: ModuleDependencyGraphUse = .computed,
57+
isGeneratePCH: Bool = false
5758
) throws {
5859
// Only pass -target to the REPL or immediate modes if it was explicitly
5960
// specified on the command line.
@@ -87,7 +88,11 @@ extension Driver {
8788
// May also be used for generation of the dependency graph itself in ExplicitModuleBuild mode.
8889
if (parsedOptions.contains(.driverExplicitModuleBuild) &&
8990
moduleDependencyGraphUse == .computed) {
90-
try addExplicitModuleBuildArguments(inputs: &inputs, commandLine: &commandLine)
91+
if isGeneratePCH {
92+
try addExplicitPCHBuildArguments(inputs: &inputs, commandLine: &commandLine)
93+
} else {
94+
try addExplicitModuleBuildArguments(inputs: &inputs, commandLine: &commandLine)
95+
}
9196
}
9297

9398
if let variant = parsedOptions.getLastArgument(.targetVariant)?.asSingle {
@@ -579,6 +584,16 @@ extension Driver {
579584
try dependencyPlanner.resolveMainModuleDependencies(inputs: &inputs, commandLine: &commandLine)
580585
}
581586

587+
/// Adds all dependencies required for an explicit module build of the bridging header
588+
/// to inputs and command line arguments of a compile job.
589+
func addExplicitPCHBuildArguments(inputs: inout [TypedVirtualPath],
590+
commandLine: inout [Job.ArgTemplate]) throws {
591+
guard var dependencyPlanner = explicitDependencyBuildPlanner else {
592+
fatalError("No dependency planner in Explicit Module Build mode.")
593+
}
594+
try dependencyPlanner.resolveBridgingHeaderDependencies(inputs: &inputs, commandLine: &commandLine)
595+
}
596+
582597
/// In Explicit Module Build mode, distinguish between main module jobs and intermediate dependency build jobs,
583598
/// such as Swift modules built from .swiftmodule files and Clang PCMs.
584599
public func isExplicitMainModuleJob(job: Job) -> Bool {

Sources/SwiftDriver/Jobs/GeneratePCHJob.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extension Driver {
2222
commandLine.appendFlag("-frontend")
2323

2424
try addCommonFrontendOptions(
25-
commandLine: &commandLine, inputs: &inputs, bridgingHeaderHandling: .parsed)
25+
commandLine: &commandLine, inputs: &inputs, bridgingHeaderHandling: .parsed, isGeneratePCH: true)
2626

2727
try commandLine.appendLast(.indexStorePath, from: &parsedOptions)
2828

Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ private extension SwiftScan {
165165
let bridgingSourceFiles =
166166
try getOptionalPathArrayDetail(from: moduleDetailsRef,
167167
using: api.swiftscan_swift_textual_detail_get_bridging_source_files)
168+
let bridgingHeaderDependencies =
169+
try getOptionalStringArrayDetail(from: moduleDetailsRef,
170+
using: api.swiftscan_swift_textual_detail_get_bridging_module_dependencies)
168171
let commandLine =
169172
try getOptionalStringArrayDetail(from: moduleDetailsRef,
170173
using: api.swiftscan_swift_textual_detail_get_command_line)
@@ -181,6 +184,7 @@ private extension SwiftScan {
181184
compiledModuleCandidates: compiledModuleCandidates,
182185
bridgingHeaderPath: bridgingHeaderPath,
183186
bridgingSourceFiles: bridgingSourceFiles,
187+
bridgingHeaderDependencies: bridgingHeaderDependencies?.map { .clang($0) },
184188
commandLine: commandLine,
185189
contextHash: contextHash,
186190
extraPcmArgs: extraPcmArgs,

Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,8 @@ final class ExplicitModuleBuildTests: XCTestCase {
269269
let cHeadersPath: AbsolutePath =
270270
testInputsPath.appending(component: "ExplicitModuleBuilds")
271271
.appending(component: "CHeaders")
272+
let bridgingHeaderpath: AbsolutePath =
273+
cHeadersPath.appending(component: "Bridging.h")
272274
let swiftModuleInterfacesPath: AbsolutePath =
273275
testInputsPath.appending(component: "ExplicitModuleBuilds")
274276
.appending(component: "Swift")
@@ -278,6 +280,7 @@ final class ExplicitModuleBuildTests: XCTestCase {
278280
"-I", cHeadersPath.nativePathString(escaped: true),
279281
"-I", swiftModuleInterfacesPath.nativePathString(escaped: true),
280282
"-explicit-module-build",
283+
"-import-objc-header", bridgingHeaderpath.nativePathString(escaped: true),
281284
main.nativePathString(escaped: true)] + sdkArgumentsForTesting)
282285

283286
let jobs = try driver.planBuild()
@@ -338,6 +341,10 @@ final class ExplicitModuleBuildTests: XCTestCase {
338341
try checkExplicitModuleBuildJob(job: job, moduleId: .clang("G"),
339342
dependencyGraph: dependencyGraph)
340343
}
344+
else if relativeOutputPathFileName.starts(with: "F-") {
345+
try checkExplicitModuleBuildJob(job: job, moduleId: .clang("F"),
346+
dependencyGraph: dependencyGraph)
347+
}
341348
else if relativeOutputPathFileName.starts(with: "SwiftShims-") {
342349
try checkExplicitModuleBuildJob(job: job, moduleId: .clang("SwiftShims"),
343350
dependencyGraph: dependencyGraph)
@@ -357,7 +364,8 @@ final class ExplicitModuleBuildTests: XCTestCase {
357364
case .temporary(_):
358365
let baseName = "testExplicitModuleBuildJobs"
359366
XCTAssertTrue(matchTemporary(outputFilePath, basename: baseName, fileExtension: "o") ||
360-
matchTemporary(outputFilePath, basename: baseName, fileExtension: "autolink"))
367+
matchTemporary(outputFilePath, basename: baseName, fileExtension: "autolink") ||
368+
matchTemporary(outputFilePath, basename: "Bridging-", fileExtension: "pch"))
361369
default:
362370
XCTFail("Unexpected module dependency build job output: \(outputFilePath)")
363371
}

0 commit comments

Comments
 (0)