Search code examples
swiftxcode11swift-package-manager

Excluding files in Swift Packages


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?


Solution

  • 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