# Draft Proposal: Platform Deployment Settings

**URL:** <https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903>\
**Category:** Package Manager\
**Created:** [November 12, 2018, 1:33am UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903 "2018-11-12T01:33:57Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Aciid](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aciid/32/429_2.png) [@Aciid](https://forums.swift.org/u/Aciid)\
**Post date:** [November 12, 2018, 1:33am UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903/1 "2018-11-12T01:33:57Z")

</div>

Hey,

Here is a draft proposal for setting minimum deployment target in Swift packages!

Latest draft is always available [here](https://github.com/aciidb0mb3r/swift-evolution/blob/dep-target/proposals/NNNN-package-manager-platform-deployment-settings.md).

* * *

# Package Manager Platform Deployment Settings

## Introduction

This is a proposal for adding support for specifying a per-platform minimum required deployment target in the `Package.swift` manifest file.

## Motivation

Packages should be able to declare the minimum required platform deployment target version. SwiftPM currently uses a hardcoded value for the macOS deployment target. This creates friction for packages which want to use APIs that were introduced after the hardcoded deployment target version.

There are two ways to work around this limitation: 1) using availability checks, or 2) passing the deployment target on the command line while building the package. However, these workarounds are not ideal and the package manager should really provide a proper API for setting the required deployment target version.

Adding support for specifying deployment targets will also allow packages to restrict the platforms that they support. This is useful for packages that are never meant to be cross-platform.

## Proposed solution

We propose to add the following API to `PackageDescription`:

```swift
/// Represents a supported platform.
struct SupportedPlatform {
    static func macOS(_ version: MacOSVersion) -> SupportedPlatform
    static func tvOS(_ version: TVOSVersion) -> SupportedPlatform
    static func iOS(_ version: IOSVersion) -> SupportedPlatform
    static func watchOS(_ version: WatchOSVersion) -> SupportedPlatform
    static let linux: SupportedPlatform

    /// Implicitly support all platforms.
    static let all: SupportedPlatform
}

extension SupportedPlatform {
    struct MacOSVersion {
        /// Create a macOS version from the given string.
        init(_ version: String)
    }

    struct TVOSVersion {
        /// Create a tvOS version from the given string.
        init(_ version: String)
    }

    struct IOSVersion {
        /// Create a iOS version from the given string.
        init(_ version: String)
    }

    struct WatchOSVersion {
        /// Create a watchOS version from the given string.
        init(_ version: String)
    }
}

/// List of known versions.
extension SupportedPlatform.MacOSVersion {
    static let v10_10: MacOSVersion
    static let v10_11: MacOSVersion
    static let v10_12: MacOSVersion
    ...
}

final class Package {

    init(
        name: String,
        platforms: [SupportedPlatform] = [.all],
        ...
    )
}

// Example usage:

let package = Package(
    name: "NIO",
    platforms: [
       .macOS(.v10_13), .iOS(.v12), .all,
    ],
    products: [
        .library(name: "NIO", targets: ["NIO"]),
    ],
    targets: [
        .target(name: "NIO"),
    ]
)

```

By default, a package will be assumed to support all platforms using a predefined minimum deployment version. This predefined deployment version will be the oldest deployment target version supported by the installed SDK for a given platform. One exception to this rule is macOS, for which the minimum deployment target version will start from 10.10.

Packages can explicitly choose to declare the minimum deployment target version for some platform by using the above APIs. In such cases, packages should use the `SupportedPlatform.all` property to declare that they want to use the default deployment target version for the platforms that they didn't explicitly specify. If a package wants to support only a limited set of platforms, they should omit the `.all`. This is very similar to Swift's [availability attribute](https://docs.swift.org/swift-book/ReferenceManual/Attributes.html) with the exception that the equivalent of `*` in the proposed APIs, `.all`, is not mandatory.

For example:

- This declaration means that the package should use 10.13 on macOS, 12.0 on iOS and the default deployment target when compiled on other platforms:

```swift
    ...
    platforms: [
       .macOS(.v10_13), .iOS(.v12), .all,
    ],
    ...

```

- This declaration means that the package only supports macOS and iOS and SwiftPM will emit an error if this package is used on any other platform:

```swift
    ...
    platforms: [
       .macOS(.v10_13), .iOS(.v12),
    ],
    ...

```

## Detailed design

Changes in deployment target versions should be considered as a major breaking change for the purposes of semantic versioning since the dependees of a library package can break when a library makes such a change.

SwiftPM will emit an error if a dependency is not compatible with the top-level package's deployment version, i.e., the deployment target of dependencies must be lower than or equal to top-level package's deployment target version for a particular platform.

Each package will be compiled with the deployment target specified by it. In theory, SwiftPM can use the top-level package's deployment version to compile the entire package graph since the deployment target versions of dependencies are guaranteed to be compatible. This might even produce more efficient compilation output but it also means that the users might start seeing a lot of warnings due to use of a higher version.

Each platform version type has an initializer that can be used to construct versions that are not already provided by PackageDescription APIs. This could be because the new version was recently released or isn't appropriate to be included in the APIs (for e.g. dot versions). The version format for each platform will be documented in the API. Invalid values will be diagnosed and presented as manifest parsing errors.

SwiftPM will emit appropriate errors when an invalid value is provided for supported platforms. For e.g., an empty array, multiple declarations for the same platform, invalid version specification.

The generated Xcode project command will set the deployment target version for each platform.

### Future directions

The Swift compiler supports several platforms like macOS, iOS, Linux, Windows, Android. However, the runtime availability checks currently only work for Apple platforms. It is expected that support for more platforms in the availability APIs will be added gradually as the community and support for Swift compiler grows. We think that the package manager can use a similar direction for declaring the supported platforms. We can start by allowing packages to declare support for Apple platforms with version specifications and a generic support for Linux as proposed by the above APIs. Depending on the need in the community, these APIs can be evolved over time by adding support for declaring the minimum deployment version for other platforms that Swift supports. For e.g., the API can be enhanced to declare the minimum required version for Windows and the API level for Android.

This proposal doesn't handle these two problems:

1. **Platform-specific targets or products** : Consider that a package supports multiple platforms but has a product that should be only built for Linux. There is no way to express this intent and the build system may end up trying to build such targets on all platforms. A simple workaround is to use `#if` to conditionalize the source code of the target. Another use case comes up when you want to keep deployment target of a certain target lower than other targets in a package. A workaround is factoring out the target into its own package. A proper solution to this problem will be explored in a separate proposal, which should provide target-level settings.
2. **Platform-specific package dependencies** : Similar to the above issue, a package may want to use a certain dependency only when building for a specific platform. It is currently not possible to declare such a dependency without using `#if os` checks in the manifest file, which doesn't interact nicely with other features like `Package.resolved` and the cross-compilation support. This can be solved by providing APIs to declare platform-specific package dependencies in the manifest file. This will also be explored in a separate proposal.

## Impact on existing packages

Existing packages will not be impacted as the behavior described in this proposal is compatible with SwiftPM's current behavior, i.e., a package is assumed to support all platforms and SwiftPM picks a default deployment target version for the macOS platform.

The new APIs will be guarded against the tools version this proposal is implemented in. Packages that want to use this feature will need to update their tools version.

## Alternatives considered

We considered making the supported platform field mandatory. We think that it would provide little value in practice and cause more friction instead. One advantage would be that SwiftPM could use that information to produce error messages when a package tries to use a dependency which is not tested on some platform. We think that is not really a big enough issue. Since Swift is cross-platform, Swift packages should generally work on all platforms that Swift supports. However, there are platform-specific packages that are only meant for certain platforms and the proposed API does provide an option to declare that intent.

We considered taking the deployment target version into the dependency resolution process to automatically find a compatible version with the top-level package. This too doesn't provide enough value in practice. Library packages generally tend to stick with a deployment target to avoid breaking their dependees. When they do bump the version, it is generally a well-thought decision and may require a semver upgrade anyway due to updates in the API.

---

<div class="post-metadata">

**Author:** ![Braden\_Scothern](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/braden_scothern/32/1580_2.png) [@Braden\_Scothern](https://forums.swift.org/u/Braden_Scothern)\
**Post date:** [November 12, 2018, 3:19am UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903/2 "2018-11-12T03:19:11Z")

</div>

I like it. With this will the package manager start to fully support non macOS and Linux targets then? If so is that going to start with only be through generated xcode projects?

---

<div class="post-metadata">

**Author:** ![kiel](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kiel/32/1392_2.png) [@kiel](https://forums.swift.org/u/kiel)\
**Post date:** [November 12, 2018, 3:31am UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903/3 "2018-11-12T03:31:42Z")

</div>

As Swift code, could package descriptions specify custom minimum version matching logic? This logic seems to be looking to satisfy the predicate `base SDK >= minimum SDK`. Could/should the API provide users a hook to custom matching logic? For example, supporting particular Linux distributions the package description API doesn't know about.

---

<div class="post-metadata">

**Author:** ![SDGGiesbrecht](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/sdggiesbrecht/32/4768_2.png) [@SDGGiesbrecht](https://forums.swift.org/u/SDGGiesbrecht)\
**Post date:** [November 12, 2018, 6:33am UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903/4 "2018-11-12T06:33:20Z")

</div>

+1

---

<div class="post-metadata">

**Author:** ![lukasa](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lukasa/32/1232_2.png) [@lukasa](https://forums.swift.org/u/lukasa)\
**Post date:** [November 12, 2018, 10:52am UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903/5 "2018-11-12T10:52:19Z")

</div>

Thanks for this proposal Ankit. This will be enormously useful for `swift-nio-transport-services`, which has a bunch of minimum SDK requirements not currently handled by Swift Package Manager.

I note your explicit decision to push out platform specific targets, products, and dependencies. I'd love to see those things addressed too, but I'm more than happy for you to take these things one at a time! With that noted, I'm a strong +1: this is a great improvement, and I'm very excited to see it.

---

<div class="post-metadata">

**Author:** ![johannesweiss](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/johannesweiss/32/38183_2.png) [@johannesweiss](https://forums.swift.org/u/johannesweiss)\
**Post date:** [November 12, 2018, 1:01pm UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903/6 "2018-11-12T13:01:17Z")

</div>

Seconded, this is a great improvement and will really help to solve real issues.

---

<div class="post-metadata">

**Author:** ![Aciid](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aciid/32/429_2.png) [@Aciid](https://forums.swift.org/u/Aciid)\
**Post date:** [November 12, 2018, 3:54pm UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903/7 "2018-11-12T15:54:47Z")

</div>

> [@Braden\_Scothern](#):
>
> I like it. With this will the package manager start to fully support non macOS and Linux targets then? If so is that going to start with only be through generated xcode projects?

The proposal aims to add APIs for platforms that are officially supported by the Swift compiler. The generated project will use the deployment target information provided for the non-macOS targets but that's not an "official" support. Generated projects are meant to provide temporary development experience inside Xcode (similar to CMake).

---

<div class="post-metadata">

**Author:** ![Aciid](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aciid/32/429_2.png) [@Aciid](https://forums.swift.org/u/Aciid)\
**Post date:** [November 12, 2018, 3:56pm UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903/8 "2018-11-12T15:56:38Z")

</div>

> [@kiel](#):
>
> As Swift code, could package descriptions specify custom minimum version matching logic? This logic seems to be looking to satisfy the predicate `base SDK >= minimum SDK` . Could/should the API provide users a hook to custom matching logic? For example, supporting particular Linux distributions the package description API doesn't know about.

I think that's an open question that should be answered as the package manager grows. If there is such a need in the community, we can explore solutions and extend the above APIs in a future proposal.

---

<div class="post-metadata">

**Author:** ![Aciid](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aciid/32/429_2.png) [@Aciid](https://forums.swift.org/u/Aciid)\
**Post date:** [November 12, 2018, 3:59pm UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903/9 "2018-11-12T15:59:14Z")

</div>

> [@lukasa](#):
>
> Thanks for this proposal Ankit. This will be enormously useful for `swift-nio-transport-services` , which has a bunch of minimum SDK requirements not currently handled by Swift Package Manager.

That's great to hear!

> [@lukasa](#):
>
> I note your explicit decision to push out platform specific targets, products, and dependencies. I'd love to see those things addressed too, but I'm more than happy for you to take these things one at a time!

Yeah, I think those features come with their own set of complexity and it is important to break down the problem instead of trying to solve everything at once.

> [@lukasa](#):
>
> With that noted, I'm a strong +1: this is a great improvement, and I'm very excited to see it.

Awesome!

---

<div class="post-metadata">

**Author:** ![thomasvl](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/thomasvl/32/3033_2.png) [@thomasvl](https://forums.swift.org/u/thomasvl)\
**Post date:** [November 13, 2018, 4:01pm UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903/10 "2018-11-13T16:01:09Z")

</div>

The proposal only includes capturing this information for the Package as a whole. Has any thought been given to what it will take to eventually support this information on a per target basis?

If SwiftPM is eventually going to grow to support building macOS/iOS/etc. applications, then the reality is since those can be composed of Applications, Frameworks, and Extensions. As the platforms have evolved, it isn't uncommon that that the core app supports say iOS 9.0+, but some extension is iOS 10.0+ because that's what the extension was introduced. So the App target would have one min, and an extension or two could have a higher min, and if there are frameworks common to the app and extensions or just some extensions, those framework targets could have another minimum to support a collection of the other targets.

From a quick reread, I think `SupportedPlatform` likely would still work to help capture this and it would just be the addition of `platforms` at the `targets` or `products` level to capture this data. The one catch might be if the package includes other library targets as dependents, they might have to _inherit_ their data from the things that depend on them, but that could lead two things depending on it with different explicit platforms, and the "lowest" min OS for each support platform would have to take effect.

Anyway, while not in the current proposal, just wanted to float the concern incase these additions should get tweaked in any way to eventually support this.

---

<div class="post-metadata">

**Author:** ![Aciid](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aciid/32/429_2.png) [@Aciid](https://forums.swift.org/u/Aciid)\
**Post date:** [November 13, 2018, 4:06pm UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903/11 "2018-11-13T16:06:59Z")

</div>

Yes, this is mentioned in the future directions.

---

<div class="post-metadata">

**Author:** ![Aciid](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aciid/32/429_2.png) [@Aciid](https://forums.swift.org/u/Aciid)\
**Post date:** [November 16, 2018, 3:06am UTC](https://forums.swift.org/t/draft-proposal-platform-deployment-settings/17903/12 "2018-11-16T03:06:09Z")

</div>

Note that this is under active review right now: [SE-0236: Package Manager Platform Deployment Settings - #7 by NeoNacho](https://forums.swift.org/t/se-0236-package-manager-platform-deployment-settings/17992/7)
