Skip to content

Commit 3eb6910

Browse files
committed
[PackageModel] Add a new target kind - provided library
This target points to a prebuilt library that comes from a certain location in a toolchain. It's going to be injected by the package manager into library manifests and shouldn't be accessible via user-facing APIs.
1 parent 5aa4835 commit 3eb6910

File tree

16 files changed

+111
-6
lines changed

16 files changed

+111
-6
lines changed

Sources/Build/BuildDescription/ProductBuildDescription.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ package final class ProductBuildDescription: SPMBuildCore.ProductBuildDescriptio
4545
// Computed during build planning.
4646
var dylibs: [ProductBuildDescription] = []
4747

48+
/// The list of provided libraries that are going to be used by this product.
49+
var providedLibraries: [String: AbsolutePath] = [:]
50+
4851
/// Any additional flags to be added. These flags are expected to be computed during build planning.
4952
var additionalFlags: [String] = []
5053

@@ -156,6 +159,8 @@ package final class ProductBuildDescription: SPMBuildCore.ProductBuildDescriptio
156159
args += ["-F", self.buildParameters.buildPath.pathString]
157160
}
158161

162+
self.providedLibraries.forEach { args += ["-L", $1.pathString, "-l", $0] }
163+
159164
args += ["-L", self.buildParameters.buildPath.pathString]
160165
args += try ["-o", binaryPath.pathString]
161166
args += ["-module-name", self.product.name.spm_mangledToC99ExtendedIdentifier()]

Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,8 @@ extension LLBuildManifestBuilder {
424424
if target.underlying is BinaryTarget { return }
425425
// Ignore Plugin Targets.
426426
if target.underlying is PluginTarget { return }
427+
// Ignore Provided Libraries.
428+
if target.underlying is ProvidedLibraryTarget { return }
427429

428430
// Depend on the binary for executable targets.
429431
if target.type == .executable {

Sources/Build/BuildPlan/BuildPlan+Product.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ extension BuildPlan {
115115
}
116116
buildProduct.libraryBinaryPaths = dependencies.libraryBinaryPaths
117117

118+
buildProduct.providedLibraries = dependencies.providedLibraries
119+
118120
buildProduct.availableTools = dependencies.availableTools
119121
}
120122

@@ -127,6 +129,7 @@ extension BuildPlan {
127129
staticTargets: [ResolvedModule],
128130
systemModules: [ResolvedModule],
129131
libraryBinaryPaths: Set<AbsolutePath>,
132+
providedLibraries: [String: AbsolutePath],
130133
availableTools: [String: AbsolutePath]
131134
) {
132135
/* Prior to tools-version 5.9, we used to erroneously recursively traverse executable/plugin dependencies and statically include their
@@ -204,6 +207,7 @@ extension BuildPlan {
204207
var staticTargets = [ResolvedModule]()
205208
var systemModules = [ResolvedModule]()
206209
var libraryBinaryPaths: Set<AbsolutePath> = []
210+
var providedLibraries = [String: AbsolutePath]()
207211
var availableTools = [String: AbsolutePath]()
208212

209213
for dependency in allTargets {
@@ -257,6 +261,8 @@ extension BuildPlan {
257261
}
258262
case .plugin:
259263
continue
264+
case .providedLibrary:
265+
providedLibraries[target.name] = target.underlying.path
260266
}
261267

262268
case .product(let product, _):
@@ -274,7 +280,7 @@ extension BuildPlan {
274280
}
275281
}
276282

277-
return (linkLibraries, staticTargets, systemModules, libraryBinaryPaths, availableTools)
283+
return (linkLibraries, staticTargets, systemModules, libraryBinaryPaths, providedLibraries, availableTools)
278284
}
279285

280286
/// Extracts the artifacts from an artifactsArchive

Sources/Build/BuildPlan/BuildPlan+Swift.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import struct Basics.InternalError
1414
import class PackageModel.BinaryTarget
1515
import class PackageModel.ClangTarget
1616
import class PackageModel.SystemLibraryTarget
17+
import class PackageModel.ProvidedLibraryTarget
1718

1819
extension BuildPlan {
1920
func plan(swiftTarget: SwiftTargetBuildDescription) throws {
@@ -48,6 +49,10 @@ extension BuildPlan {
4849
swiftTarget.libraryBinaryPaths.insert(library.libraryPath)
4950
}
5051
}
52+
case let target as ProvidedLibraryTarget:
53+
swiftTarget.additionalFlags += [
54+
"-I", target.path.pathString
55+
]
5156
default:
5257
break
5358
}

Sources/Build/BuildPlan/BuildPlan.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ public class BuildPlan: SPMBuildCore.BuildPlan {
433433
toolsVersion: toolsVersion,
434434
fileSystem: fileSystem
435435
))
436-
case is SystemLibraryTarget, is BinaryTarget:
436+
case is SystemLibraryTarget, is BinaryTarget, is ProvidedLibraryTarget:
437437
break
438438
default:
439439
throw InternalError("unhandled \(target.underlying)")

Sources/Commands/Snippets/Cards/TopCard.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ fileprivate extension Target.Kind {
153153
return "snippets"
154154
case .macro:
155155
return "macros"
156+
case .providedLibrary:
157+
return "provided libraries"
156158
}
157159
}
158160
}

Sources/PackageLoading/PackageBuilder.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,16 @@ public final class PackageBuilder {
542542
throw ModuleError.artifactNotFound(targetName: target.name, expectedArtifactName: target.name)
543543
}
544544
return artifact.path
545+
} else if let targetPath = target.path, target.type == .providedLibrary {
546+
guard let path = try? AbsolutePath(validating: targetPath) else {
547+
throw ModuleError.invalidCustomPath(target: target.name, path: targetPath)
548+
}
549+
550+
if !self.fileSystem.isDirectory(path) {
551+
throw ModuleError.unsupportedTargetPath(targetPath)
552+
}
553+
554+
return path
545555
} else if let subpath = target.path { // If there is a custom path defined, use that.
546556
if subpath == "" || subpath == "." {
547557
return self.packagePath
@@ -855,6 +865,11 @@ public final class PackageBuilder {
855865
path: potentialModule.path,
856866
origin: artifactOrigin
857867
)
868+
} else if potentialModule.type == .providedLibrary {
869+
return ProvidedLibraryTarget(
870+
name: potentialModule.name,
871+
path: potentialModule.path
872+
)
858873
}
859874

860875
// Check for duplicate target dependencies

Sources/PackageModel/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ add_library(PackageModel
5151
Target/BinaryTarget.swift
5252
Target/ClangTarget.swift
5353
Target/PluginTarget.swift
54+
Target/ProvidedLibraryTarget.swift
5455
Target/SwiftTarget.swift
5556
Target/SystemLibraryTarget.swift
5657
Target/Target.swift

Sources/PackageModel/Manifest/TargetDescription.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public struct TargetDescription: Hashable, Encodable, Sendable {
2121
case binary
2222
case plugin
2323
case `macro`
24+
case providedLibrary
2425
}
2526

2627
/// Represents a target's dependency on another entity.
@@ -222,6 +223,19 @@ public struct TargetDescription: Hashable, Encodable, Sendable {
222223
if pkgConfig != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "pkgConfig") }
223224
if providers != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "providers") }
224225
if pluginCapability != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "pluginCapability") }
226+
case .providedLibrary:
227+
if path == nil { throw Error.providedLibraryTargetRequiresPath(targetName: name) }
228+
if url != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "url") }
229+
if !dependencies.isEmpty { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "dependencies") }
230+
if !exclude.isEmpty { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "exclude") }
231+
if sources != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "sources") }
232+
if !resources.isEmpty { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "resources") }
233+
if publicHeadersPath != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "publicHeadersPath") }
234+
if pkgConfig != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "pkgConfig") }
235+
if providers != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "providers") }
236+
if pluginCapability != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "pluginCapability") }
237+
if !settings.isEmpty { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "settings") }
238+
if pluginUsages != nil { throw Error.disallowedPropertyInTarget(targetName: name, propertyName: "pluginUsages") }
225239
}
226240

227241
self.name = name
@@ -370,13 +384,16 @@ import protocol Foundation.LocalizedError
370384
private enum Error: LocalizedError, Equatable {
371385
case binaryTargetRequiresEitherPathOrURL(targetName: String)
372386
case disallowedPropertyInTarget(targetName: String, propertyName: String)
373-
387+
case providedLibraryTargetRequiresPath(targetName: String)
388+
374389
var errorDescription: String? {
375390
switch self {
376391
case .binaryTargetRequiresEitherPathOrURL(let targetName):
377392
return "binary target '\(targetName)' neither defines neither path nor URL for its artifacts"
378393
case .disallowedPropertyInTarget(let targetName, let propertyName):
379394
return "target '\(targetName)' contains a value for disallowed property '\(propertyName)'"
395+
case .providedLibraryTargetRequiresPath(let targetName):
396+
return "provided library target '\(targetName)' does not define a path to the library"
380397
}
381398
}
382399
}

Sources/PackageModel/ManifestSourceGeneration.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ fileprivate extension SourceCodeFragment {
317317
self.init(enum: "plugin", subnodes: params, multiline: true)
318318
case .macro:
319319
self.init(enum: "macro", subnodes: params, multiline: true)
320+
case .providedLibrary:
321+
self.init(enum: "providedLibrary", subnodes: params, multiline: true)
320322
}
321323
}
322324

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2014-2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import struct Basics.AbsolutePath
14+
15+
/// Represents a target library that comes from a toolchain in prebuilt form.
16+
public final class ProvidedLibraryTarget: Target {
17+
public init(
18+
name: String,
19+
path: AbsolutePath
20+
) {
21+
let sources = Sources(paths: [], root: path)
22+
super.init(
23+
name: name,
24+
type: .providedLibrary,
25+
path: sources.root,
26+
sources: sources,
27+
dependencies: [],
28+
packageAccess: false,
29+
buildSettings: .init(),
30+
buildSettingsDescription: [],
31+
pluginUsages: [],
32+
usesUnsafeFlags: false
33+
)
34+
}
35+
36+
37+
public override func encode(to encoder: Encoder) throws {
38+
try super.encode(to: encoder)
39+
}
40+
41+
required public init(from decoder: Decoder) throws {
42+
try super.init(from: decoder)
43+
}
44+
}

Sources/PackageModel/Target/Target.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public class Target: PolymorphicCodableProtocol {
2121
SystemLibraryTarget.self,
2222
BinaryTarget.self,
2323
PluginTarget.self,
24+
ProvidedLibraryTarget.self,
2425
]
2526

2627
/// The target kind.
@@ -33,6 +34,7 @@ public class Target: PolymorphicCodableProtocol {
3334
case plugin
3435
case snippet
3536
case `macro`
37+
case providedLibrary
3638
}
3739

3840
/// A group a target belongs to that allows customizing access boundaries. A target is treated as

Sources/PackageModelSyntax/AddTarget.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public struct AddTarget {
6262
)
6363

6464
let outerDirectory: String? = switch target.type {
65-
case .binary, .plugin, .system: nil
65+
case .binary, .plugin, .system, .providedLibrary: nil
6666
case .executable, .regular, .macro: "Sources"
6767
case .test: "Tests"
6868
}
@@ -167,7 +167,7 @@ public struct AddTarget {
167167
}
168168

169169
let sourceFileText: SourceFileSyntax = switch target.type {
170-
case .binary, .plugin, .system:
170+
case .binary, .plugin, .system, .providedLibrary:
171171
fatalError("should have exited above")
172172

173173
case .macro:

Sources/PackageModelSyntax/TargetDescription+Syntax.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ extension TargetDescription: ManifestSyntaxRepresentable {
2727
case .regular: "target"
2828
case .system: "systemLibrary"
2929
case .test: "testTarget"
30+
case .providedLibrary: "providedLibrary"
3031
}
3132
}
3233

Sources/SPMBuildCore/Plugins/PluginContextSerializer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ fileprivate extension WireInput.Target.TargetInfo.SourceModuleKind {
282282
self = .test
283283
case .macro:
284284
self = .macro
285-
case .binary, .plugin, .systemModule:
285+
case .binary, .plugin, .systemModule, .providedLibrary:
286286
throw StringError("unexpected target kind \(kind) for source module")
287287
}
288288
}

Sources/XCBuildSupport/PIFBuilder.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,9 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder {
399399
case .macro:
400400
// Macros are not supported when using XCBuild, similar to package plugins.
401401
return
402+
case .providedLibrary:
403+
// Provided libraries don't need to be built.
404+
return
402405
}
403406
}
404407

0 commit comments

Comments
 (0)