Package Manager Conditional Target Dependencies

:partying_face: Yeah, so after you do that, "it just works".

Thanks a lot :slight_smile:

1 Like

Cool.

Iā€™ve recently been helping a developer whoā€™s shipping a custom toolchain (s. 723651342), so Iā€™ve spent a bunch of time looking into this. The issue here is that Xcode toolchains kinda look like a bundle but arenā€™t really, and that causes them to slip through a crack between Gatekeeper and the notary service. This is something that Apple needs to investigate (I donā€™t yet have a bug number because I only just asked the developer to file one).

Share and Enjoy

Quinn ā€œThe Eskimo!ā€ @ DTS @ Apple

1 Like

Just to clarify ā€” this will not allow me to declare an entire dependency only for debug, correct?

(I'm +1 either way, as I think it'll be useful)

Correct. You can't directly declare a dependency only for debug: it will just indirectly only be for debug if it is only depended on by targets with a conditional configuration of Debug.

Which only means nothing from it will be built when you do swift build --configuration debug.

Such a dependency will still be fetched and still participate in the resolution of the package graph; all its own version constraints will still be relevant. This is important so that Package.resolved plays nice, and so you cannot accidentally end up with a package graph that works in debug but is unsolvable in release.

2 Likes

I'm using this new SE-0273 feature in Xcode 12 beta 6-- thanks for it! It really is important in a package I'm using between an iOS client and a Swift-based server. The package uses Kitura on the server, but I don't want that built on the client.

I have a syntax question-- From what I've seen of the documentation on this feature, we should use something like:

.product(name: "BluetoothLinux", condition: .when(platforms: [.linux])),

However, Xcode 12 beta 6 gives a syntax error unless I add a package parameter. E.g.,

.product(name: "Kitura", package: "Kitura", condition: .when(platforms: [.linux])),

Is this change documented somewhere?

Thanks!

The error message is due to SEā€0262. As an unrelated change that hadnā€™t been implemented yet when SEā€0273 was drafted, the examples in the text did not take it into account.

Thanks! Is there some comprehensive documentation, or is this waiting on the actual Swift 5.3 release?

The comprehensive API documentation of the latest release can be found here. It will be updated when 5.3 is officially released.

Just found this, nice improvement to SPM :+1:

One question though, it's not 100% clear to me if this will resolve the need for the hack I had to do here:

The problem I had, specifically, was that when running CI on Linux I had no way to ensure that swift test would only run the tests for ComposableArchitecture, and not the other two libraries which are specific to Apple platforms. Even when using --filter to restrict the tests, the other two Apple specific libraries would still attempt to get built and fail.

I guess that only having .linux in the platform conditions for ComposableArchitecture would work. When I switch to 5.3 tooling I will give it a try.

No, this does not prevent products from existing for a particular platform. It only prevents them from being included in the dependency graph by a higherā€level target. swift build will still attempt to build all the targets in the main package.

Hence it is only really useful across package boundaries, where unused dependencies are ignored. What it allows is for anyone who uses your ComposableArchitecture product as a dependency to declare it as a macOSā€only dependency in their manifest, and thus avoid having to duplicate your hack at each level.

I have oft wished for the type of platform exclusion you are trying to accomplish. But until then, I have found the best way for now is to wrap each source file in #if. That way the whole package can safely be built no matter how convoluted the crossā€compilation. (Attempting to crossā€compile from macOS to Linux will fail with your hack, because the manifest will compile for macOS, but the target will attempt to compile for Linux.)

The package declares 3 libraries as products, only one of which is ever going to be compatible with Linux. That library has the necessary #if os(Linux) or #if canImport(Combine) guards so it will compile properly for all platforms.

My problem is really just for running CI for Linux. I wanted a way to tell SwiftPM: just run ComposableArchitecture tests, and ignore any other products or targets in the package. Unfortunately swift test doesn't have the --target option that swift build does. Even using swift test --filter to restrict tests to a specific test target doesn't help, as SwiftPM will still try to build all the non-test targets first, even the ones that the filtered tests don't depend on.

For the other two libraries, I literally meant enclosing every single file entirely in #if so that they successfully build as empty libraries:

#if os(macOS)
  // All library content here.
#endif

Otherwise your hack is still necessary, and there is no proposal in the evolution process yet that would make it otherwise. If you want to improve your hack to also support crossā€compilation, see this post: