Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Dependency Scanning] Add support for Swift Overlay dependencies as a separate dependency details field #1365

Merged
merged 1 commit into from May 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions Sources/CSwiftScan/include/swiftscan_header.h
Expand Up @@ -122,6 +122,8 @@ typedef struct {
(*swiftscan_swift_textual_detail_get_context_hash)(swiftscan_module_details_t);
bool
(*swiftscan_swift_textual_detail_get_is_framework)(swiftscan_module_details_t);
swiftscan_string_set_t *
(*swiftscan_swift_textual_detail_get_swift_overlay_dependencies)(swiftscan_module_details_t);

//=== Swift Binary Module Details query APIs ------------------------------===//
swiftscan_string_ref_t
Expand Down
Expand Up @@ -124,7 +124,6 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
}
for moduleId in swiftDependencies {
let moduleInfo = try dependencyGraph.moduleInfo(of: moduleId)
let pcmArgs = try dependencyGraph.swiftModulePCMArgs(of: moduleId)
var inputs: [TypedVirtualPath] = []
let outputs: [TypedVirtualPath] = [
TypedVirtualPath(file: moduleInfo.modulePath.path, type: .swiftModule)
Expand Down
Expand Up @@ -75,9 +75,22 @@ extension InterModuleDependencyGraph {
}
// Traverse the set of modules in reverse topological order, assimilating transitive closures
for moduleId in topologicalIdList.reversed() {
for dependencyId in try moduleInfo(of: moduleId).directDependencies! {
let moduleInfo = try moduleInfo(of: moduleId)
for dependencyId in moduleInfo.directDependencies! {
transitiveClosureMap[moduleId]!.formUnion(transitiveClosureMap[dependencyId]!)
}
// For Swift dependencies, their corresponding Swift Overlay dependencies
// and bridging header dependencies are equivalent to direct dependencies.
if case .swift(let swiftModuleDetails) = moduleInfo.details {
let swiftOverlayDependencies = swiftModuleDetails.swiftOverlayDependencies ?? []
for dependencyId in swiftOverlayDependencies {
transitiveClosureMap[moduleId]!.formUnion(transitiveClosureMap[dependencyId]!)
}
let bridgingHeaderDependencies = swiftModuleDetails.bridgingHeaderDependencies ?? []
for dependencyId in bridgingHeaderDependencies {
transitiveClosureMap[moduleId]!.formUnion(transitiveClosureMap[dependencyId]!)
}
}
}
// For ease of use down-the-line, remove the node's self from its set of reachable nodes
for (key, _) in transitiveClosureMap {
Expand Down
Expand Up @@ -79,7 +79,9 @@ extension ModuleDependencyId: Codable {
/// Bridging header
public struct BridgingHeader: Codable {
var path: TextualVirtualPath
/// The source files referenced by the bridging header.
var sourceFiles: [TextualVirtualPath]
/// Modules that the bridging header specifically depends on
var moduleDependencies: [String]
}

Expand All @@ -92,13 +94,16 @@ public struct SwiftModuleDetails: Codable {
public var compiledModuleCandidates: [TextualVirtualPath]?

/// The bridging header, if any.
public var bridgingHeaderPath: TextualVirtualPath?

/// The source files referenced by the bridging header.
public var bridgingSourceFiles: [TextualVirtualPath]? = []

/// Modules that the bridging header specifically depends on
public var bridgingHeaderDependencies: [ModuleDependencyId]? = []
public var bridgingHeader: BridgingHeader?
public var bridgingHeaderPath: TextualVirtualPath? {
bridgingHeader?.path
}
public var bridgingSourceFiles: [TextualVirtualPath]? {
bridgingHeader?.sourceFiles
}
public var bridgingHeaderDependencies: [ModuleDependencyId]? {
bridgingHeader?.moduleDependencies.map { .clang($0) }
}

/// Options to the compile command
public var commandLine: [String]? = []
Expand All @@ -115,6 +120,9 @@ public struct SwiftModuleDetails: Codable {

/// A flag to indicate whether or not this module is a framework.
public var isFramework: Bool?

/// A set of Swift Overlays of Clang Module Dependencies
var swiftOverlayDependencies: [ModuleDependencyId]?
}

/// Details specific to Swift placeholder dependencies.
Expand Down
39 changes: 31 additions & 8 deletions Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift
Expand Up @@ -123,7 +123,8 @@ private extension SwiftScan {
guard let moduleDetailsRef = api.swiftscan_module_info_get_details(moduleInfoRef) else {
throw DependencyScanningError.missingField("modules[\(moduleId)].details")
}
let details = try constructModuleDetails(from: moduleDetailsRef)
let details = try constructModuleDetails(from: moduleDetailsRef,
moduleAliases: moduleAliases)

return (moduleId, ModuleInfo(modulePath: modulePath, sourceFiles: sourceFiles,
directDependencies: directDependencies,
Expand All @@ -133,12 +134,14 @@ private extension SwiftScan {
/// From a reference to a binary-format module info details object info returned by libSwiftScan,
/// construct an instance of an `ModuleInfo`.Details as used by the driver.
/// The object returned by libSwiftScan is a union so ensure to execute dependency-specific queries.
func constructModuleDetails(from moduleDetailsRef: swiftscan_module_details_t)
func constructModuleDetails(from moduleDetailsRef: swiftscan_module_details_t,
moduleAliases: [String: String]?)
throws -> ModuleInfo.Details {
let moduleKind = api.swiftscan_module_detail_get_kind(moduleDetailsRef)
switch moduleKind {
case SWIFTSCAN_DEPENDENCY_INFO_SWIFT_TEXTUAL:
return .swift(try constructSwiftTextualModuleDetails(from: moduleDetailsRef))
return .swift(try constructSwiftTextualModuleDetails(from: moduleDetailsRef,
moduleAliases: moduleAliases))
case SWIFTSCAN_DEPENDENCY_INFO_SWIFT_BINARY:
return .swiftPrebuiltExternal(try constructSwiftBinaryModuleDetails(from: moduleDetailsRef))
case SWIFTSCAN_DEPENDENCY_INFO_SWIFT_PLACEHOLDER:
Expand All @@ -151,7 +154,8 @@ private extension SwiftScan {
}

/// Construct a `SwiftModuleDetails` from a `swiftscan_module_details_t` reference
func constructSwiftTextualModuleDetails(from moduleDetailsRef: swiftscan_module_details_t)
func constructSwiftTextualModuleDetails(from moduleDetailsRef: swiftscan_module_details_t,
moduleAliases: [String: String]?)
throws -> SwiftModuleDetails {
let moduleInterfacePath =
try getOptionalPathDetail(from: moduleDetailsRef,
Expand All @@ -168,6 +172,15 @@ private extension SwiftScan {
let bridgingHeaderDependencies =
try getOptionalStringArrayDetail(from: moduleDetailsRef,
using: api.swiftscan_swift_textual_detail_get_bridging_module_dependencies)
let bridgingHeader: BridgingHeader?
if let resolvedBridgingHeaderPath = bridgingHeaderPath {
bridgingHeader = BridgingHeader(path: resolvedBridgingHeaderPath,
sourceFiles: bridgingSourceFiles ?? [],
moduleDependencies: bridgingHeaderDependencies ?? [])
} else {
bridgingHeader = nil
}

let commandLine =
try getOptionalStringArrayDetail(from: moduleDetailsRef,
using: api.swiftscan_swift_textual_detail_get_command_line)
Expand All @@ -180,15 +193,25 @@ private extension SwiftScan {
using: api.swiftscan_swift_textual_detail_get_context_hash)
let isFramework = api.swiftscan_swift_textual_detail_get_is_framework(moduleDetailsRef)

// Decode all dependencies of this module
let swiftOverlayDependencies: [ModuleDependencyId]?
if supportsSeparateSwiftOverlayDependencies(),
let encodedOverlayDepsRef = api.swiftscan_swift_textual_detail_get_swift_overlay_dependencies(moduleDetailsRef) {
let encodedOverlayDependencies = try toSwiftStringArray(encodedOverlayDepsRef.pointee)
swiftOverlayDependencies =
try encodedOverlayDependencies.map { try decodeModuleNameAndKind(from: $0, moduleAliases: moduleAliases) }
} else {
swiftOverlayDependencies = nil
}

return SwiftModuleDetails(moduleInterfacePath: moduleInterfacePath,
compiledModuleCandidates: compiledModuleCandidates,
bridgingHeaderPath: bridgingHeaderPath,
bridgingSourceFiles: bridgingSourceFiles,
bridgingHeaderDependencies: bridgingHeaderDependencies?.map { .clang($0) },
bridgingHeader: bridgingHeader,
commandLine: commandLine,
contextHash: contextHash,
extraPcmArgs: extraPcmArgs,
isFramework: isFramework)
isFramework: isFramework,
swiftOverlayDependencies: swiftOverlayDependencies)
}

/// Construct a `SwiftPrebuiltExternalModuleDetails` from a `swiftscan_module_details_t` reference
Expand Down
8 changes: 8 additions & 0 deletions Sources/SwiftDriver/SwiftScan/SwiftScan.swift
Expand Up @@ -263,6 +263,10 @@ internal extension swiftscan_diagnostic_severity_t {
func resetScannerCache() {
api.swiftscan_scanner_cache_reset(scanner)
}

@_spi(Testing) public func supportsSeparateSwiftOverlayDependencies() -> Bool {
return api.swiftscan_swift_textual_detail_get_swift_overlay_dependencies != nil
}

@_spi(Testing) public func supportsScannerDiagnostics() -> Bool {
return api.swiftscan_scanner_diagnostics_query != nil &&
Expand Down Expand Up @@ -419,6 +423,10 @@ private extension swiftscan_functions_t {
self.swiftscan_swift_binary_detail_get_is_framework =
try loadOptional("swiftscan_swift_binary_detail_get_is_framework")

// Swift Overlay Dependencies
self.swiftscan_swift_textual_detail_get_swift_overlay_dependencies =
try loadOptional("swiftscan_swift_textual_detail_get_swift_overlay_dependencies")

// MARK: Required Methods
func loadRequired<T>(_ symbol: String) throws -> T {
guard let sym: T = Loader.lookup(symbol: symbol, in: swiftscan) else {
Expand Down