Skip to content

Commit a834937

Browse files
heckjFranzBuschbripeticca
authored
Traits docs (#9048)
Adds documentation for the Swift 6.1 traits feature ### Motivation: - Show how to consume packages that provide traits - Show how to present traits from your package(s) - Updating PackageDescription API to use slightly more readable content related to traits. ### Modifications: - updated PackageDescription API around traits - added curation (organization) for Traits and Package/Dependency/Traits - extended `Using Dependencies` article to touch on traits and how to consume packages that provide them - added an article to share patterns to use when providing a traits from your own package ### Result: Updated content and one additional article in the central documentation for Swift Package Manager that illustrates how to consume and provide packages with traits. --------- Co-authored-by: Franz Busch <[email protected]> Co-authored-by: Bri Peticca <[email protected]>
1 parent d7465ef commit a834937

File tree

10 files changed

+367
-76
lines changed

10 files changed

+367
-76
lines changed

Sources/PackageDescription/PackageDependency.swift

Lines changed: 74 additions & 44 deletions
Large diffs are not rendered by default.

Sources/PackageDescription/PackageDependencyTrait.swift

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,22 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
extension Package.Dependency {
14-
/// A struct representing an enabled trait of a dependency.
14+
/// An enabled trait of a dependency.
1515
@available(_PackageDescription, introduced: 6.1)
1616
public struct Trait: Hashable, Sendable, ExpressibleByStringLiteral {
17-
/// Enables all default traits of a package.
17+
/// Enables all default traits of the dependency.
1818
public static let defaults = Self.init(name: "default")
1919

20-
/// A condition that limits the application of a dependencies trait.
20+
/// A condition that limits the application of a trait for a dependency.
2121
public struct Condition: Hashable, Sendable {
22-
/// The set of traits of this package that enable the dependencie's trait.
22+
/// The set of traits that enable the dependencies trait.
2323
let traits: Set<String>?
2424

2525
/// Creates a package dependency trait condition.
2626
///
27-
/// - Parameter traits: The set of traits that enable the dependencies trait. If any of the traits are enabled on this package
28-
/// the dependencies trait will be enabled.
27+
/// If the depending package enables any of the traits you provide, the package manager enables the dependency to which this condition applies.
28+
///
29+
/// - Parameter traits: The set of traits that enable the dependencies trait.
2930
public static func when(
3031
traits: Set<String>
3132
) -> Self? {
@@ -36,10 +37,10 @@ extension Package.Dependency {
3637
/// The name of the enabled trait.
3738
public var name: String
3839

39-
/// The condition under which the trait is enabled.
40+
/// The condition under which the package manager enables the dependency.
4041
public var condition: Condition?
4142

42-
/// Initializes a new enabled trait.
43+
/// Creates a new enabled trait.
4344
///
4445
/// - Parameters:
4546
/// - name: The name of the enabled trait.
@@ -52,11 +53,14 @@ extension Package.Dependency {
5253
self.condition = condition
5354
}
5455

56+
/// Creates a new enabled trait.
57+
///
58+
/// - Parameter value: The name of the enabled trait.
5559
public init(stringLiteral value: StringLiteralType) {
5660
self.init(name: value)
5761
}
5862

59-
/// Initializes a new enabled trait.
63+
/// Creates a new enabled trait.
6064
///
6165
/// - Parameters:
6266
/// - name: The name of the enabled trait.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# ``PackageDescription/Package/Dependency/Trait``
2+
3+
## Topics
4+
5+
### Declaring a Dependency Trait
6+
7+
- ``trait(name:condition:)``
8+
- ``defaults``
9+
10+
### Creating a Dependency Trait
11+
12+
- ``init(name:condition:)``
13+
- ``init(stringLiteral:)``
14+
- ``Condition``
15+
16+
### Inspecting a Dependency Trait
17+
18+
- ``name``
19+
- ``condition``

Sources/PackageDescription/PackageDescription.docc/Curation/Dependency.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,12 @@
4141
- ``Trait``
4242
- ``RegistryRequirement``
4343
- ``SourceControlRequirement``
44-
- ``requirement-swift.property``
45-
- ``Requirement-swift.enum``
4644

4745
### Describing a Package Dependency
4846

4947
- ``kind-swift.property``
5048
- ``Kind``
5149
- ``Version``
52-
- ``name``
53-
- ``url``
5450

5551
### Deprecated methods
5652

@@ -63,3 +59,5 @@
6359
- ``package(url:_:)-(_,Package.Dependency.Requirement)``
6460
- ``name``
6561
- ``url``
62+
- ``requirement-swift.property``
63+
- ``Requirement-swift.enum``

Sources/PackageDescription/PackageDescription.docc/Curation/Package.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66

77
- ``Package/init(name:defaultLocalization:platforms:pkgConfig:providers:products:dependencies:targets:swiftLanguageModes:cLanguageStandard:cxxLanguageStandard:)``
88
- ``Package/init(name:defaultLocalization:platforms:pkgConfig:providers:products:traits:dependencies:targets:swiftLanguageModes:cLanguageStandard:cxxLanguageStandard:)``
9-
- ``Package/init(name:defaultLocalization:platforms:pkgConfig:providers:products:dependencies:targets:swiftLanguageVersions:cLanguageStandard:cxxLanguageStandard:)``
109
- ``Package/init(name:platforms:pkgConfig:providers:products:dependencies:targets:swiftLanguageVersions:cLanguageStandard:cxxLanguageStandard:)``
1110
- ``Package/init(name:pkgConfig:providers:products:dependencies:targets:swiftLanguageVersions:cLanguageStandard:cxxLanguageStandard:)-(_,_,_,_,_,_,[Int]?,_,_)``
1211
- ``Package/init(name:pkgConfig:providers:products:dependencies:targets:swiftLanguageVersions:cLanguageStandard:cxxLanguageStandard:)-(_,_,_,_,_,_,[SwiftVersion]?,_,_)``
13-
12+
- ``Package/init(name:defaultLocalization:platforms:pkgConfig:providers:products:dependencies:targets:swiftLanguageVersions:cLanguageStandard:cxxLanguageStandard:)``
1413

1514
### Naming the Package
1615

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# ``PackageDescription/Trait``
2+
3+
## Topics
4+
5+
### Declaring Traits
6+
7+
- ``trait(name:description:enabledTraits:)``
8+
- ``default(enabledTraits:)``
9+
10+
### Creating Traits
11+
12+
- ``init(name:description:enabledTraits:)``
13+
- ``init(stringLiteral:)``
14+
15+
### Inspecting Traits
16+
17+
- ``name``
18+
- ``description``
19+
- ``enabledTraits``
20+

Sources/PackageDescription/PackageDescription.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public final class Package {
9797
/// The list of products that this package vends and that clients can use.
9898
public var products: [Product]
9999

100-
/// The set of traits of this package.
100+
/// The set of traits this package provides.
101101
@available(_PackageDescription, introduced: 6.1)
102102
public var traits: Set<Trait>
103103

@@ -344,7 +344,7 @@ public final class Package {
344344
/// `<name>.pc` file to get the additional flags required for a system target.
345345
/// - providers: The package providers for a system target.
346346
/// - products: The list of products that this package makes available for clients to use.
347-
/// - traits: The set of traits of this package.
347+
/// - traits: The set of traits this package provides.
348348
/// - dependencies: The list of package dependencies.
349349
/// - targets: The list of targets that are part of this package.
350350
/// - swiftLanguageModes: The list of Swift language modes with which this package is compatible.

Sources/PackageDescription/Trait.swift

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,50 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
/// A struct representing a package's trait.
13+
/// A package trait.
1414
///
15-
/// Traits can be used for expressing conditional compilation and optional dependencies.
15+
/// A trait is a package feature that expresses conditional compilation and potentially optional dependencies.
16+
/// It is typically used to expose additional or extended API for the package.
1617
///
17-
/// - Important: Traits must be strictly additive and enabling a trait **must not** remove API.
18+
/// When you define a trait on a package, the package manager uses the name of that trait as a conditional block for the package's code.
19+
/// Use the conditional block to enable imports or code paths for that trait.
20+
/// For example, a trait with the canonical name `MyTrait` allows you to use the name as a conditional block:
21+
///
22+
/// ```swift
23+
/// #if MyTrait
24+
/// // additional imports or APIs that MyTrait enables
25+
/// #endif // MyTrait
26+
/// ```
27+
///
28+
/// - Important: Traits must be strictly additive. Enabling a trait **must not** remove API.
29+
///
30+
/// If your conditional code requires a dependency that you want to enable only when the trait is enabled,
31+
/// add a conditional declaration to the target dependencies,
32+
/// then include the import statement within the conditional block.
33+
/// The following example illustrates enabling the dependency `MyDependency` when the trait `Trait1` is enabled:
34+
///
35+
/// ```swift
36+
/// targets: [
37+
/// .target(
38+
/// name: "MyTarget",
39+
/// dependencies: [
40+
/// .product(
41+
/// name: "MyAPI",
42+
/// package: "MyDependency",
43+
/// condition: .when(traits: ["Trait1"])
44+
/// )
45+
/// ]
46+
/// ),
47+
/// ]
48+
/// ```
49+
///
50+
/// Coordinate a declaration like the example above with code that imports the dependency in a conditional block:
51+
///
52+
/// ```swift
53+
/// #if Trait1
54+
/// import MyAPI
55+
/// #endif // Trait1
56+
/// ```
1857
@available(_PackageDescription, introduced: 6.1)
1958
public struct Trait: Hashable, ExpressibleByStringLiteral {
2059
/// Declares the default traits for this package.
@@ -28,25 +67,26 @@ public struct Trait: Hashable, ExpressibleByStringLiteral {
2867

2968
/// The trait's canonical name.
3069
///
31-
/// This is used when enabling the trait or when referring to it from other modifiers in the manifest.
70+
/// Use the trait's name to enable the trait or when referring to it from other modifiers in the manifest.
71+
/// The trait's name also defines the conditional block that the compiler supports when the trait is active.
3272
///
3373
/// The following rules are enforced on trait names:
3474
/// - The first character must be a [Unicode XID start character](https://unicode.org/reports/tr31/#Figure_Code_Point_Categories_for_Identifier_Parsing)
3575
/// (most letters), a digit, or `_`.
3676
/// - Subsequent characters must be a [Unicode XID continue character](https://unicode.org/reports/tr31/#Figure_Code_Point_Categories_for_Identifier_Parsing)
3777
/// (a digit, `_`, or most letters), `-`, or `+`.
38-
/// - `default` and `defaults` (in any letter casing combination) are not allowed as trait names to avoid confusion with default traits.
78+
/// - The names `default` and `defaults` (in any letter casing combination) aren't allowed as trait names to avoid confusion with default traits.
3979
public var name: String
4080

4181
/// The trait's description.
4282
///
43-
/// Use this to explain what functionality this trait enables.
83+
/// Use the description to explain the additional functionality that the trait enables.
4484
public var description: String?
4585

4686
/// A set of other traits of this package that this trait enables.
4787
public var enabledTraits: Set<String>
4888

49-
/// Initializes a new trait.
89+
/// Creates a trait with a name, a description, and set of additional traits it enables.
5090
///
5191
/// - Parameters:
5292
/// - name: The trait's canonical name.
@@ -62,11 +102,13 @@ public struct Trait: Hashable, ExpressibleByStringLiteral {
62102
self.enabledTraits = enabledTraits
63103
}
64104

105+
/// Creates a trait with the name you provide.
106+
/// - Parameter value: The trait's canonical name.
65107
public init(stringLiteral value: StringLiteralType) {
66108
self.init(name: value)
67109
}
68110

69-
/// Initializes a new trait.
111+
/// Creates a trait with a name, a description, and set of additional traits it enables.
70112
///
71113
/// - Parameters:
72114
/// - name: The trait's canonical name.

Sources/PackageManagerDocs/Documentation.docc/AddingDependencies.md

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# Adding dependencies to a Swift package
22

3-
Use other swift packages, system libraries, or binary dependencies in your package.
3+
Use other Swift packages, system libraries, or binary dependencies in your package.
44

55
## Overview
66

77
To depend on another Swift package, define a dependency and the requirements for its version if it's remote, then add a product of that dependency to one or more of your targets.
88

99
A remote dependency requires a location, represented by a URL, and a requirement on the versions the package manager may use.
1010

11-
The following example illustrates a package that depends on [PlayingCard](https://github.com/apple/example-package-playingcard), using `from` to require at least version `3.0.4`, and allow any other version up to the next major version that is available at the time of dependency resolution.
11+
The following example illustrates a package that depends on [PlayingCard](https://github.com/apple/example-package-playingcard), using `from` to require at least version `4.0.0`, and allow any other version up to the next major version that is available at the time of dependency resolution.
1212
It then uses the product `PlayingCard` as a dependency for the target `MyPackage`:
1313

1414
```swift
@@ -19,7 +19,7 @@ let package = Package(
1919
name: "MyPackage",
2020
dependencies: [
2121
.package(url: "https://github.com/apple/example-package-playingcard.git",
22-
from: "3.0.4"),
22+
from: "4.0.0"),
2323
],
2424
targets: [
2525
.target(
@@ -43,15 +43,52 @@ For more information on resolving package versions, see <doc:ResolvingPackageVer
4343

4444
### Constraining dependency versions
4545

46-
Constrain the version of a remote dependency when you when you declare the dependency.
47-
The package manager uses git tags interpretted as semantic versions to identify eligible versions of packages.
46+
Constrain the version of a remote dependency when you declare the dependency.
47+
The package manager uses git tags, interpreted as a semantic version, to identify eligible versions of packages.
4848

49-
> Note: tags for package versions should include all three components of a semantic version: major, minor, and patch.
49+
> Note: tags for package versions should include all three components of a semantic version: major, minor, and patch.
5050
> Tags that only include one or two of those components are not interpreted as semantic versions.
5151
5252
Use the version requirement when you declare the dependency to limit what the package manager can choose.
5353
The version requirement can be a range of possible semantic versions, a specific semantic version, a branch name, or a commit hash.
54-
The API reference documentation for [Package.Dependency](https://developer.apple.com/documentation/packagedescription/package/dependency) defines the methods to use.
54+
The API reference documentation for [Package.Dependency](https://docs.swift.org/swiftpm/documentation/packagedescription/package/dependency) defines the methods to use.
55+
56+
### Packages with Traits
57+
58+
Traits, introduced with Swift 6.1, allow packages to offer additional API that may include optional dependencies.
59+
Packages should offer traits to provide API beyond the core of a package.
60+
For example, a package may provide an experimental API, an optional API that requires additional dependencies, or functionality that isn't critical that a developer may want to enable only in specific circumstances.
61+
62+
If a package offers traits and you depend on it without defining the traits to use, the package uses its default set of traits.
63+
In the following example, the dependency `example-package-playingcard` uses its default traits, if it offers any:
64+
```swift
65+
dependencies: [
66+
.package(url: "https://github.com/swiftlang/example-package-playingcard",
67+
from: "4.0.0")
68+
]
69+
```
70+
71+
To determine what traits a package offers, including its defaults, either inspect its `Package.swift` manifest or use <doc:PackageShowDependencies> to print out the resolved dependencies and their traits.
72+
73+
Enabling a trait should only expand the API offered by a package.
74+
If a package offers default traits, you can choose to not use those traits by declaring an empty set of traits when you declare the dependency.
75+
The following example dependency declaration uses the dependency with no traits, even if the package normally provides a set of default traits to enable:
76+
77+
```swift
78+
dependencies: [
79+
.package(url: "https://github.com/swiftlang/example-package-playingcard",
80+
from: "4.0.0",
81+
traits: [])
82+
]
83+
```
84+
85+
Swift package manager determines the traits to enable using the entire graph of dependencies in a project.
86+
The traits enabled for a dependency is the union of all of the traits that for packages that depend upon it.
87+
For example, if you opt out of all traits, but a dependency you use uses the same package with some trait enabled, the package will use the depdendency with the requested traits enabled.
88+
89+
> Note: By disabling any default traits, you may be removing available APIs from the dependency you use.
90+
91+
To learn how to provide packages with traits, see <doc:PackageTraits>.
5592

5693
### Local Dependencies
5794

@@ -77,6 +114,7 @@ For more information on creating a binary target, see [Creating a multiplatform
77114
## Topics
78115

79116
- <doc:ResolvingPackageVersions>
117+
- <doc:PackageTraits>
80118
- <doc:ResolvingDependencyFailures>
81119
- <doc:AddingSystemLibraryDependency>
82120
- <doc:ExampleSystemLibraryPkgConfig>

0 commit comments

Comments
 (0)