[Proposal] Linux specific Package.swift file

Hello everyone,

Currently, we use Package.swift manifest file when defining our packages.
Within the manifest file you define your targets, dependencies, excluded
folders etc. This works fairly well while you’re using frameworks that
exist on all supported platforms (ex. Foundation).

The main problem starts if you want to use code that exists only on macOS
platform, for example, if you want to use Objective C runtime calls or
UIKit. Then, you need to use bunch of #if os(Linux) to define what’s
available on Linux and what’s available on macOS. While this approach can
be non problematic for simple projects, it can introduce unnecessary
complexity if you have a large target and dependency graph.

One way people tackle this problem is writing something like this:

#if os(Linux)
let macOnlyTargets =
#else
let macOnlyTargets = [
    .Target(name: "SomeMacOSTarget")
]
#end

This structure looks even worse if you need to define more complex
behaviors. For example, look at the RxSwift Package.swift
<https://github.com/ReactiveX/RxSwift/blob/master/Package.swift&gt; file. In
my case, I try to write #if os(Linux) as little as possible which leads me
to writing my packages like:

#if os(Linux)
    // Define full Linux package
    let package = Package(...)
#else
    // Define full macOS package
    let package = Package(..)
#end

Proposal

I propose that we support using different file for writing Linux package
manifests. This file could be named:

   - PackageLinux.swift
   - Package.Linux.swift
   - Package.linux.swift

Inside this file you would be able to define your package only for Linux in
the same way you’re defining one in regular Package.swift. The defined
behaviors of building a package would be:

   1. If building on Linux and PackageLinux.swift is present, use that file
   when building the package.
   2. If building on Linux and PackageLinux.swift is not present, use
   regular Package.swift manifest.
   3. If building on macOS always use Package.swift manifest.

Possible problems

This behavior would only introduce problems when SPM gains support for new
platforms, but then again, you would need to use new #if os(somethingNew)
checks.
Compatibility with current packages

This would be only a additive feature for Swift Package Manager and
backwards compatibility will be maintained.

Hi Said,

Since `Package.targets` is a mutable public property,
https://github.com/apple/swift-package-manager/blob/master/Sources/PackageDescription/Package.swift#L60-L67
you can freely mutate it later, as documented in
https://github.com/apple/swift-package-manager/blob/master/Documentation/Reference.md#customizing-builds

···

2016-11-22 4:21 GMT+09:00 Said Sikira via swift-evolution < swift-evolution@swift.org>:

Hello everyone,

Currently, we use Package.swift manifest file when defining our packages.
Within the manifest file you define your targets, dependencies, excluded
folders etc. This works fairly well while you’re using frameworks that
exist on all supported platforms (ex. Foundation).

The main problem starts if you want to use code that exists only on macOS
platform, for example, if you want to use Objective C runtime calls or
UIKit. Then, you need to use bunch of if os(Linux) to define what’s
available on Linux and what’s available on macOS. While this approach can
be non problematic for simple projects, it can introduce unnecessary
complexity if you have a large target and dependency graph.

One way people tackle this problem is writing something like this:

if os(Linux)
let macOnlyTargets =
#else
let macOnlyTargets = [
    .Target(name: "SomeMacOSTarget")
]
#end

This structure looks even worse if you need to define more complex
behaviors. For example, look at the RxSwift Package.swift
<https://github.com/ReactiveX/RxSwift/blob/master/Package.swift&gt; file. In
my case, I try to write if os(Linux) as little as possible which leads
me to writing my packages like:

if os(Linux)
    // Define full Linux package
    let package = Package(...)
#else
    // Define full macOS package
    let package = Package(..)
#end

Proposal

I propose that we support using different file for writing Linux package
manifests. This file could be named:

   - PackageLinux.swift
   - Package.Linux.swift
   - Package.linux.swift

Inside this file you would be able to define your package only for Linux
in the same way you’re defining one in regular Package.swift. The defined
behaviors of building a package would be:

   1. If building on Linux and PackageLinux.swift is present, use that
   file when building the package.
   2. If building on Linux and PackageLinux.swift is not present, use
   regular Package.swift manifest.
   3. If building on macOS always use Package.swift manifest.

Possible problems

This behavior would only introduce problems when SPM gains support for new
platforms, but then again, you would need to use new if os(somethingNew)
checks.
Compatibility with current packages

This would be only a additive feature for Swift Package Manager and
backwards compatibility will be maintained.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Hi Said,

Since `Package.targets` is a mutable public property,
https://github.com/apple/swift-package-manager/blob/master/Sources/PackageDescription/Package.swift#L60-L67
you can freely mutate it later, as documented in
https://github.com/apple/swift-package-manager/blob/master/Documentation/Reference.md#customizing-builds

Right. If they were immutable, it seems that another (more general) solution to this would be to relax the restrictions around if checks, enabling them to apply to elements in lists. That would allow you to write:

let macOnlyTargets = [
if !os(Linux)
    .Target(name: "SomeMacOSTarget")
#end
]

-Chris

···

On Nov 22, 2016, at 3:28 AM, rintaro ishizaki via swift-users <swift-users@swift.org> wrote:

2016-11-22 4:21 GMT+09:00 Said Sikira via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:
Hello everyone,

Currently, we use Package.swift manifest file when defining our packages. Within the manifest file you define your targets, dependencies, excluded folders etc. This works fairly well while you’re using frameworks that exist on all supported platforms (ex. Foundation).

The main problem starts if you want to use code that exists only on macOS platform, for example, if you want to use Objective C runtime calls or UIKit. Then, you need to use bunch of if os(Linux) to define what’s available on Linux and what’s available on macOS. While this approach can be non problematic for simple projects, it can introduce unnecessary complexity if you have a large target and dependency graph.

One way people tackle this problem is writing something like this:

if os(Linux)
let macOnlyTargets =
#else
let macOnlyTargets = [
    .Target(name: "SomeMacOSTarget")
]
#end
This structure looks even worse if you need to define more complex behaviors. For example, look at the RxSwift Package.swift <https://github.com/ReactiveX/RxSwift/blob/master/Package.swift&gt; file. In my case, I try to write if os(Linux) as little as possible which leads me to writing my packages like:

if os(Linux)
    // Define full Linux package
    let package = Package(...)
#else
    // Define full macOS package
    let package = Package(..)
#end
Proposal

I propose that we support using different file for writing Linux package manifests. This file could be named:

PackageLinux.swift
Package.Linux.swift
Package.linux.swift
Inside this file you would be able to define your package only for Linux in the same way you’re defining one in regular Package.swift. The defined behaviors of building a package would be:

If building on Linux and PackageLinux.swift is present, use that file when building the package.
If building on Linux and PackageLinux.swift is not present, use regular Package.swift manifest.
If building on macOS always use Package.swift manifest.
Possible problems

This behavior would only introduce problems when SPM gains support for new platforms, but then again, you would need to use new if os(somethingNew) checks.

Compatibility with current packages

This would be only a additive feature for Swift Package Manager and backwards compatibility will be maintained.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users