Skip to content

Commit d01f6ba

Browse files
committed
automatically populate linker flags for dynamic library dependencies
1 parent 2c12b95 commit d01f6ba

File tree

5 files changed

+49
-27
lines changed

5 files changed

+49
-27
lines changed

Sources/Build/BuildPlan/BuildPlan+Product.swift

+29-17
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,27 @@ extension BuildPlan {
4444
}
4545

4646
// Add flags for binary dependencies.
47-
for binaryPath in dependencies.libraryBinaryPaths {
47+
var dynamicLibraries: Set<Substring> = []
48+
for binaryPath in dependencies.sharedLibraryBinaries {
49+
if binaryPath.basename.starts(with: "lib"), binaryPath.extension == "so" {
50+
buildProduct.additionalFlags += ["-L", binaryPath.parentDirectory.pathString]
51+
dynamicLibraries.insert(binaryPath.basenameWithoutExt.dropFirst(3))
52+
} else {
53+
self.observabilityScope.emit(error: "unexpected binary library")
54+
}
55+
}
56+
for binaryPath in dependencies.xcframeworkBinaries {
4857
if binaryPath.extension == "framework" {
4958
buildProduct.additionalFlags += ["-framework", binaryPath.basenameWithoutExt]
5059
} else if binaryPath.basename.starts(with: "lib") {
51-
buildProduct.additionalFlags += ["-l\(binaryPath.basenameWithoutExt.dropFirst(3))"]
60+
dynamicLibraries.insert(binaryPath.basenameWithoutExt.dropFirst(3))
5261
} else {
5362
self.observabilityScope.emit(error: "unexpected binary framework")
5463
}
5564
}
65+
for dynamicLibrary: Substring in dynamicLibraries {
66+
buildProduct.additionalFlags += ["-l\(dynamicLibrary)"]
67+
}
5668

5769
// Don't link libc++ or libstd++ when building for Embedded Swift.
5870
// Users can still link it manually for embedded platforms when needed,
@@ -102,7 +114,7 @@ extension BuildPlan {
102114
buildProduct.staticTargets = dependencies.staticTargets.map(\.module)
103115
buildProduct.dylibs = dependencies.dylibs
104116
buildProduct.objects += try dependencies.staticTargets.flatMap { try $0.objects }
105-
buildProduct.libraryBinaryPaths = dependencies.libraryBinaryPaths
117+
buildProduct.libraryBinaryPaths = dependencies.xcframeworkBinaries
106118
buildProduct.availableTools = dependencies.availableTools
107119
}
108120

@@ -113,7 +125,8 @@ extension BuildPlan {
113125
dylibs: [ProductBuildDescription],
114126
staticTargets: [ModuleBuildDescription],
115127
systemModules: [ResolvedModule],
116-
libraryBinaryPaths: Set<AbsolutePath>,
128+
sharedLibraryBinaries: Set<AbsolutePath>,
129+
xcframeworkBinaries: Set<AbsolutePath>,
117130
availableTools: [String: AbsolutePath]
118131
) {
119132
let product = productDescription.product
@@ -230,7 +243,8 @@ extension BuildPlan {
230243
var linkLibraries = [ProductBuildDescription]()
231244
var staticTargets = [ModuleBuildDescription]()
232245
var systemModules = [ResolvedModule]()
233-
var libraryBinaryPaths: Set<AbsolutePath> = []
246+
var sharedLibraryBinaries: Set<AbsolutePath> = []
247+
var xcframeworkBinaries: Set<AbsolutePath> = []
234248
var availableTools = [String: AbsolutePath]()
235249

236250
for dependency in allDependencies {
@@ -294,11 +308,17 @@ extension BuildPlan {
294308
triple: productDescription.buildParameters.triple
295309
)
296310
for library in libraries {
297-
libraryBinaryPaths.insert(library.libraryPath)
311+
xcframeworkBinaries.insert(library.libraryPath)
298312
}
299313
case .artifactsArchive:
300-
let tools = try self.parseArtifactsArchive(
301-
for: binaryTarget, triple: productDescription.buildParameters.triple
314+
let libraries = try self.parseLibraries(
315+
in: binaryTarget, triple: productDescription.buildParameters.triple
316+
)
317+
for library in libraries {
318+
sharedLibraryBinaries.insert(library.libraryPath)
319+
}
320+
let tools = try self.parseExecutables(
321+
in: binaryTarget, triple: productDescription.buildParameters.triple
302322
)
303323
tools.forEach { availableTools[$0.name] = $0.executablePath }
304324
case .unknown:
@@ -326,14 +346,6 @@ extension BuildPlan {
326346
})
327347
}
328348

329-
return (linkLibraries, staticTargets, systemModules, libraryBinaryPaths, availableTools)
330-
}
331-
332-
/// Extracts the artifacts from an artifactsArchive
333-
private func parseArtifactsArchive(for binaryTarget: BinaryModule, triple: Triple) throws -> [ExecutableInfo] {
334-
try self.externalExecutablesCache.memoize(key: binaryTarget) {
335-
let execInfos = try binaryTarget.parseArtifactArchives(for: triple, fileSystem: self.fileSystem)
336-
return execInfos.filter { !$0.supportedTriples.isEmpty }
337-
}
349+
return (linkLibraries, staticTargets, systemModules, sharedLibraryBinaries, xcframeworkBinaries, availableTools)
338350
}
339351
}

Sources/Build/BuildPlan/BuildPlan+Swift.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ extension BuildPlan {
4141
case let target as BinaryModule:
4242
switch target.kind {
4343
case .artifactsArchive:
44-
let libraries = try self.parseArtifactbundle(for: target, triple: swiftTarget.buildParameters.triple)
44+
let libraries = try self.parseLibraries(in: target, triple: swiftTarget.buildParameters.triple)
4545
for library in libraries {
4646
library.headersPaths.forEach {
4747
swiftTarget.additionalFlags += ["-I", $0.pathString]

Sources/Build/BuildPlan/BuildPlan.swift

+11-4
Original file line numberDiff line numberDiff line change
@@ -680,13 +680,20 @@ public class BuildPlan: SPMBuildCore.BuildPlan {
680680
return result
681681
}
682682

683-
/// Extracts the library information from an Artifact Bundle.
684-
func parseArtifactbundle(for binaryTarget: BinaryModule, triple: Basics.Triple) throws -> [LibraryInfo] {
683+
/// Extracts the information about executables in an Artifact Bundle, with caching.
684+
func parseExecutables(in binaryTarget: BinaryModule, triple: Basics.Triple) throws -> [ExecutableInfo] {
685+
try self.externalExecutablesCache.memoize(key: binaryTarget) {
686+
let execInfos = try binaryTarget.parseExecutables(for: triple, fileSystem: self.fileSystem)
687+
return execInfos.filter { !$0.supportedTriples.isEmpty }
688+
}
689+
}
690+
/// Extracts the information about libraries in an Artifact Bundle, with caching.
691+
func parseLibraries(in binaryTarget: BinaryModule, triple: Basics.Triple) throws -> [LibraryInfo] {
685692
try self.externalLibrariesCache.memoize(key: binaryTarget) {
686-
try binaryTarget.parseLibraryArtifacts(for: triple, fileSystem: self.fileSystem)
693+
try binaryTarget.parseLibraries(for: triple, fileSystem: self.fileSystem)
687694
}
688695
}
689-
/// Extracts the library information from an XCFramework.
696+
/// Extracts the library information from an XCFramework, with caching.
690697
func parseXCFramework(for binaryTarget: BinaryModule, triple: Basics.Triple) throws -> [LibraryInfo] {
691698
try self.externalLibrariesCache.memoize(key: binaryTarget) {
692699
try binaryTarget.parseXCFrameworks(for: triple, fileSystem: self.fileSystem)

Sources/SPMBuildCore/BinaryTarget+Extensions.swift

+7-4
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ extension BinaryModule {
5555
.map { [try AbsolutePath(validating: $0, relativeTo: libraryDir)] } ?? [] + [libraryDir]
5656
return [LibraryInfo(libraryPath: libraryFile, headersPaths: headersDirs)]
5757
}
58-
59-
public func parseLibraryArtifacts(for triple: Triple, fileSystem: FileSystem) throws -> [LibraryInfo] {
58+
public func parseLibraries(for triple: Triple, fileSystem: FileSystem) throws -> [LibraryInfo] {
6059
let metadata = try ArtifactsArchiveMetadata.parse(fileSystem: fileSystem, rootPath: self.artifactPath)
6160
return metadata.artifacts.reduce(into: []) {
6261
guard case .library = $1.value.type else {
@@ -68,9 +67,8 @@ extension BinaryModule {
6867

6968
$0.append(.init(libraryPath: libraryFile, headersPaths: [libraryDir]))
7069
}
71-
7270
}
73-
public func parseArtifactArchives(for triple: Triple, fileSystem: FileSystem) throws -> [ExecutableInfo] {
71+
public func parseExecutables(for triple: Triple, fileSystem: FileSystem) throws -> [ExecutableInfo] {
7472
// The host triple might contain a version which we don't want to take into account here.
7573
let versionLessTriple = try triple.withoutVersion()
7674
// We return at most a single variant of each artifact.
@@ -96,6 +94,11 @@ extension BinaryModule {
9694
}
9795
}
9896
}
97+
98+
@available(*, deprecated, renamed: "parseExecutables(for:fileSystem:)")
99+
public func parseArtifactArchives(for triple: Triple, fileSystem: FileSystem) throws -> [ExecutableInfo] {
100+
try self.parseExecutables(for: triple, fileSystem: fileSystem)
101+
}
99102
}
100103

101104
extension Triple {

Sources/SPMBuildCore/Plugins/PluginInvocation.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ fileprivate func collectAccessibleTools(
621621
// For a binary target we create a `vendedTool`.
622622
if let module = executableOrBinaryModule as? BinaryModule {
623623
// TODO: Memoize this result for the host triple
624-
let execInfos = try module.parseArtifactArchives(for: hostTriple, fileSystem: fileSystem)
624+
let execInfos = try module.parseExecutables(for: hostTriple, fileSystem: fileSystem)
625625
return try execInfos.map{ .vendedTool(name: $0.name, path: $0.executablePath, supportedTriples: try $0.supportedTriples.map{ try $0.withoutVersion().tripleString }) }
626626
}
627627
// For an executable target we create a `builtTool`.

0 commit comments

Comments
 (0)