Skip to content

Commit cee8c66

Browse files
authored
Merge pull request #1240 from artemcm/BinaryExplicitDependencyFrameworks
[Dependency Scanning] Query scanner whether discovered binary Swift modules are frameworks
2 parents 960296d + 3b2ec65 commit cee8c66

File tree

6 files changed

+114
-2
lines changed

6 files changed

+114
-2
lines changed

Sources/CSwiftScan/include/swiftscan_header.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ typedef struct {
130130
(*swiftscan_swift_binary_detail_get_module_doc_path)(swiftscan_module_details_t);
131131
swiftscan_string_ref_t
132132
(*swiftscan_swift_binary_detail_get_module_source_info_path)(swiftscan_module_details_t);
133+
bool
134+
(*swiftscan_swift_binary_detail_get_is_framework)(swiftscan_module_details_t);
133135

134136
//=== Swift Placeholder Module Details query APIs -------------------------===//
135137
swiftscan_string_ref_t

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public struct SwiftPrebuiltExternalModuleDetails: Codable {
141141
public init(compiledModulePath: TextualVirtualPath,
142142
moduleDocPath: TextualVirtualPath? = nil,
143143
moduleSourceInfoPath: TextualVirtualPath? = nil,
144-
isFramework: Bool = false) throws {
144+
isFramework: Bool) throws {
145145
self.compiledModulePath = compiledModulePath
146146
self.moduleDocPath = moduleDocPath
147147
self.moduleSourceInfoPath = moduleSourceInfoPath

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ public class InterModuleDependencyOracle {
128128
swiftScan.resetScannerCache()
129129
}
130130
}
131+
132+
@_spi(Testing) public func supportsBinaryFrameworkDependencies() throws -> Bool {
133+
guard let swiftScan = swiftScanLibInstance else {
134+
fatalError("Attempting to query supported scanner API with no scanner instance.")
135+
}
136+
return swiftScan.hasBinarySwiftModuleIsFramework
137+
}
131138

132139
@_spi(Testing) public func supportsScannerDiagnostics() throws -> Bool {
133140
guard let swiftScan = swiftScanLibInstance else {

Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,18 @@ private extension SwiftScan {
200200
let moduleSourceInfoPath =
201201
try getOptionalPathDetail(from: moduleDetailsRef,
202202
using: api.swiftscan_swift_binary_detail_get_module_source_info_path)
203+
204+
let isFramework: Bool
205+
if hasBinarySwiftModuleIsFramework {
206+
isFramework = api.swiftscan_swift_binary_detail_get_is_framework(moduleDetailsRef)
207+
} else {
208+
isFramework = false
209+
}
210+
203211
return try SwiftPrebuiltExternalModuleDetails(compiledModulePath: compiledModulePath,
204212
moduleDocPath: moduleDocPath,
205-
moduleSourceInfoPath: moduleSourceInfoPath)
213+
moduleSourceInfoPath: moduleSourceInfoPath,
214+
isFramework: isFramework)
206215
}
207216

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

Sources/SwiftDriver/SwiftScan/SwiftScan.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ internal final class SwiftScan {
234234
return resultGraphMap
235235
}
236236

237+
@_spi(Testing) public var hasBinarySwiftModuleIsFramework : Bool {
238+
api.swiftscan_swift_binary_detail_get_is_framework != nil
239+
}
240+
237241
@_spi(Testing) public var canLoadStoreScannerCache : Bool {
238242
api.swiftscan_scanner_cache_load != nil &&
239243
api.swiftscan_scanner_cache_serialize != nil &&
@@ -370,6 +374,10 @@ private extension swiftscan_functions_t {
370374
self.swiftscan_diagnostics_set_dispose =
371375
try loadOptional("swiftscan_diagnostics_set_dispose")
372376

377+
// isFramework on binary module dependencies
378+
self.swiftscan_swift_binary_detail_get_is_framework =
379+
try loadOptional("swiftscan_swift_binary_detail_get_is_framework")
380+
373381
// MARK: Required Methods
374382
func loadRequired<T>(_ symbol: String) throws -> T {
375383
guard let sym: T = Loader.lookup(symbol: symbol, in: swiftscan) else {

Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,92 @@ final class ExplicitModuleBuildTests: XCTestCase {
789789
}
790790
}
791791

792+
func testBinaryFrameworkDependencyScan() throws {
793+
try withTemporaryDirectory { path in
794+
let (stdLibPath, shimsPath, toolchain, hostTriple) = try getDriverArtifactsForScanning()
795+
let moduleCachePath = path.appending(component: "ModuleCache")
796+
797+
// Setup module to be used as dependency
798+
try localFileSystem.createDirectory(moduleCachePath)
799+
let frameworksPath = path.appending(component: "Frameworks")
800+
let frameworkModuleDir = frameworksPath.appending(component: "Foo.framework")
801+
.appending(component: "Modules")
802+
.appending(component: "Foo.swiftmodule")
803+
let frameworkModulePath =
804+
frameworkModuleDir.appending(component: hostTriple.archName + ".swiftmodule")
805+
try localFileSystem.createDirectory(frameworkModuleDir, recursive: true)
806+
let fooSourcePath = path.appending(component: "Foo.swift")
807+
try localFileSystem.writeFileContents(fooSourcePath) {
808+
$0 <<< "public func foo() {}"
809+
}
810+
811+
// Setup our main test module
812+
let mainSourcePath = path.appending(component: "Foo.swift")
813+
try localFileSystem.writeFileContents(mainSourcePath) {
814+
$0 <<< "import Foo"
815+
}
816+
817+
// 1. Build Foo module
818+
let sdkArgumentsForTesting = (try? Driver.sdkArgumentsForTesting()) ?? []
819+
var driverFoo = try Driver(args: ["swiftc",
820+
"-module-cache-path", moduleCachePath.nativePathString(escaped: true),
821+
"-module-name", "Foo",
822+
"-emit-module",
823+
"-emit-module-path",
824+
frameworkModulePath.nativePathString(escaped: true),
825+
"-working-directory",
826+
path.nativePathString(escaped: true),
827+
fooSourcePath.nativePathString(escaped: true)] + sdkArgumentsForTesting,
828+
env: ProcessEnv.vars)
829+
let jobs = try driverFoo.planBuild()
830+
try driverFoo.run(jobs: jobs)
831+
XCTAssertFalse(driverFoo.diagnosticEngine.hasErrors)
832+
833+
// 2. Run a dependency scan to find the just-built module
834+
let dependencyOracle = InterModuleDependencyOracle()
835+
let scanLibPath = try Driver.getScanLibPath(of: toolchain,
836+
hostTriple: hostTriple,
837+
env: ProcessEnv.vars)
838+
guard try dependencyOracle
839+
.verifyOrCreateScannerInstance(fileSystem: localFileSystem,
840+
swiftScanLibPath: scanLibPath) else {
841+
XCTFail("Dependency scanner library not found")
842+
return
843+
}
844+
guard try dependencyOracle.supportsBinaryFrameworkDependencies() else {
845+
throw XCTSkip("libSwiftScan does not support framework binary dependency reporting.")
846+
}
847+
848+
var driver = try Driver(args: ["swiftc",
849+
"-I", stdLibPath.nativePathString(escaped: true),
850+
"-I", shimsPath.nativePathString(escaped: true),
851+
"-F", frameworksPath.nativePathString(escaped: true),
852+
"-import-objc-header",
853+
"-explicit-module-build",
854+
"-module-name", "main",
855+
"-working-directory", path.nativePathString(escaped: true),
856+
mainSourcePath.nativePathString(escaped: true)] + sdkArgumentsForTesting,
857+
env: ProcessEnv.vars)
858+
let resolver = try ArgsResolver(fileSystem: localFileSystem)
859+
var scannerCommand = try driver.dependencyScannerInvocationCommand().1.map { try resolver.resolve($0) }
860+
if scannerCommand.first == "-frontend" {
861+
scannerCommand.removeFirst()
862+
}
863+
let dependencyGraph =
864+
try! dependencyOracle.getDependencies(workingDirectory: path,
865+
commandLine: scannerCommand)
866+
867+
let fooDependencyInfo = try XCTUnwrap(dependencyGraph.modules[.swiftPrebuiltExternal("Foo")])
868+
guard case .swiftPrebuiltExternal(let fooDetails) = fooDependencyInfo.details else {
869+
XCTFail("Foo dependency module does not have Swift details field")
870+
return
871+
}
872+
873+
// Ensure the dependency has been reported as a framework
874+
XCTAssertTrue(fooDetails.isFramework)
875+
}
876+
}
877+
792878
func getStdlibShimsPaths(_ driver: Driver) throws -> (AbsolutePath, AbsolutePath) {
793879
let toolchainRootPath: AbsolutePath = try driver.toolchain.getToolPath(.swiftCompiler)
794880
.parentDirectory // bin

0 commit comments

Comments
 (0)