10

To exclude entire sections of a file, I can use macros to target platforms such as #if os(iOS) || os(watchOS).

Is there a way to do this in Package.swift, or another way to target a few files for specific platforms in Swift Package Manager?

TruMan1
  • 33,665
  • 59
  • 184
  • 335

1 Answers1

17

Is there a way to do this in Package.swift ... ?

Swifty stuff also works in Package.swift since the package declaration file is itself a .swift file.

Here are some examples which use Swift 5.3 Package Manager Conditional Target Dependencies SE-0273 condition and when.

// swift-tools-version:5.3
import PackageDescription

// ...
    targets: [
        .target(
            name: "BKSecurity",
            dependencies: [
                .product(name: "Crypto", condition: .when(platforms: [.linux])),
                "BKFoundation"
        ]),
// swift-tools-version:5.3
import PackageDescription

// ...
    targets: [
      .target(
        name: "CombineShim",
        dependencies: [
          .product(name: "OpenCombine", 
                   package: "OpenCombine",
                   condition: .when(platforms: [.wasi, .linux])
        )]
      ),
      .target(
        name: "TokamakShim",
        dependencies: [
          .target(name: "TokamakDOM", condition: .when(platforms: [.wasi])),
          "SomeCommonDependency"
        ]
      ),
// swift-tools-version:5.3
import PackageDescription

let supportsCoreAudio: BuildSettingCondition = 
        .when(platforms: [.iOS, .macOS, .tvOS, .watchOS])
let supportsALSA: BuildSettingCondition = 
        .when(platforms: [.linux])

let package = Package(
    name: "portaudio",
// ...
  targets: [
    .target(
      name: "libportaudio",
      dependencies: [],
      cSettings: [
        .define("PA_USE_COREAUDIO", supportsCoreAudio),
        .define("PA_USE_ALSA", supportsALSA)
      ],
      linkerSettings: [
        .linkedLibrary("asound", supportsALSA),
        .linkedFramework("CoreAudio", supportsCoreAudio),
        .linkedFramework("CoreServices", supportsCoreAudio),
        .linkedFramework("CoreFoundation", supportsCoreAudio),
        .linkedFramework("AudioUnit", supportsCoreAudio),
        .linkedFramework("AudioToolbox", supportsCoreAudio)
    ]),
  ]
//...
)

Note that #if os(…) can be used in Package.swift. However, Package.swift is evaluated, built and executed in the context of the build platform. So, #if os(…) is useful in the context when the target platform is the same as the build platform e.g. macOS, Linux or Windows.

Package.swift

import PackageDescription

let package = Package(
    // ...
    targets: {
        var targets: [Target] = [
            .testTarget(
                name: "QuickTests",
                dependencies: [ "Quick", "Nimble" ],
                exclude: ["SomeFile.ext"]
            ),
        ]
#if os(macOS)
        // macOS build platform
        targets.append(contentsOf: [
            .target(name: "QuickSpecBase", dependencies: []),
            .target(name: "Quick", dependencies: [ "QuickSpecBase" ]),
        ])
#else
        // not macOS build platform, e.g. linux
        targets.append(contentsOf: [
            .target(name: "Quick", dependencies: []),
        ])
#endif
        return targets
    }(),
)

See Also

marc-medley
  • 8,931
  • 5
  • 60
  • 66
  • I tried the above but it seems it always tries to compile as macOS.. – JoeBayLD Oct 07 '19 at 05:25
  • 3
    The exclude list can be directories, like "QuickTests" – David H Feb 03 '20 at 15:19
  • 1
    I find this works for macOS vs. Linux, but when I try it with iOS, it seems to also include all the macOS stuff. – Steven W. Klassen Aug 26 '20 at 23:47
  • 4
    I'm not entirely positive at the moment, but I suspect that `#if os(macOS)` in `Package.swift` may be referring to the os on which Xcode is running and not on the target os that it is compiling for. But I'm not certain on that point. – Steven W. Klassen Aug 26 '20 at 23:49
  • @StevenW.Klassen ... good observation. And so it is: `Package.swift` is evaluated, built and executed in the context of the build platform. So, `#if os(…)` would only apply to the context where the target platform is the build platform. Updated answer has been posted with SwiftPM 5.3 `condition` examples. – marc-medley Aug 27 '20 at 19:00
  • I can't get this to work. Getting ` missing argument for parameter 'package'` – Sentry.co Jul 29 '21 at 13:40