Skip to content

Commit 2ad97b0

Browse files
committed
[Dependency Scanning] Move computation of the path for libSwiftScan to the toolchain
Alongside lookup of executable tools, the toolchain is now responsible for looking up the driver's compiler support and dependency scanning library. It also adds an environment variable override 'SWIFT_DRIVER_SWIFTSCAN_LIB' for clients to specify a specific path to this shared library that they would like to be used instead of the default.
1 parent f563677 commit 2ad97b0

File tree

8 files changed

+102
-88
lines changed

8 files changed

+102
-88
lines changed

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -650,11 +650,11 @@ public struct Driver {
650650
outputFileMap: outputFileMap)
651651

652652
self.supportedFrontendFlags =
653-
try Self.computeSupportedCompilerArgs(of: self.toolchain, hostTriple: self.hostTriple,
654-
parsedOptions: &self.parsedOptions,
655-
diagnosticsEngine: diagnosticEngine,
656-
fileSystem: fileSystem, executor: executor,
657-
env: env)
653+
try Self.computeSupportedCompilerArgs(of: self.toolchain,
654+
parsedOptions: &self.parsedOptions,
655+
diagnosticsEngine: diagnosticEngine,
656+
fileSystem: fileSystem,
657+
executor: executor)
658658
let supportedFrontendFlagsLocal = self.supportedFrontendFlags
659659
self.savedUnknownDriverFlagsForSwiftFrontend = try self.parsedOptions.saveUnknownFlags {
660660
Driver.isOptionFound($0, allOpts: supportedFrontendFlagsLocal)

Sources/SwiftDriver/Driver/WindowsExtensions.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,27 @@ internal func executableName(_ name: String) -> String {
2020
return name
2121
#endif
2222
}
23+
24+
@_spi(Testing) public func sharedLibraryName(_ name: String) -> String {
25+
#if canImport(Darwin)
26+
let ext = ".dylib"
27+
#elseif os(Windows)
28+
let ext = ".dll"
29+
#else
30+
let ext = ".so"
31+
#endif
32+
return name + ext
33+
}
34+
35+
// FIXME: This can be subtly wrong, we should rather
36+
// try to get the client to provide this info or move to a better
37+
// path convention for where we keep compiler support libraries
38+
internal var compilerHostSupportLibraryOSComponent : String {
39+
#if canImport(Darwin)
40+
return "macosx"
41+
#elseif os(Windows)
42+
return "windows"
43+
#else
44+
return "linux"
45+
#endif
46+
}

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,9 @@ public extension Driver {
221221
// attempt to fallback to using `swift-frontend -scan-dependencies` invocations for dependency
222222
// scanning.
223223
var fallbackToFrontend = parsedOptions.hasArgument(.driverScanDependenciesNonLib)
224-
let scanLibPath = try Self.getScanLibPath(of: toolchain, hostTriple: hostTriple, env: env)
225-
if try interModuleDependencyOracle
224+
let optionalScanLibPath = try toolchain.lookupSwiftScanLib()
225+
if let scanLibPath = optionalScanLibPath,
226+
try interModuleDependencyOracle
226227
.verifyOrCreateScannerInstance(fileSystem: fileSystem,
227228
swiftScanLibPath: scanLibPath) == false {
228229
fallbackToFrontend = true
@@ -490,46 +491,9 @@ public extension Driver {
490491
useResponseFiles: useResponseFiles)
491492
return args
492493
}
493-
}
494-
495-
@_spi(Testing) public extension Driver {
496-
static func getScanLibPath(of toolchain: Toolchain, hostTriple: Triple,
497-
env: [String: String]) throws -> AbsolutePath {
498-
if hostTriple.isWindows {
499-
// no matter if we are in a build tree or an installed tree, the layout is
500-
// always: `bin/_InternalSwiftScan.dll`
501-
return try getRootPath(of: toolchain, env: env)
502-
.appending(component: "bin")
503-
.appending(component: "_InternalSwiftScan.dll")
504-
}
505-
506-
let sharedLibExt: String
507-
if hostTriple.isMacOSX {
508-
sharedLibExt = ".dylib"
509-
} else {
510-
sharedLibExt = ".so"
511-
}
512-
let libScanner = "lib_InternalSwiftScan\(sharedLibExt)"
513-
// We first look into position in toolchain
514-
let libPath
515-
= try getRootPath(of: toolchain, env: env).appending(component: "lib")
516-
.appending(component: "swift")
517-
.appending(component: hostTriple.osNameUnversioned)
518-
.appending(component: libScanner)
519-
if localFileSystem.exists(libPath) {
520-
return libPath
521-
}
522-
// In case we are using a compiler from the build dir, we should also try
523-
// this path.
524-
return try getRootPath(of: toolchain, env: env).appending(component: "lib")
525-
.appending(component: libScanner)
526-
}
527494

528495
static func getRootPath(of toolchain: Toolchain, env: [String: String])
529496
throws -> AbsolutePath {
530-
if let overrideString = env["SWIFT_DRIVER_SWIFT_SCAN_TOOLCHAIN_PATH"] {
531-
return try AbsolutePath(validating: overrideString)
532-
}
533497
return try toolchain.getToolPath(.swiftCompiler)
534498
.parentDirectory // bin
535499
.parentDirectory // toolchain root

Sources/SwiftDriver/Jobs/EmitSupportedFeaturesJob.swift

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,15 @@ extension Toolchain {
5757
}
5858

5959
extension Driver {
60-
static func computeSupportedCompilerArgs(of toolchain: Toolchain, hostTriple: Triple,
60+
61+
static func computeSupportedCompilerArgs(of toolchain: Toolchain,
6162
parsedOptions: inout ParsedOptions,
6263
diagnosticsEngine: DiagnosticsEngine,
6364
fileSystem: FileSystem,
64-
executor: DriverExecutor, env: [String: String])
65+
executor: DriverExecutor)
6566
throws -> Set<String> {
66-
if let supportedArgs = try querySupportedCompilerArgsInProcess(of: toolchain, hostTriple: hostTriple,
67-
fileSystem: fileSystem, env: env) {
67+
if let supportedArgs =
68+
try querySupportedCompilerArgsInProcess(of: toolchain, fileSystem: fileSystem) {
6869
return supportedArgs
6970
}
7071

@@ -84,14 +85,11 @@ extension Driver {
8485
}
8586

8687
static func querySupportedCompilerArgsInProcess(of toolchain: Toolchain,
87-
hostTriple: Triple,
88-
fileSystem: FileSystem,
89-
env: [String: String])
88+
fileSystem: FileSystem)
9089
throws -> Set<String>? {
91-
let swiftScanLibPath = try Self.getScanLibPath(of: toolchain,
92-
hostTriple: hostTriple,
93-
env: env)
94-
if fileSystem.exists(swiftScanLibPath) {
90+
let optionalSwiftScanLibPath = try toolchain.lookupSwiftScanLib()
91+
if let swiftScanLibPath = optionalSwiftScanLibPath,
92+
fileSystem.exists(swiftScanLibPath) {
9593
let libSwiftScanInstance = try SwiftScan(dylib: swiftScanLibPath)
9694
if libSwiftScanInstance.canQuerySupportedArguments() {
9795
return try libSwiftScanInstance.querySupportedArguments()

Sources/SwiftDriver/SwiftScan/SwiftScan.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,7 @@ internal final class SwiftScan {
317317
@_spi(Testing) public extension Driver {
318318
func querySupportedArgumentsForTest() throws -> Set<String>? {
319319
// If a capable libSwiftScan is found, manually ensure we can get the supported arguments
320-
let scanLibPath = try Self.getScanLibPath(of: toolchain,
321-
hostTriple: hostTriple,
322-
env: env)
323-
if fileSystem.exists(scanLibPath) {
320+
if let scanLibPath = try toolchain.lookupSwiftScanLib() {
324321
let libSwiftScanInstance = try SwiftScan(dylib: scanLibPath)
325322
if libSwiftScanInstance.canQuerySupportedArguments() {
326323
return try libSwiftScanInstance.querySupportedArguments()

Sources/SwiftDriver/Toolchains/Toolchain.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,45 @@ extension Toolchain {
245245
}
246246
}
247247

248+
/// Looks for the executable in the `SWIFT_DRIVER_SWIFTSCAN_LIB` environment variable, if found nothing,
249+
/// looks in the `lib` relative to the compiler executable.
250+
/// TODO: If the driver needs to lookup other shared libraries, this is simple to generalize
251+
@_spi(Testing) public func lookupSwiftScanLib() throws -> AbsolutePath? {
252+
#if os(Windows)
253+
// no matter if we are in a build tree or an installed tree, the layout is
254+
// always: `bin/_InternalSwiftScan.dll`
255+
return try getToolPath(.swiftCompiler).parentDirectory // bin
256+
.appending(component: "_InternalSwiftScan.dll")
257+
#else
258+
let libraryName = sharedLibraryName("lib_InternalSwiftScan")
259+
if let overrideString = env["SWIFT_DRIVER_SWIFTSCAN_LIB"],
260+
let path = try? AbsolutePath(validating: overrideString) {
261+
return path
262+
} else {
263+
let compilerPath = try getToolPath(.swiftCompiler)
264+
let toolchainRootPath = compilerPath.parentDirectory // bin
265+
.parentDirectory // toolchain root
266+
267+
let searchPaths = [toolchainRootPath.appending(component: "lib")
268+
.appending(component: "swift")
269+
.appending(component: compilerHostSupportLibraryOSComponent),
270+
toolchainRootPath.appending(component: "lib")
271+
.appending(component: "swift")
272+
.appending(component: "host"),
273+
// In case we are using a compiler from the build dir, we should also try
274+
// this path.
275+
toolchainRootPath.appending(component: "lib")]
276+
for libraryPath in searchPaths.map({ $0.appending(component: libraryName) }) {
277+
if fileSystem.isFile(libraryPath) {
278+
return libraryPath
279+
}
280+
}
281+
}
282+
283+
return nil
284+
#endif
285+
}
286+
248287
private func xcrunFind(executable: String) throws -> AbsolutePath {
249288
let xcrun = "xcrun"
250289
guard lookupExecutablePath(filename: xcrun, searchPaths: searchPaths) != nil else {

Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ final class ExplicitModuleBuildTests: XCTestCase {
648648
}
649649

650650
func testModuleAliasingWithImportPrescan() throws {
651-
let (_, _, toolchain, hostTriple) = try getDriverArtifactsForScanning()
651+
let (_, _, toolchain, _) = try getDriverArtifactsForScanning()
652652

653653
let dummyDriver = try Driver(args: ["swiftc", "-module-name", "dummyDriverCheck", "test.swift"])
654654
guard dummyDriver.isFrontendArgSupported(.moduleAlias) else {
@@ -658,9 +658,7 @@ final class ExplicitModuleBuildTests: XCTestCase {
658658
// The dependency oracle wraps an instance of libSwiftScan and ensures thread safety across
659659
// queries.
660660
let dependencyOracle = InterModuleDependencyOracle()
661-
let scanLibPath = try Driver.getScanLibPath(of: toolchain,
662-
hostTriple: hostTriple,
663-
env: ProcessEnv.vars)
661+
let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib())
664662
guard try dependencyOracle
665663
.verifyOrCreateScannerInstance(fileSystem: localFileSystem,
666664
swiftScanLibPath: scanLibPath) else {
@@ -840,9 +838,7 @@ final class ExplicitModuleBuildTests: XCTestCase {
840838

841839
// 2. Run a dependency scan to find the just-built module
842840
let dependencyOracle = InterModuleDependencyOracle()
843-
let scanLibPath = try Driver.getScanLibPath(of: toolchain,
844-
hostTriple: hostTriple,
845-
env: ProcessEnv.vars)
841+
let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib())
846842
guard try dependencyOracle
847843
.verifyOrCreateScannerInstance(fileSystem: localFileSystem,
848844
swiftScanLibPath: scanLibPath) else {
@@ -939,14 +935,12 @@ final class ExplicitModuleBuildTests: XCTestCase {
939935

940936
/// Test the libSwiftScan dependency scanning (import-prescan).
941937
func testDependencyImportPrescan() throws {
942-
let (stdLibPath, shimsPath, toolchain, hostTriple) = try getDriverArtifactsForScanning()
938+
let (stdLibPath, shimsPath, toolchain, _) = try getDriverArtifactsForScanning()
943939

944940
// The dependency oracle wraps an instance of libSwiftScan and ensures thread safety across
945941
// queries.
946942
let dependencyOracle = InterModuleDependencyOracle()
947-
let scanLibPath = try Driver.getScanLibPath(of: toolchain,
948-
hostTriple: hostTriple,
949-
env: ProcessEnv.vars)
943+
let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib())
950944
guard try dependencyOracle
951945
.verifyOrCreateScannerInstance(fileSystem: localFileSystem,
952946
swiftScanLibPath: scanLibPath) else {
@@ -1020,14 +1014,12 @@ final class ExplicitModuleBuildTests: XCTestCase {
10201014
}
10211015

10221016
func testDependencyScanningFailure() throws {
1023-
let (stdlibPath, shimsPath, toolchain, hostTriple) = try getDriverArtifactsForScanning()
1017+
let (stdlibPath, shimsPath, toolchain, _) = try getDriverArtifactsForScanning()
10241018

10251019
// The dependency oracle wraps an instance of libSwiftScan and ensures thread safety across
10261020
// queries.
10271021
let dependencyOracle = InterModuleDependencyOracle()
1028-
let scanLibPath = try Driver.getScanLibPath(of: toolchain,
1029-
hostTriple: hostTriple,
1030-
env: ProcessEnv.vars)
1022+
let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib())
10311023
guard try dependencyOracle
10321024
.verifyOrCreateScannerInstance(fileSystem: localFileSystem,
10331025
swiftScanLibPath: scanLibPath) else {
@@ -1098,9 +1090,7 @@ final class ExplicitModuleBuildTests: XCTestCase {
10981090
// The dependency oracle wraps an instance of libSwiftScan and ensures thread safety across
10991091
// queries.
11001092
let dependencyOracle = InterModuleDependencyOracle()
1101-
let scanLibPath = try Driver.getScanLibPath(of: toolchain,
1102-
hostTriple: hostTriple,
1103-
env: ProcessEnv.vars)
1093+
let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib())
11041094
guard try dependencyOracle
11051095
.verifyOrCreateScannerInstance(fileSystem: localFileSystem,
11061096
swiftScanLibPath: scanLibPath) else {
@@ -1293,11 +1283,9 @@ final class ExplicitModuleBuildTests: XCTestCase {
12931283
}
12941284

12951285
func testDependencyGraphDotSerialization() throws {
1296-
let (stdlibPath, shimsPath, toolchain, hostTriple) = try getDriverArtifactsForScanning()
1286+
let (stdlibPath, shimsPath, toolchain, _) = try getDriverArtifactsForScanning()
12971287
let dependencyOracle = InterModuleDependencyOracle()
1298-
let scanLibPath = try Driver.getScanLibPath(of: toolchain,
1299-
hostTriple: hostTriple,
1300-
env: ProcessEnv.vars)
1288+
let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib())
13011289
guard try dependencyOracle
13021290
.verifyOrCreateScannerInstance(fileSystem: localFileSystem,
13031291
swiftScanLibPath: scanLibPath) else {
@@ -1358,7 +1346,7 @@ final class ExplicitModuleBuildTests: XCTestCase {
13581346

13591347
/// Test the libSwiftScan dependency scanning.
13601348
func testDependencyScanReuseCache() throws {
1361-
let (stdlibPath, shimsPath, toolchain, hostTriple) = try getDriverArtifactsForScanning()
1349+
let (stdlibPath, shimsPath, toolchain, _) = try getDriverArtifactsForScanning()
13621350
try withTemporaryDirectory { path in
13631351
let cacheSavePath = path.appending(component: "saved.moddepcache")
13641352
let main = path.appending(component: "testDependencyScanning.swift")
@@ -1394,9 +1382,7 @@ final class ExplicitModuleBuildTests: XCTestCase {
13941382
scannerCommand.removeFirst()
13951383
}
13961384

1397-
let scanLibPath = try Driver.getScanLibPath(of: toolchain,
1398-
hostTriple: hostTriple,
1399-
env: ProcessEnv.vars)
1385+
let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib())
14001386
// Run the first scan and serialize the cache contents.
14011387
let firstDependencyOracle = InterModuleDependencyOracle()
14021388
guard try firstDependencyOracle

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6685,6 +6685,8 @@ final class SwiftDriverTests: XCTestCase {
66856685
let PATH = "PATH"
66866686
#endif
66876687
let SWIFT_FRONTEND_EXEC = "SWIFT_DRIVER_SWIFT_FRONTEND_EXEC"
6688+
let SWIFT_SCANNER_LIB = "SWIFT_DRIVER_SWIFTSCAN_LIB"
6689+
66886690

66896691
// Reset the environment to ensure tool resolution is exactly run against PATH.
66906692
var driver = try Driver(args: ["swiftc", "-print-target-info"], env: [PATH: ProcessEnv.path!])
@@ -6695,6 +6697,7 @@ final class SwiftDriverTests: XCTestCase {
66956697

66966698
try withTemporaryDirectory { toolsDirectory in
66976699
let customSwiftFrontend = toolsDirectory.appending(component: executableName("swift-frontend"))
6700+
let customSwiftScan = toolsDirectory.appending(component: sharedLibraryName("lib_InternalSwiftScan"))
66986701
try localFileSystem.createSymbolicLink(customSwiftFrontend, pointingAt: defaultSwiftFrontend, relative: false)
66996702

67006703
try withTemporaryDirectory { tempDirectory in
@@ -6707,7 +6710,9 @@ final class SwiftDriverTests: XCTestCase {
67076710
// test if SWIFT_DRIVER_TOOLNAME_EXEC is respected
67086711
do {
67096712
var driver = try Driver(args: ["swiftc", "-print-target-info"],
6710-
env: [PATH: ProcessEnv.path!, SWIFT_FRONTEND_EXEC: customSwiftFrontend.pathString])
6713+
env: [PATH: ProcessEnv.path!,
6714+
SWIFT_FRONTEND_EXEC: customSwiftFrontend.pathString,
6715+
SWIFT_SCANNER_LIB: customSwiftScan.pathString])
67116716
let jobs = try driver.planBuild()
67126717
XCTAssertEqual(jobs.count, 1)
67136718
XCTAssertEqual(jobs.first!.tool.name, customSwiftFrontend.pathString)
@@ -6716,15 +6721,16 @@ final class SwiftDriverTests: XCTestCase {
67166721
// test if tools directory is respected
67176722
do {
67186723
var driver = try Driver(args: ["swiftc", "-print-target-info", "-tools-directory", toolsDirectory.pathString],
6719-
env: [PATH: ProcessEnv.path!])
6724+
env: [PATH: ProcessEnv.path!, SWIFT_SCANNER_LIB: customSwiftScan.pathString])
67206725
let jobs = try driver.planBuild()
67216726
XCTAssertEqual(jobs.count, 1)
67226727
XCTAssertEqual(jobs.first!.tool.name, customSwiftFrontend.pathString)
67236728
}
67246729

67256730
// test if current working directory is searched before PATH
67266731
do {
6727-
var driver = try Driver(args: ["swiftc", "-print-target-info"], env: [PATH: toolsDirectory.pathString])
6732+
var driver = try Driver(args: ["swiftc", "-print-target-info"],
6733+
env: [PATH: toolsDirectory.pathString, SWIFT_SCANNER_LIB: customSwiftScan.pathString])
67286734
let jobs = try driver.planBuild()
67296735
XCTAssertEqual(jobs.count, 1)
67306736
XCTAssertEqual(jobs.first!.tool.name, anotherSwiftFrontend.pathString)

0 commit comments

Comments
 (0)