The difference between 11.5 and 12.0 is that we amended the diagnostic to also detect duplicated linkage of package targets. In 11.5, we were only looking at package products.
We've been fighting with the tools (Xcode) over the last 10+ years with all kinds of workarounds, because although these are 2 different concepts (dependency and linking), they really want hard to make it a single concept. Dynamic libs have further masked this problem, but they are otherwise not optimal (load time + typically not stripped to just the symbols needed).
This (basic, common, useful) example, that Xcode targets are unable to implement, shows it:
I think SPM wants to allow that, but there remains friction on Xcode side. We sure hope to move the 5.3 (that now support resources) and remove many our "stub" workaround targets. + there is a lot less state in SPM targets than in Xcode's, which means easier maintenance.
I think setting DISABLE_DIAMOND_PROBLEM_DIAGNOSTIC may reveal the root cause:
/warning:1:1: file: /Users/neonacho1/Library/Developer/Xcode/DerivedData/W1-drxqtaioopukohfdphknquwsadbh/Build/Products/Debug-iphonesimulator/PackageFrameworks/A-stub.framework/A-stub is a dynamic library, not added to the static library
So the build system thinks the A-stub dynamic product is being linked, but it just doesn't happen in practice.
Another parallel example is an app being comprised of multiple targets, all of which depend on some library A.
You have this structure:
App
- Dependency A
- Extension A
- Dependency A
- Extension B
- Dependency A
This architecture is incredibly common, more so as additional extension points become available to iOS apps. Dependency A could be an analytics library, Alamofire, or an internal framework that encapsulates business logic in a shared codebase. Whatever it is, SPM and Xcode should be able to handle this gracefully. We should end up with one copy of Dependency A, and all of the binaries should link to it.
yes. We use "stub" dynamic libs because we know dynamic libs are never linked into a static lib, yet correctly setup build oder and module generation.
Again, this is a workaround. I'd rather not have such stub libs at all, and just declare depends_on and link_against relationships in Xcode. The former is not possible across targets in distinct projects in an Xcode workspace, only the latter is, which is why we need these stubs in the first place.
Hopefully SPM is smarter here, and we can progressively replace Xcode lib targets with SPM, which will do the right thing.
I'm struggling with this now. Not having previews has stalled my progress. For this particular issue the DISABLE_DIAMOND_PROBLEM_DIAGNOSTIC=YES work-around hasn't worked for me.
We have a single SPM package in our Xcode project; I'll refer to it as the "root". That root package depends on a number of other SPM packages that specify no linking; neither dynamic nor static.
Wether we mark the single root package as "static" or "dynamic" we receive the error about duplicated code when attempting to use previews. DISABLE_DIAMOND_PROBLEM_DIAGNOSTIC=YES does nothing.
You must fix this ASAP. As it stands SPM is useless because it disables the most valuable feature of Xcode.
I think this thread is starting to get a little confusing for everyone, since we are really discussing several different problems here, which just happen to have the same outcome. To summarise:
There were issues with just the diagnostic which have mostly been fixed at this point, except for the problem that @rsebbe is describing.
There is the general problem of actual diamond-shaped linkage in projects, for which currently the only solution is manually changing your project as a workaround. We aware that this is an issue for many people and are investigating a solution.
There is an entirely separate issue which happens only for Xcode previews which is related to all package products being built dynamically in Xcode 12 to enable previews. It is also something we're actively investigating. There is no workaround for this, since users do not have control over how builds for preview are being done.
The DISABLE_DIAMOND_PROBLEM_DIAGNOSTIC setting only helps in the first case, because there isn't a real problem being flagged. In all other cases, it won't actually help because the diamond-shaped linkage is real.
@NeoNacho@Aciid We have complex project which has multiple sub projects inside workspace, where each target depends internally, but this modularization works fine with Cocoapods but not with SPM(Xcode 12/ swift 5.3), any idea when this problem would be solved?
If the issue happens with a package target, the solution is unfortunately quite complicated, since packages don't give control over the type of targets, they are always static. One solution is creating a framework in Xcode which bundles up the products in question to avoid having to link them twice. Another solution is to restructure the package in question so that the given target can become a product, but this will require breaking it out into its own package.
As said before, we aware that this is an issue for many people and are investigating a solution, especially because the workarounds aren't particularly easy to deploy.
Are there any news on this Topic? I think Swift Package Manager could be awesome but without being able to add a Dependency to multiple Frameworks I can't use it for my projects.
We are still running into this problem today in Xcode 12.3.
We have a Swift Package that declares two dynamic library products:
Fooable
Foo
Foo depends on Fooable.
Some frameworks in our app just depend on Fooable, and this works just fine.
However when we made the app itself link to both Fooable and Foo, now compile breaks with:
"Swift package target 'Fooable' is linked as a static library by 'App' and 'Foo'. This will result in duplication of library code.
Why is Xcode statically linking to a dynamic library target...? What is the fix?
I've found two workarounds so far:
If I only link the app to Foo then, the error goes away.
If I turn on "DISABLE_DIAMOND_PROBLEM_DIAGNOSTIC" then the error goes away.
But I would like to understand first of all, why this problem is happening in the first place? Considering that the Swift package itself declares both of its products as dynamic libraries, why would Xcode try to statically link anything? Is there a way to prevent it from statically linking these, and if so, how? If not, why not?
@NeoNacho thanks for chiming in here. Looking forward to a desined solution.
Another solution is to restructure the package in question so that the given target can become a product, but this will require breaking it out into its own package.
Would it be possible to expand on this (or point me/us to documentation)? What is the relationship between products and targets and how would a target become a product?