-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Environment-Dependent Shared Libraries #2676
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
tayloraswift
wants to merge
8
commits into
swiftlang:main
Choose a base branch
from
tayloraswift:master
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 3 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
c107545
Replaceable Library Plugins
tayloraswift f3a13de
links to example projects
tayloraswift 686a8c9
link to Forums thread
tayloraswift b02a4ac
unassigned number
tayloraswift f300472
replace term RLP with EDSL
tayloraswift 45b3f89
add documentation link
tayloraswift 47d96fc
update link
tayloraswift 02e9dfd
Merge branch 'swiftlang:main' into master
tayloraswift File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
# Replaceable Library Plugins | ||
|
||
* Proposal: [SE-0461](0641-replaceable-library-plugins.md) | ||
* Authors: [tayloraswift](https://github.com/tayloraswift) | ||
* Review Manager: TBD | ||
* Implementation: [swiftlang/swift-package-manager#8249](https://github.com/swiftlang/swift-package-manager/pull/8249) | ||
* Bugs: [SR-5714](https://github.com/swiftlang/swift-package-manager/issues/5714) | ||
|
||
## Introduction | ||
|
||
SwiftPM currently has no support for non-system binary library dependencies on Linux. This proposal adds support for **Replaceable Library Plugins**, which are a type of dynamic library that is shared across a fleet of machines and can be upgraded without recompiling and redeploying all applications running on those machines. We will distribute Replaceable Library Plugins through the existing `.artifactbundle` format. | ||
|
||
Swift-evolution thread: [Discussion thread](https://forums.swift.org/t/pitch-replaceable-library-plugins/77605) | ||
|
||
Example Producer: [swift-rlp-example](https://github.com/tayloraswift/swift-rlp-example) | ||
|
||
Example Consumer: [swift-rlp-example-client](https://github.com/tayloraswift/swift-rlp-example-client) | ||
|
||
## Motivation | ||
|
||
Many of us in the Server World have a Big App with a small component that changes very rapidly, much more rapidly than the rest of the App. This component might be something like a filter, or an algorithm, or a plugin that is being constantly tuned. | ||
|
||
We could, for argument’s sake, try and turn this component into data that can be consumed by the Big App, which would probably involve designing a bytecode and an interpreter, and maybe even a whole interpreted domain-specific programming language. But that is very hard and we would rather just write this thing in Swift, and let Swift code call Swift code. | ||
|
||
While macOS has Dynamic Library support through XCFrameworks, on Linux we currently have to recompile the Big App from source and redeploy the Big App every time the filter changes, and we don’t want to do that. What we really want instead is to have the Big App link the filter as a Dynamic Library, and redeploy the Dynamic Library as needed. | ||
|
||
|
||
## Proposed solution | ||
|
||
On Linux, there are a lot of obstacles to having fully general support for Dynamic Libraries. Swift is not ABI stable on Linux, and Linux itself is not a single platform but a wide range of similar platforms that provide few binary compatibility guarantees. This means it is pretty much impossible for a public Swift library to vend precompiled binaries that will Just Work for everyone, and we are not going to try to solve that problem in this proposal. | ||
|
||
Instead, we will focus on **Replaceable Library Plugins** (RLPs). We choose this term to emphasize the distinction between our use case and fully general Dynamic Libraries. | ||
|
||
### Organization-Defined Platforms (ODPs) | ||
|
||
Unlike fully general Dynamic Libraries, you would distribute Replaceable Library Plugins strictly for internal consumption within an organization, or to a small set of paying clients. | ||
|
||
The organization that distributes an RLP is responsible for defining what exactly constitutes a “platform” for their purposes. An Organization-Defined Platform (ODP) is not necessarily an operating system or architecture, or even a specific distribution of an operating system. A trivial example of two ODPs might be: | ||
|
||
1. Ubuntu 24.04 with the Swift 6.0.3 runtime installed at `/home/ubuntu/swift` | ||
2. Ubuntu 24.04 with the Swift 6.0.3 runtime installed at `/home/ubuntu/swift-runtime` | ||
|
||
Concepts like Platform Triples are not sufficient to describe an ODP. Even though both ODPs above would probably share the Triple `aarch64-unknown-linux-gnu`, Swift code compiled (without `--static-swift-stdlib`) for one would never be able to run on the other. | ||
|
||
Organizations add and remove ODPs as needed, and trying to define a global registry of all possible ODPs is a non-goal. | ||
|
||
To keep things simple, we identify ODPs by the URL of the Artifact Bundle that contains the RLP. | ||
|
||
### Creating RLPs | ||
|
||
To compile an RLP, you just need to build an ordinary SwiftPM library product with the `-enable-library-evolution` flag. This requires no modifications to SwiftPM. | ||
|
||
You would package an RLP as an `.artifactbundle` just as you would an executable, with the following differences: | ||
|
||
- The `info.json` must have `schemaVersion` set to `1.2` or higher. | ||
- The artifact type must be `library`, a new enum case introduced in this proposal. | ||
- The artifact must have exactly one variant in the `variants` list, and the `supportedTriples` field is forbidden. | ||
- The artifact payload must include the `.swiftinterface` file corresponding to the actual library object. | ||
|
||
Because SwiftPM is not (and cannot be) aware of a particular organization’s ODPs, this enforces the requirement that each ODP must have its own Artifact Bundle. | ||
|
||
The organization that distributes the RLP is responsible for upholding ABI stability guarantees, including the exact Swift compiler and runtime versions needed to safely consume the RLP. | ||
|
||
|
||
### Consuming RLPs | ||
|
||
To consume an RLP, you would add a `binaryTarget` to your `Package.swift` manifest, just as you would for an executable. Because ODPs are identified by the URL of the Artifact Bundle, there are no new fields in the `PackageDescription` API. | ||
|
||
We expect that the logic for selecting the correct RLP for a given ODP would live within the `Package.swift` file, that it would be highly organization-specific, and that it would be manipulated using existing means such as environment variables. | ||
|
||
|
||
### Deploying RLPs | ||
|
||
Deploying RLPs does not involve SwiftPM or Artifact Bundles at all. You would deploy an RLP by copying the latest binaries to the appropriate `@rpath` location on each machine in your fleet. The `@rpath` location is part of the ODP definition, and is not modeled by SwiftPM. | ||
|
||
Some organizations might choose to forgo the `@rpath` mechanism entirely and simply install the RLPs in a system-wide location. | ||
|
||
|
||
## Detailed design | ||
|
||
### Schema extensions | ||
|
||
We will extend the `ArtifactsArchiveMetadata` schema to include a new `library` case in the `ArtifactType` enum. | ||
|
||
```diff | ||
public enum ArtifactType: String, RawRepresentable, Decodable { | ||
case executable | ||
+ case library | ||
case swiftSDK | ||
} | ||
``` | ||
|
||
This also bumps the latest `schemaVersion` to `1.2`. | ||
|
||
|
||
### Artifact Bundle layout | ||
|
||
Below is an example of an `info.json` file for an Artifact Bundle containing a single library called `MyLibrary`. | ||
|
||
```json | ||
{ | ||
"schemaVersion": "1.2", | ||
"artifacts": { | ||
"MyLibrary": { | ||
"type": "library", | ||
"version": "1.0.0", | ||
"variants": [{ "path": "MyLibrary" }] | ||
} | ||
} | ||
} | ||
``` | ||
|
||
The artifact must have exactly one variant in the `variants` list, and the `supportedTriples` field is forbidden. An RLP Artifact Bundle can contain multiple libraries at the top level. | ||
|
||
Below is an example of the layout of an Artifact Bundle containing a single library called `MyLibrary`. Only the `info.json` must appear at the root of the Artifact Bundle; all other files can appear at whatever paths are defined in the `info.json`, as long as they are within the Artifact Bundle. | ||
|
||
```text | ||
📂 example.artifactbundle | ||
📂 MyLibrary | ||
⚙️ libMyLibrary.so | ||
📝 MyLibrary.swiftinterface | ||
📝 info.json | ||
``` | ||
|
||
A macOS Artifact Bundle would contain a `.dylib` instead of a `.so`. RLPs will be supported on macOS, although we expect this will be an exceedingly rare use case. | ||
|
||
|
||
## Security | ||
|
||
RLPs are not intended for public distribution, and are not subject to the same security concerns as public libraries. Organizations that distribute RLPs are responsible for ensuring that the RLPs are safe to consume. | ||
|
||
|
||
## Impact on existing packages | ||
|
||
There will be no impact on existing packages. All Artifact Bundle schema changes are additive. | ||
|
||
|
||
## Alternatives considered | ||
|
||
### Extending Platform Triples to model ODPs | ||
|
||
SwiftPM currently uses Platform Triples to select among artifact variants when consuming executables. This is workable because it is usually feasible to build executables that are portable across the range of platforms encompassed by a single Platform Triple. | ||
|
||
We could extend Platform Triples to model ODPs, but this would privilege a narrow set of predefined deployment architectures, and if you wanted to add a new ODP, you would have to modify SwiftPM to teach it to recognize the new ODP. | ||
|
||
### Supporting multiple variants of an RLP in the same Artifact Bundle | ||
|
||
We could allow an Artifact Bundle to contain multiple variants of an RLP, but we would still need to support a way to identify those variants, which in practice makes SwiftPM aware of ODPs. | ||
|
||
We also don’t see much value in this feature, as you would probably package and upload RLPs using one CI/CD workflow per ODP anyway. Combining artifacts would require some kind of synchronization mechanism to await all pipelines before fetching and merging bundles. | ||
|
||
One benefit of merging bundles would be that it reduces the number of checksums you need to keep track of, but we expect that most organizations will have a very small number of ODPs, with new ODPs continously phasing out old ODPs. | ||
|
||
### Using a different `ArtifactType` name besides `library` | ||
|
||
We intentionally preserved the structure of the `variants` list in the `info.json` file, despite imposing the current restriction of one variant per library, in order to allow this format to be extended in the future to support fully general Dynamic Libraries. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.