Skip to content

Commit 63469ce

Browse files
authored
Merge pull request #781 from artemcm/ExplicitModuleCherryFarming
[5.5][Explicit Module Builds] Cherry-pick explicit module build changes
2 parents 917466d + 5fa09d4 commit 63469ce

19 files changed

+674
-648
lines changed

Sources/CSwiftScan/include/swiftscan_header.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,17 +200,20 @@ typedef struct {
200200
//=== Scanner Functions ---------------------------------------------------===//
201201
swiftscan_scanner_t (*swiftscan_scanner_create)(void);
202202
void (*swiftscan_scanner_dispose)(swiftscan_scanner_t);
203-
204203
swiftscan_dependency_graph_t
205204
(*swiftscan_dependency_graph_create)(swiftscan_scanner_t, swiftscan_scan_invocation_t);
206-
207205
swiftscan_batch_scan_result_t *
208206
(*swiftscan_batch_scan_result_create)(swiftscan_scanner_t,
209207
swiftscan_batch_scan_input_t *,
210208
swiftscan_scan_invocation_t);
211-
212209
swiftscan_import_set_t
213210
(*swiftscan_import_set_create)(swiftscan_scanner_t, swiftscan_scan_invocation_t);
211+
212+
//=== Scanner Cache Functions ---------------------------------------------===//
213+
void (*swiftscan_scanner_cache_serialize)(swiftscan_scanner_t scanner, const char * path);
214+
bool (*swiftscan_scanner_cache_load)(swiftscan_scanner_t scanner, const char * path);
215+
void (*swiftscan_scanner_cache_reset)(swiftscan_scanner_t scanner);
216+
214217
} swiftscan_functions_t;
215218

216219
#endif // SWIFT_C_DEPENDENCY_SCAN_H

Sources/SwiftDriver/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ add_library(SwiftDriver
1010
"ExplicitModuleBuilds/ClangVersionedDependencyResolution.swift"
1111
"ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift"
1212
"ExplicitModuleBuilds/ModuleDependencyScanning.swift"
13-
"ExplicitModuleBuilds/PlaceholderDependencyResolution.swift"
1413
"ExplicitModuleBuilds/SerializableModuleArtifacts.swift"
1514
"ExplicitModuleBuilds/InterModuleDependencies/CommonDependencyOperations.swift"
1615
"ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift"

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public struct Driver {
2323
case invalidArgumentValue(String, String)
2424
case relativeFrontendPath(String)
2525
case subcommandPassedToDriver
26+
case externalTargetDetailsAPIError
2627
case integratedReplRemoved
2728
case cannotSpecify_OForMultipleOutputs
2829
case conflictingOptions(Option, Option)
@@ -38,6 +39,7 @@ public struct Driver {
3839
case malformedModuleDependency(String, String)
3940
case missingPCMArguments(String)
4041
case missingModuleDependency(String)
42+
case missingContextHashOnSwiftDependency(String)
4143
case dependencyScanningFailure(Int, String)
4244
case missingExternalDependency(String)
4345

@@ -56,6 +58,8 @@ public struct Driver {
5658
return "relative frontend path: \(path)"
5759
case .subcommandPassedToDriver:
5860
return "subcommand passed to driver"
61+
case .externalTargetDetailsAPIError:
62+
return "Cannot specify both: externalTargetModulePathMap and externalTargetModuleDetailsMap"
5963
case .integratedReplRemoved:
6064
return "Compiler-internal integrated REPL has been removed; use the LLDB-enhanced REPL instead."
6165
case .cannotSpecify_OForMultipleOutputs:
@@ -91,6 +95,8 @@ public struct Driver {
9195
return "Missing extraPcmArgs to build Clang module: \(moduleName)"
9296
case .missingModuleDependency(let moduleName):
9397
return "Missing Module Dependency Info: \(moduleName)"
98+
case .missingContextHashOnSwiftDependency(let moduleName):
99+
return "Missing Context Hash for Swift dependency: \(moduleName)"
94100
case .dependencyScanningFailure(let code, let error):
95101
return "Module Dependency Scanner returned with non-zero exit status: \(code), \(error)"
96102
case .unableToLoadOutputFileMap(let path):
@@ -302,12 +308,9 @@ public struct Driver {
302308
/// is shared across many targets; otherwise, a new instance is created by the driver itself.
303309
@_spi(Testing) public let interModuleDependencyOracle: InterModuleDependencyOracle
304310

305-
// TODO: Once the clients have transitioned to using the InterModuleDependencyOracle API,
306-
// this must convey information about the externally-prebuilt targets only
307-
/// All external artifacts a build system (e.g. SwiftPM) may pass in as input to the explicit
308-
/// build of the current module. Consists of a map of externally-built targets, and a map of all previously
309-
/// discovered/scanned modules and their infos.
310-
@_spi(Testing) public var externalBuildArtifacts: ExternalBuildArtifacts? = nil
311+
/// A dictionary of external targets that are a part of the same build, mapping to filesystem paths
312+
/// of their module files
313+
@_spi(Testing) public var externalTargetModuleDetailsMap: ExternalTargetModuleDetailsMap? = nil
311314

312315
/// A collection of all the flags the selected toolchain's `swift-frontend` supports
313316
public let supportedFrontendFlags: Set<String>
@@ -384,9 +387,17 @@ public struct Driver {
384387
/// expand response files, etc. By default this is the local filesystem.
385388
/// - Parameter executor: Used by the driver to execute jobs. The default argument
386389
/// is present to streamline testing, it shouldn't be used in production.
387-
/// - Parameter externalBuildArtifacts: All external artifacts a build system may pass in as input to the explicit
388-
/// build of the current module. Consists of a map of externally-built targets, and a map of all previously
389-
/// discovered/scanned modules.
390+
/// - Parameter integratedDriver: Used to distinguish whether the driver is being used as
391+
/// an executable or as a library.
392+
/// - Parameter compilerExecutableDir: Directory that contains the compiler executable to be used.
393+
/// Used when in `integratedDriver` mode as a substitute for the driver knowing its executable path.
394+
/// - Parameter externalTargetModulePathMap: DEPRECATED: A dictionary of external targets
395+
/// that are a part of the same build, mapping to filesystem paths of their module files.
396+
/// - Parameter externalTargetModuleDetailsMap: A dictionary of external targets that are a part of
397+
/// the same build, mapping to a details value which includes a filesystem path of their
398+
/// `.swiftmodule` and a flag indicating whether the external target is a framework.
399+
/// - Parameter interModuleDependencyOracle: An oracle for querying inter-module dependencies,
400+
/// shared across different module builds by a build system.
390401
public init(
391402
args: [String],
392403
env: [String: String] = ProcessEnv.vars,
@@ -395,10 +406,9 @@ public struct Driver {
395406
executor: DriverExecutor,
396407
integratedDriver: Bool = true,
397408
compilerExecutableDir: AbsolutePath? = nil,
398-
// FIXME: Duplication with externalBuildArtifacts and externalTargetModulePathMap
399-
// is a temporary backwards-compatibility shim to help transition SwiftPM to the new API
400-
externalBuildArtifacts: ExternalBuildArtifacts? = nil,
409+
// Deprecated in favour of the below `externalTargetModuleDetailsMap`
401410
externalTargetModulePathMap: ExternalTargetModulePathMap? = nil,
411+
externalTargetModuleDetailsMap: ExternalTargetModuleDetailsMap? = nil,
402412
interModuleDependencyOracle: InterModuleDependencyOracle? = nil
403413
) throws {
404414
self.env = env
@@ -408,10 +418,15 @@ public struct Driver {
408418
self.diagnosticEngine = diagnosticsEngine
409419
self.executor = executor
410420

411-
if let externalArtifacts = externalBuildArtifacts {
412-
self.externalBuildArtifacts = externalArtifacts
413-
} else if let externalTargetPaths = externalTargetModulePathMap {
414-
self.externalBuildArtifacts = (externalTargetPaths, [:])
421+
if externalTargetModulePathMap != nil && externalTargetModuleDetailsMap != nil {
422+
throw Error.externalTargetDetailsAPIError
423+
}
424+
if let externalTargetPaths = externalTargetModulePathMap {
425+
self.externalTargetModuleDetailsMap = externalTargetPaths.mapValues {
426+
ExternalTargetModuleDetails(path: $0, isFramework: false)
427+
}
428+
} else if let externalTargetDetails = externalTargetModuleDetailsMap {
429+
self.externalTargetModuleDetailsMap = externalTargetDetails
415430
}
416431

417432
if case .subcommand = try Self.invocationRunMode(forArgs: args).mode {
@@ -504,14 +519,6 @@ public struct Driver {
504519
self.interModuleDependencyOracle = dependencyOracle
505520
} else {
506521
self.interModuleDependencyOracle = InterModuleDependencyOracle()
507-
508-
// This is a shim for backwards-compatibility with ModuleInfoMap-based API
509-
// used by SwiftPM
510-
if let externalArtifacts = externalBuildArtifacts {
511-
if !externalArtifacts.1.isEmpty {
512-
try self.interModuleDependencyOracle.mergeModules(from: externalArtifacts.1)
513-
}
514-
}
515522
}
516523

517524
self.fileListThreshold = try Self.computeFileListThreshold(&self.parsedOptions, diagnosticsEngine: diagnosticsEngine)

Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,21 @@ import TSCUtility
1414
import Foundation
1515

1616
/// A map from a module identifier to a path to its .swiftmodule file.
17+
/// Deprecated in favour of the below `ExternalTargetModuleDetails`
1718
public typealias ExternalTargetModulePathMap = [ModuleDependencyId: AbsolutePath]
1819

19-
// FIXME: ExternalBuildArtifacts is a temporary backwards-compatibility shim
20-
// to help transition SwiftPM to the new API.
21-
/// A tuple all external artifacts a build system may pass in as input to the explicit build of the current module
22-
/// Consists of a map of externally-built targets, and a map of all previously discovered/scanned modules.
23-
public typealias ExternalBuildArtifacts = (ExternalTargetModulePathMap, ModuleInfoMap)
20+
/// Details about an external target, including the path to its .swiftmodule file
21+
/// and whether it is a framework.
22+
public struct ExternalTargetModuleDetails {
23+
public init(path: AbsolutePath, isFramework: Bool) {
24+
self.path = path
25+
self.isFramework = isFramework
26+
}
27+
let path: AbsolutePath
28+
let isFramework: Bool
29+
}
30+
31+
public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalTargetModuleDetails]
2432

2533
/// In Explicit Module Build mode, this planner is responsible for generating and providing
2634
/// build jobs for all module dependencies and providing compile command options
@@ -211,18 +219,20 @@ public typealias ExternalBuildArtifacts = (ExternalTargetModulePathMap, ModuleIn
211219
inputs: &inputs,
212220
commandLine: &commandLine)
213221

222+
let moduleMapPath = moduleDetails.moduleMapPath.path
214223
// Encode the target triple pcm args into the output `.pcm` filename
215224
let targetEncodedModulePath =
216225
try targetEncodedClangModuleFilePath(for: moduleInfo,
217-
hashParts: getPCMHashParts(pcmArgs: pcmArgs))
226+
hashParts: getPCMHashParts(pcmArgs: pcmArgs,
227+
moduleMapPath: moduleMapPath.description))
218228
outputs.append(TypedVirtualPath(file: targetEncodedModulePath, type: .pcm))
219229
commandLine.appendFlags("-emit-pcm", "-module-name", moduleId.moduleName,
220230
"-o", targetEncodedModulePath.description)
221231

222232
// The only required input is the .modulemap for this module.
223233
// Command line options in the dependency scanner output will include the
224234
// required modulemap, so here we must only add it to the list of inputs.
225-
inputs.append(TypedVirtualPath(file: moduleDetails.moduleMapPath.path,
235+
inputs.append(TypedVirtualPath(file: moduleMapPath,
226236
type: .clangModuleMap))
227237

228238
jobs.append(Job(
@@ -246,7 +256,7 @@ public typealias ExternalBuildArtifacts = (ExternalTargetModulePathMap, ModuleIn
246256
commandLine: inout [Job.ArgTemplate]) throws {
247257
// Prohibit the frontend from implicitly building textual modules into binary modules.
248258
commandLine.appendFlags("-disable-implicit-swift-modules", "-Xcc", "-Xclang", "-Xcc",
249-
"-fno-implicit-modules")
259+
"-fno-implicit-modules", "-Xcc", "-Xclang", "-Xcc", "-fno-implicit-module-maps")
250260
var swiftDependencyArtifacts: [SwiftModuleArtifactInfo] = []
251261
var clangDependencyArtifacts: [ClangModuleArtifactInfo] = []
252262
try addModuleDependencies(moduleId: moduleId, pcmArgs: pcmArgs,
@@ -314,25 +324,28 @@ public typealias ExternalBuildArtifacts = (ExternalTargetModulePathMap, ModuleIn
314324
let dependencyInfo = try dependencyGraph.moduleInfo(of: dependencyId)
315325
let dependencyClangModuleDetails =
316326
try dependencyGraph.clangModuleDetails(of: dependencyId)
327+
let moduleMapPath = dependencyClangModuleDetails.moduleMapPath.path
317328
let clangModulePath =
318329
try targetEncodedClangModuleFilePath(for: dependencyInfo,
319-
hashParts: getPCMHashParts(pcmArgs: pcmArgs))
330+
hashParts: getPCMHashParts(pcmArgs: pcmArgs,
331+
moduleMapPath: moduleMapPath.description))
320332
// Accumulate the requried information about this dependency
321333
clangDependencyArtifacts.append(
322334
ClangModuleArtifactInfo(name: dependencyId.moduleName,
323335
modulePath: TextualVirtualPath(path: clangModulePath),
324336
moduleMapPath: dependencyClangModuleDetails.moduleMapPath))
325337
case .swiftPrebuiltExternal:
326-
let compiledModulePath = try dependencyGraph
327-
.swiftPrebuiltDetails(of: dependencyId)
328-
.compiledModulePath
338+
let prebuiltModuleDetails = try dependencyGraph.swiftPrebuiltDetails(of: dependencyId)
339+
let compiledModulePath = prebuiltModuleDetails.compiledModulePath
340+
let isFramework = prebuiltModuleDetails.isFramework
329341
let swiftModulePath: TypedVirtualPath =
330342
.init(file: compiledModulePath.path, type: .swiftModule)
331343
// Accumulate the requried information about this dependency
332344
// TODO: add .swiftdoc and .swiftsourceinfo for this module.
333345
swiftDependencyArtifacts.append(
334346
SwiftModuleArtifactInfo(name: dependencyId.moduleName,
335-
modulePath: TextualVirtualPath(path: swiftModulePath.fileHandle)))
347+
modulePath: TextualVirtualPath(path: swiftModulePath.fileHandle),
348+
isFramework: isFramework))
336349
case .swiftPlaceholder:
337350
fatalError("Unresolved placeholder dependencies at planning stage: \(dependencyId) of \(moduleId)")
338351
}
@@ -380,11 +393,14 @@ public typealias ExternalBuildArtifacts = (ExternalTargetModulePathMap, ModuleIn
380393
return VirtualPath.createUniqueTemporaryFileWithKnownContents(.init("\(moduleId.moduleName)-dependencies.json"), contents)
381394
}
382395

383-
private func getPCMHashParts(pcmArgs: [String]) -> [String] {
396+
private func getPCMHashParts(pcmArgs: [String], moduleMapPath: String) -> [String] {
397+
var results: [String] = []
398+
results.append(moduleMapPath)
399+
results.append(contentsOf: pcmArgs)
384400
if integratedDriver {
385-
return pcmArgs
401+
return results
386402
}
387-
var results = pcmArgs
403+
388404
// We need this to enable explict modules in the driver-as-executable mode. For instance,
389405
// we have two Swift targets A and B, where A depends on X.pcm which in turn depends on Y.pcm,
390406
// and B only depends on Y.pcm. In the driver-as-executable mode, the build system isn't aware
@@ -436,15 +452,15 @@ extension ExplicitDependencyBuildPlanner {
436452
#else
437453
hashedArguments = SHA256().hash(hashInput).hexadecimalRepresentation
438454
#endif
439-
let resultingName = moduleName + hashedArguments
455+
let resultingName = moduleName + "-" + hashedArguments
440456
hashedModuleNameCache[cacheQuery] = resultingName
441457
return resultingName
442458
}
443459
}
444460

445461
/// Encapsulates some of the common queries of the ExplicitDependencyBuildPlanner with error-checking
446462
/// on the dependency graph's structure.
447-
internal extension InterModuleDependencyGraph {
463+
@_spi(Testing) public extension InterModuleDependencyGraph {
448464
func moduleInfo(of moduleId: ModuleDependencyId) throws -> ModuleInfo {
449465
guard let moduleInfo = modules[moduleId] else {
450466
throw Driver.Error.missingModuleDependency(moduleId.moduleName)

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/CommonDependencyOperations.swift

Lines changed: 9 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,10 @@ import TSCBasic
1515
/// For targets that are built alongside the driver's current module, the scanning action will report them as
1616
/// textual targets to be built from source. Because we can rely on these targets to have been built prior
1717
/// to the driver's current target, we resolve such external targets as prebuilt binary modules, in the graph.
18-
mutating func resolveExternalDependencies(for externalBuildArtifacts: ExternalBuildArtifacts)
18+
mutating func resolveExternalDependencies(for externalTargetModuleDetailsMap: ExternalTargetModuleDetailsMap)
1919
throws {
20-
let externalTargetModulePathMap = externalBuildArtifacts.0
21-
22-
for (externalModuleId, externalModulePath) in externalTargetModulePathMap {
20+
for (externalModuleId, externalModuleDetails) in externalTargetModuleDetailsMap {
21+
let externalModulePath = externalModuleDetails.path
2322
// Replace the occurence of a Swift module to-be-built from source-file
2423
// to an info that describes a pre-built binary module.
2524
let swiftModuleId: ModuleDependencyId = .swift(externalModuleId.moduleName)
@@ -30,57 +29,22 @@ import TSCBasic
3029
// a dependency on a target that is not actually used.
3130
continue
3231
}
33-
34-
let newModuleId: ModuleDependencyId = .swiftPrebuiltExternal(externalModuleId.moduleName)
32+
33+
let newModuleId: ModuleDependencyId = .swiftPrebuiltExternal(externalModuleId.moduleName)
3534
let newExternalModuleDetails =
36-
try SwiftPrebuiltExternalModuleDetails(compiledModulePath:
37-
TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()))
35+
try SwiftPrebuiltExternalModuleDetails(compiledModulePath:
36+
TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()),
37+
isFramework: externalModuleDetails.isFramework)
3838
let newInfo = ModuleInfo(modulePath: TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()),
3939
sourceFiles: [],
4040
directDependencies: currentInfo.directDependencies,
4141
details: .swiftPrebuiltExternal(newExternalModuleDetails))
42-
43-
Self.replaceModule(originalId: swiftModuleId, replacementId: newModuleId,
42+
Self.replaceModule(originalId: swiftModuleId, replacementId: newModuleId,
4443
replacementInfo: newInfo, in: &modules)
4544
}
4645
}
4746
}
4847

49-
@_spi(Testing) public extension InterModuleDependencyOracle {
50-
/// An API to allow clients to accumulate InterModuleDependencyGraphs across mutiple main externalModules/targets
51-
/// into a single collection of discovered externalModules.
52-
func mergeModules(from dependencyGraph: InterModuleDependencyGraph) throws {
53-
try queue.sync {
54-
for (moduleId, moduleInfo) in dependencyGraph.modules {
55-
try InterModuleDependencyGraph.mergeModule(moduleId, moduleInfo, into: &externalModules)
56-
}
57-
}
58-
}
59-
60-
// This is a backwards-compatibility shim to handle existing ModuleInfoMap-based API
61-
// used by SwiftPM
62-
func mergeModules(from moduleInfoMap: ModuleInfoMap) throws {
63-
try queue.sync {
64-
for (moduleId, moduleInfo) in moduleInfoMap {
65-
try InterModuleDependencyGraph.mergeModule(moduleId, moduleInfo, into: &externalModules)
66-
}
67-
}
68-
}
69-
}
70-
71-
public extension InterModuleDependencyGraph {
72-
// This is a shim for backwards-compatibility with existing API used by SwiftPM.
73-
// TODO: After SwiftPM switches to using the oracle, this should be deleted.
74-
static func mergeModules(
75-
from dependencyGraph: InterModuleDependencyGraph,
76-
into discoveredModules: inout ModuleInfoMap
77-
) throws {
78-
for (moduleId, moduleInfo) in dependencyGraph.modules {
79-
try mergeModule(moduleId, moduleInfo, into: &discoveredModules)
80-
}
81-
}
82-
}
83-
8448
extension InterModuleDependencyGraph {
8549
/// Compute a set of modules that are "reachable" (form direct or transitive dependency)
8650
/// from each module in the graph.

0 commit comments

Comments
 (0)