I'm trying to conditionally add code into a SPM target (A) only when that's a dependency of another target (B) that imports another dependency (C).
in target A
target B imports A and C.
I thought canImport would work for this but it doesn't seem to behave as I expect, at least from Xcode. Sometimes the code is compiled when compiling the schema for A, even tho C is not imported at all. Other times compiling B doesn't work, even tho it imports both other targets.
I don't think canImport works for this, since it is based on whether or not there happens to be a module C in the search path. If you don't explicitly depend on it, that will not be deterministic as C can be build in parallel or even after A. It can also be present from previous builds if you are building incrementally.
Oh that seems to be what I was looking for. In my mind the can import technique makes more sense so you don’t have to make more packages but maybe it can’t work. Anyway I will look into that other thread.
There’s a few issues here that I feel are worth discussing, as the status quo runs straight into them.
A package should be able to take advantage of an optional package if it already exists. Despite being optional, it would need to have version restrictions to avoid unpredictably breaking. In the event of a version that doesn’t match the optional dependency, it would be best for the optional functionality to be disabled rather than failing outright.
A package may want a dependency purely to use optional functionality in another package (that is, without directly using anything in the optional dependency). It may make sense, therefore, to instead specify that the optional functionality is required. This could be accomplished by assigning optional dependencies to a “flag” that can be passed when depending on a product. Using a separate product would be ideal, but prevents internal declarations from being used.
A package may need at least one of a set of “optional” dependencies. Swift Package Manager could implement this deterministically by choosing the first compatible dependency in the list if none of them already exist (most notably when it is the root package).
A package may have mutually-exclusive optional dependencies that produce the same interface: for instance, the same protocol implementation may be provided using different packages, such that having multiple would cause compilation to fail. This could be resolved deterministically by choosing the first present dependency in the list, similar to #3.