How does #if canImport(...) determine what can be imported?

I have a package I have implemented which is desktop only, and I want to depend on it conditionally in a package which serves both iOS and MacOS.

Ideally, in the client package, I would like to be able to conditionally import like so:

#if canImport(DesktopOnlyPackage)
import DesktopOnlyPackage
#endif

How can I define that DesktopOnlyPackage will fail the canImport test on iOS?

It seems like this would be configured through the platforms argument in the package description, but this is a bit confusion, because it seems the platforms doesn't actually define which platforms the package can be compiled to. I.e. there is actually no way include Linux in the `platforms field.

Quoting @NeoNacho (How to exclude a local package from an Xcode target? - #5 by NeoNacho):

The way canImport works is if the module exists in your search paths, it'll be true. Typically when using Xcode or SwiftPM, there's just one shared directory for any modules being built, so whether a dependency has been declared won't affect whether canImport will return true. Generally speaking, the compiler doesn't know at all about your declared dependencies from the package manifest today.

Yes, platforms defines the minimum deployment target for the listed platforms. Non-mentioned platforms are implicitly included by default (with SwiftPM's default min deployment target, if the concept makes sense for the platform).

As far as I know, there is no way to specify an unsupported platform in a SwiftPM manifest.

1 Like

So then when does canImport actually return false? I.e. what is the deciding factor for why canImport(UIKit) will be true for iOS and false for macOS?

The UIKit.framework is not found in the search path when building against the the macOS sysroot.

1 Like