Skip to content

Commit 3982378

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 3208d49 commit 3982378

File tree

8 files changed

+102
-90
lines changed

8 files changed

+102
-90
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: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ 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)
224+
let scanLibPath = try toolchain.lookupSwiftScanLib()
225225
if try interModuleDependencyOracle
226226
.verifyOrCreateScannerInstance(fileSystem: fileSystem,
227227
swiftScanLibPath: scanLibPath) == false {
@@ -490,46 +490,9 @@ public extension Driver {
490490
useResponseFiles: useResponseFiles)
491491
return args
492492
}
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-
}
527493

528494
static func getRootPath(of toolchain: Toolchain, env: [String: String])
529495
throws -> AbsolutePath {
530-
if let overrideString = env["SWIFT_DRIVER_SWIFT_SCAN_TOOLCHAIN_PATH"] {
531-
return try AbsolutePath(validating: overrideString)
532-
}
533496
return try toolchain.getToolPath(.swiftCompiler)
534497
.parentDirectory // bin
535498
.parentDirectory // toolchain root

Sources/SwiftDriver/Jobs/EmitSupportedFeaturesJob.swift

Lines changed: 7 additions & 10 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,13 +85,9 @@ 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)
90+
let swiftScanLibPath = try toolchain.lookupSwiftScanLib()
9491
if fileSystem.exists(swiftScanLibPath) {
9592
let libSwiftScanInstance = try SwiftScan(dylib: swiftScanLibPath)
9693
if libSwiftScanInstance.canQuerySupportedArguments() {

Sources/SwiftDriver/SwiftScan/SwiftScan.swift

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,10 @@ 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) {
324-
let libSwiftScanInstance = try SwiftScan(dylib: scanLibPath)
325-
if libSwiftScanInstance.canQuerySupportedArguments() {
326-
return try libSwiftScanInstance.querySupportedArguments()
327-
}
320+
let scanLibPath = try toolchain.lookupSwiftScanLib()
321+
let libSwiftScanInstance = try SwiftScan(dylib: scanLibPath)
322+
if libSwiftScanInstance.canQuerySupportedArguments() {
323+
return try libSwiftScanInstance.querySupportedArguments()
328324
}
329325
return nil
330326
}

Sources/SwiftDriver/Toolchains/Toolchain.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,46 @@ 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 toolchain.getToolPath(.swiftCompiler)
256+
.parentDirectory // bin
257+
.appending(component: "_InternalSwiftScan.dll")
258+
#else
259+
let libraryName = sharedLibraryName("lib_InternalSwiftScan")
260+
if let overrideString = env["SWIFT_DRIVER_SWIFTSCAN_LIB"],
261+
let path = try? AbsolutePath(validating: overrideString) {
262+
return path
263+
} else {
264+
let compilerPath = try getToolPath(.swiftCompiler)
265+
let toolchainRootPath = compilerPath.parentDirectory // bin
266+
.parentDirectory // toolchain root
267+
268+
let searchPaths = [toolchainRootPath.appending(component: "lib")
269+
.appending(component: "swift")
270+
.appending(component: compilerHostSupportLibraryOSComponent),
271+
toolchainRootPath.appending(component: "lib")
272+
.appending(component: "swift")
273+
.appending(component: "host"),
274+
// In case we are using a compiler from the build dir, we should also try
275+
// this path.
276+
toolchainRootPath.appending(component: "lib")]
277+
for libraryPath in searchPaths.map({ $0.appending(component: libraryName) }) {
278+
if fileSystem.isFile(libraryPath) {
279+
return libraryPath
280+
}
281+
}
282+
}
283+
284+
throw ToolchainError.unableToFind(tool: libraryName)
285+
#endif
286+
}
287+
248288
private func xcrunFind(executable: String) throws -> AbsolutePath {
249289
let xcrun = "xcrun"
250290
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 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 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 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 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 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 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 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)