Skip to content

Commit 6646c38

Browse files
committed
[Explicit Module Builds] Adopt dependency scanner Link Libraries support
- Adopt new libSwiftScan API to query link libraries for each module dependency - Introduce '-explicit-auto-linking' to turn explicit dependency link library information into flags passed directly to the linker invocation
1 parent 193e2c7 commit 6646c38

File tree

12 files changed

+228
-11
lines changed

12 files changed

+228
-11
lines changed

Sources/CSwiftScan/include/swiftscan_header.h

+16-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include <stdint.h>
1919

2020
#define SWIFTSCAN_VERSION_MAJOR 0
21-
#define SWIFTSCAN_VERSION_MINOR 6
21+
#define SWIFTSCAN_VERSION_MINOR 10
2222

2323
//=== Public Scanner Data Types -------------------------------------------===//
2424

@@ -41,6 +41,7 @@ typedef enum {
4141

4242
typedef struct swiftscan_module_details_s *swiftscan_module_details_t;
4343
typedef struct swiftscan_dependency_info_s *swiftscan_dependency_info_t;
44+
typedef struct swiftscan_link_library_info_s *swiftscan_link_library_info_t;
4445
typedef struct swiftscan_dependency_graph_s *swiftscan_dependency_graph_t;
4546
typedef struct swiftscan_import_set_s *swiftscan_import_set_t;
4647
typedef struct swiftscan_diagnostic_info_s *swiftscan_diagnostic_info_t;
@@ -60,6 +61,10 @@ typedef struct {
6061
swiftscan_dependency_info_t *modules;
6162
size_t count;
6263
} swiftscan_dependency_set_t;
64+
typedef struct {
65+
swiftscan_link_library_info_t *link_libraries;
66+
size_t count;
67+
} swiftscan_link_library_set_t;
6368

6469
//=== Batch Scan Input Specification --------------------------------------===//
6570

@@ -110,9 +115,19 @@ typedef struct {
110115
(*swiftscan_module_info_get_source_files)(swiftscan_dependency_info_t);
111116
swiftscan_string_set_t *
112117
(*swiftscan_module_info_get_direct_dependencies)(swiftscan_dependency_info_t);
118+
swiftscan_link_library_set_t *
119+
(*swiftscan_module_info_get_link_libraries)(swiftscan_dependency_graph_t);
113120
swiftscan_module_details_t
114121
(*swiftscan_module_info_get_details)(swiftscan_dependency_info_t);
115122

123+
//=== Link Library Info Functions ------------------------------------===//
124+
swiftscan_string_ref_t
125+
(*swiftscan_link_library_info_get_link_name)(swiftscan_link_library_info_t);
126+
bool
127+
(*swiftscan_link_library_info_get_is_framework)(swiftscan_link_library_info_t);
128+
bool
129+
(*swiftscan_link_library_info_get_should_force_load)(swiftscan_link_library_info_t);
130+
116131
//=== Dependency Module Info Details Functions ----------------------------===//
117132
swiftscan_dependency_info_kind_t
118133
(*swiftscan_module_detail_get_kind)(swiftscan_module_details_t);

Sources/SwiftDriver/Driver/Driver.swift

+8
Original file line numberDiff line numberDiff line change
@@ -3076,6 +3076,14 @@ extension Driver {
30763076
diagnosticsEngine.emit(.error_hermetic_seal_requires_lto)
30773077
}
30783078
}
3079+
3080+
if parsedOptions.hasArgument(.explicitAutoLinking) {
3081+
if !parsedOptions.hasArgument(.driverExplicitModuleBuild) {
3082+
diagnosticsEngine.emit(.error(Error.optionRequiresAnother(Option.explicitAutoLinking.spelling,
3083+
Option.driverExplicitModuleBuild.spelling)),
3084+
location: nil)
3085+
}
3086+
}
30793087
}
30803088

30813089
private static func validateSanitizerAddressUseOdrIndicatorFlag(

Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift

+24-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
3434
/// that specify said explicit module dependencies.
3535
@_spi(Testing) public struct ExplicitDependencyBuildPlanner {
3636
/// The module dependency graph.
37-
private let dependencyGraph: InterModuleDependencyGraph
37+
@_spi(Testing) public let dependencyGraph: InterModuleDependencyGraph
3838

3939
/// A set of direct and transitive dependencies for every module in the dependency graph
4040
private let reachabilityMap: [ModuleDependencyId : Set<ModuleDependencyId>]
@@ -421,6 +421,29 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
421421
}
422422
}
423423

424+
public func getLinkLibraryLoadCommandFlags(_ commandLine: inout [Job.ArgTemplate]) throws {
425+
var allLinkLibraries: [LinkLibraryInfo] = []
426+
for (_, moduleInfo) in dependencyGraph.modules {
427+
guard let moduleLinkLibraries = moduleInfo.linkLibraries else {
428+
continue
429+
}
430+
for linkLibrary in moduleLinkLibraries {
431+
allLinkLibraries.append(linkLibrary)
432+
}
433+
}
434+
435+
for linkLibrary in allLinkLibraries {
436+
if !linkLibrary.isFramework {
437+
commandLine.appendFlag("-l\(linkLibrary.linkName)")
438+
} else {
439+
commandLine.appendFlag(.Xlinker)
440+
commandLine.appendFlag("-framework")
441+
commandLine.appendFlag(.Xlinker)
442+
commandLine.appendFlag(linkLibrary.linkName)
443+
}
444+
}
445+
}
446+
424447
/// Resolve all module dependencies of the main module and add them to the lists of
425448
/// inputs and command line flags.
426449
public mutating func resolveMainModuleDependencies(inputs: inout [TypedVirtualPath],

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/CommonDependencyOperations.swift

+12-6
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,26 @@ import func TSCBasic.topologicalSort
2727
if let currentInfo = modules[swiftModuleId],
2828
externalModuleId.moduleName != mainModuleName {
2929
let newExternalModuleDetails =
30-
try SwiftPrebuiltExternalModuleDetails(compiledModulePath:
31-
TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()),
32-
isFramework: externalModuleDetails.isFramework)
30+
SwiftPrebuiltExternalModuleDetails(compiledModulePath:
31+
TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()),
32+
isFramework: externalModuleDetails.isFramework)
3333
let newInfo = ModuleInfo(modulePath: TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()),
3434
sourceFiles: [],
3535
directDependencies: currentInfo.directDependencies,
36+
linkLibraries: currentInfo.linkLibraries,
3637
details: .swiftPrebuiltExternal(newExternalModuleDetails))
3738
Self.replaceModule(originalId: swiftModuleId, replacementId: prebuiltModuleId,
3839
replacementInfo: newInfo, in: &modules)
3940
} else if let currentPrebuiltInfo = modules[prebuiltModuleId] {
4041
// Just update the isFramework bit on this prebuilt module dependency
4142
let newExternalModuleDetails =
42-
try SwiftPrebuiltExternalModuleDetails(compiledModulePath:
43-
TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()),
44-
isFramework: externalModuleDetails.isFramework)
43+
SwiftPrebuiltExternalModuleDetails(compiledModulePath:
44+
TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()),
45+
isFramework: externalModuleDetails.isFramework)
4546
let newInfo = ModuleInfo(modulePath: TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()),
4647
sourceFiles: [],
4748
directDependencies: currentPrebuiltInfo.directDependencies,
49+
linkLibraries: currentPrebuiltInfo.linkLibraries,
4850
details: .swiftPrebuiltExternal(newExternalModuleDetails))
4951
Self.replaceModule(originalId: prebuiltModuleId, replacementId: prebuiltModuleId,
5052
replacementInfo: newInfo, in: &modules)
@@ -231,6 +233,9 @@ extension InterModuleDependencyGraph {
231233
let firstModuleDependencies = firstInfo.directDependencies ?? []
232234
let secondModuleDependencies = secondInfo.directDependencies ?? []
233235
let combinedDependencies = Array(Set(firstModuleDependencies + secondModuleDependencies))
236+
let firstLinkLibraries = firstInfo.linkLibraries ?? []
237+
let secondLinkLibraries = secondInfo.linkLibraries ?? []
238+
let combinedLinkLibraries = Array(Set(firstLinkLibraries + secondLinkLibraries))
234239

235240
let firstModuleCapturedPCMArgs = firstDetails.capturedPCMArgs ?? Set<[String]>()
236241
let secondModuleCapturedPCMArgs = secondDetails.capturedPCMArgs ?? Set<[String]>()
@@ -245,6 +250,7 @@ extension InterModuleDependencyGraph {
245250
return ModuleInfo(modulePath: firstInfo.modulePath,
246251
sourceFiles: combinedSourceFiles,
247252
directDependencies: combinedDependencies,
253+
linkLibraries: combinedLinkLibraries,
248254
details: .clang(combinedModuleDetails))
249255
}
250256
}

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift

+13-1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ public struct BridgingHeader: Codable, Hashable {
9494
var moduleDependencies: [String]
9595
}
9696

97+
/// Linked Library
98+
public struct LinkLibraryInfo: Codable, Hashable {
99+
public var linkName: String
100+
public var isFramework: Bool
101+
public var shouldForceLoad: Bool
102+
}
103+
97104
/// Details specific to Swift modules.
98105
public struct SwiftModuleDetails: Codable, Hashable {
99106
/// The module interface from which this module was built, if any.
@@ -203,6 +210,9 @@ public struct ModuleInfo: Codable, Hashable {
203210
/// The set of direct module dependencies of this module.
204211
public var directDependencies: [ModuleDependencyId]?
205212

213+
/// The set of libraries that need to be linked
214+
public var linkLibraries: [LinkLibraryInfo]?
215+
206216
/// Specific details of a particular kind of module.
207217
public var details: Details
208218

@@ -226,10 +236,12 @@ public struct ModuleInfo: Codable, Hashable {
226236
public init(modulePath: TextualVirtualPath,
227237
sourceFiles: [String]?,
228238
directDependencies: [ModuleDependencyId]?,
239+
linkLibraries: [LinkLibraryInfo]?,
229240
details: Details) {
230241
self.modulePath = modulePath
231242
self.sourceFiles = sourceFiles
232243
self.directDependencies = directDependencies
244+
self.linkLibraries = linkLibraries
233245
self.details = details
234246
}
235247
}
@@ -306,7 +318,7 @@ public struct InterModuleDependencyGraph: Codable {
306318
public var mainModule: ModuleInfo { modules[.swift(mainModuleName)]! }
307319
}
308320

309-
internal extension InterModuleDependencyGraph {
321+
@_spi(Testing) public extension InterModuleDependencyGraph {
310322
func toJSONData() throws -> Data {
311323
let encoder = JSONEncoder()
312324
#if os(Linux) || os(Android)

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift

+7
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,13 @@ public class InterModuleDependencyOracle {
174174
return swiftScan.supportsDiagnosticSourceLocations
175175
}
176176

177+
@_spi(Testing) public func supportsLinkLibraries() throws -> Bool {
178+
guard let swiftScan = swiftScanLibInstance else {
179+
fatalError("Attempting to query supported scanner API with no scanner instance.")
180+
}
181+
return swiftScan.supportsLinkLibraries
182+
}
183+
177184
@_spi(Testing) public func getScannerDiagnostics() throws -> [ScannerDiagnosticPayload]? {
178185
guard let swiftScan = swiftScanLibInstance else {
179186
fatalError("Attempting to reset scanner cache with no scanner instance.")

Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift

+6
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,12 @@ extension Driver {
472472
commandLine.appendFlag("-frontend-parseable-output")
473473
}
474474

475+
// If explicit auto-linking is enabled, ensure that compiler tasks do not produce
476+
// auto-link load commands in resulting object files.
477+
if parsedOptions.hasArgument(.explicitAutoLinking) {
478+
commandLine.appendFlag(.disableAllAutolinking)
479+
}
480+
475481
savedUnknownDriverFlagsForSwiftFrontend.forEach {
476482
commandLine.appendFlag($0)
477483
}

Sources/SwiftDriver/Jobs/LinkJob.swift

+4
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ extension Driver {
7575
targetInfo: frontendTargetInfo
7676
)
7777

78+
if parsedOptions.hasArgument(.explicitAutoLinking) {
79+
try explicitDependencyBuildPlanner?.getLinkLibraryLoadCommandFlags(&commandLine)
80+
}
81+
7882
return Job(
7983
moduleName: moduleOutputInfo.name,
8084
kind: .link,

Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift

+25
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,24 @@ private extension SwiftScan {
120120
directDependencies = nil
121121
}
122122

123+
var linkLibraries: [LinkLibraryInfo] = []
124+
if supportsLinkLibraries {
125+
let linkLibrarySetRefOrNull = api.swiftscan_module_info_get_link_libraries(moduleInfoRef)
126+
guard let linkLibrarySetRef = linkLibrarySetRefOrNull else {
127+
throw DependencyScanningError.missingField("dependency_graph.link_libraries")
128+
}
129+
// Turn the `swiftscan_dependency_set_t` into an array of `swiftscan_dependency_info_t`
130+
// references we can iterate through in order to construct `ModuleInfo` objects.
131+
let linkLibraryRefArray = Array(UnsafeBufferPointer(start: linkLibrarySetRef.pointee.link_libraries,
132+
count: Int(linkLibrarySetRef.pointee.count)))
133+
for linkLibraryRefOrNull in linkLibraryRefArray {
134+
guard let linkLibraryRef = linkLibraryRefOrNull else {
135+
throw DependencyScanningError.missingField("dependency_set_t.link_libraries[_]")
136+
}
137+
linkLibraries.append(try constructLinkLibrayInfo(from: linkLibraryRef))
138+
}
139+
}
140+
123141
guard let moduleDetailsRef = api.swiftscan_module_info_get_details(moduleInfoRef) else {
124142
throw DependencyScanningError.missingField("modules[\(moduleId)].details")
125143
}
@@ -128,9 +146,16 @@ private extension SwiftScan {
128146

129147
return (moduleId, ModuleInfo(modulePath: modulePath, sourceFiles: sourceFiles,
130148
directDependencies: directDependencies,
149+
linkLibraries: linkLibraries,
131150
details: details))
132151
}
133152

153+
func constructLinkLibrayInfo(from linkLibraryInfoRef: swiftscan_link_library_info_t) throws -> LinkLibraryInfo {
154+
return LinkLibraryInfo(linkName: try toSwiftString(api.swiftscan_link_library_info_get_link_name(linkLibraryInfoRef)),
155+
isFramework: api.swiftscan_link_library_info_get_is_framework(linkLibraryInfoRef),
156+
shouldForceLoad: api.swiftscan_link_library_info_get_should_force_load(linkLibraryInfoRef))
157+
}
158+
134159
/// From a reference to a binary-format module info details object info returned by libSwiftScan,
135160
/// construct an instance of an `ModuleInfo`.Details as used by the driver.
136161
/// The object returned by libSwiftScan is a union so ensure to execute dependency-specific queries.

Sources/SwiftDriver/SwiftScan/SwiftScan.swift

+12
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,13 @@ private extension String {
364364
api.swiftscan_source_location_get_column_number != nil
365365
}
366366

367+
@_spi(Testing) public var supportsLinkLibraries : Bool {
368+
return api.swiftscan_module_info_get_link_libraries != nil &&
369+
api.swiftscan_link_library_info_get_link_name != nil &&
370+
api.swiftscan_link_library_info_get_is_framework != nil &&
371+
api.swiftscan_link_library_info_get_should_force_load != nil
372+
}
373+
367374
func serializeScannerCache(to path: AbsolutePath) {
368375
api.swiftscan_scanner_cache_serialize(scanner,
369376
path.description.cString(using: String.Encoding.utf8))
@@ -636,6 +643,11 @@ private extension swiftscan_functions_t {
636643
self.swiftscan_source_location_get_line_number = try loadOptional("swiftscan_source_location_get_line_number")
637644
self.swiftscan_source_location_get_column_number = try loadOptional("swiftscan_source_location_get_column_number")
638645

646+
self.swiftscan_module_info_get_link_libraries = try loadOptional("swiftscan_module_info_get_link_libraries")
647+
self.swiftscan_link_library_info_get_link_name = try loadOptional("swiftscan_link_library_info_get_link_name")
648+
self.swiftscan_link_library_info_get_is_framework = try loadOptional("swiftscan_link_library_info_get_is_framework")
649+
self.swiftscan_link_library_info_get_should_force_load = try loadOptional("swiftscan_link_library_info_get_should_force_load")
650+
639651
// Swift Overlay Dependencies
640652
self.swiftscan_swift_textual_detail_get_swift_overlay_dependencies =
641653
try loadOptional("swiftscan_swift_textual_detail_get_swift_overlay_dependencies")

0 commit comments

Comments
 (0)