We’ve got a package that contains a bunch of helper code for our iOS app. We only have an iOS app that’s consuming this project, with no macOS, tvOS, watchOS projects, or projects on other platforms that Swift supports. This package also contains a macro. What’s the best way to set up this package such that running tests does The Right Thing™?
The problem that I run into is that, as best as I can tell, when trying to run tests for a package, the build system compiles the whole package, even if a target doesn’t make sense to run on a particular platform. So, for example, if I try to run the tests targeting an iOS simulator (so I can test the iOS code in the package), the build fails because the build system tries to compile the macro for iOS, which isn’t a thing that’s supported. In a similar vein, if I try to run the tests targeting macOS (so I can test the macro in the package), the build also fails because the build system can’t find the iOS-specific API and frameworks like UIKit as it tries to compile the target with the iOS code. This seems to be the case regardless of if I try to run tests on the command line when invoking swift test, or trying to run tests in Xcode.
As far as I know, there’s no way to tell the build system that a target is meant for a particular platform. That is, I can’t specify that the target that contains iOS code is only meant for iOS and thus shouldn’t be compiled when targeting macOS. In the same way, I can’t specify that the macro is only meant for a development host machine, so it shouldn’t be compiled when targeting iOS (though that’s something I might expect the build system to know automatically?)
I can’t use the platforms parameter of the package manifest, since that only sets the minimum deployment targets for the platforms that Swift as a whole supports; that doesn’t restrict what platforms my package is allowed to be used on. I believe there’s a way to limit which tests are executed when I invoke the build from the command line, but a) I don’t think that affects what the build system tries to compile, and b) that doesn’t help me when trying to run tests within Xcode.
The best solution I’ve been able to come up with is starting to wrap my code in a bunch of canImport checks to see if UIKit or SwiftSyntax or other modules can be imported. I don’t really like this approach, though, because it feels like a hack in some respects. The macro can’t ever run on iOS, so it seems like not compiling that should be taken care of by the build system for me, and it feels odd to use a check for canImport(UIKit) in my iOS code module because we only have an iOS app and nothing else, so that check more or less always evaluates to true for us at compile time (with the exception of running the macro’s tests). Has anyone got a better solution to this problem?