Issue with SwiftPM and multiple targets

Hi!

I have a bigger Xcode project that has multiple targets:

  • the main app (MainApp)
  • helper command line tool (HelperTool)

The project also lists multiple package dependencies via SwiftPM and these dependencies have dependencies between themselves.

One of such packages produces a dynamic library MyFramework which is a dependency for both the main app and the HelperTool which has it listed under Build Phases > Dependencies as well as under Link with Frameworks.

This builds just fine, but the issue somes when I want to add another target called AdditionalHelperTool which it has pretty much the same dependencies as HelperTool.

When I add this second target, I start running into issues like the following:

Multiple commands produce '[...]/Build/Products/Debug/Frameworks/MyFramework.framework/Versions/A'

Target 'HelperTool' (project 'MyApp') has copy command from '[...]/Build/Products/Debug/PackageFrameworks/MyFramework.framework' to '[...]/Build/Products/Debug/Frameworks/MyFramework.framework'

Target 'AdditionalHelperTool' (project 'MyApp') has copy command from '[...]/Build/Products/Debug/PackageFrameworks/MyFramework.framework' to '[...]/Build/Products/Debug/Frameworks/MyFramework.framework'`

It seems that Xcode runs the build of both targets separately and it sees a conflict given that both targets have same dependencies that it's trying to built separately.

Has anyone encountered something similar? Can anyone suggest a solution for this?

Thanks for this very interesting issue that I’m sure many people has different ideas to deal with this reference to external projects.

Will be great to see a simple focused project to see how you using it, when dealing with shared dynamic frameworks and multiple non-app targets like command-line tools. The error message "Multiple commands produce..." clearly indicates that two or more targets are trying to copy the same file

In my personal experience, I address this challenge by consistently simplifying my projects to ensure that no project reference is duplicated and can be utilized throughout the entire project. While this approach may not be as straightforward as it appears, simplification has consistently proven to be my preferred solution when constructing projects.

Xcode's build system, by default, tries to ensure that all linked dynamic frameworks are available.

It is possible to reference a manager class once and utilize the accessed project instead of duplicating the framework.

When you have HelperTool and AdditionalHelperTool both linking MyFramework and both having an "Embed Frameworks" or "Copy Files" phase configured to copy MyFramework to Build/Products/Debug/Frameworks/, Xcode sees two distinct commands attempting to write to the identical location, leading to the conflict.

Removes the conflicting copy commands. Xcode will still link MyFramework to your helper tools during compilation, but it won't try to copy the framework into the shared output directory.

If MyFramework is not a system framework (which it likely isn't if it's from a SwiftPM package), your helper tools will need to find it at runtime.

If you absolutely need MyFramework to be copied to a specific shared location by your build process, you can create an aggregate target to handle this copy operation exactly once.

Those are just thoughts before my second cup of coffee without really knowing your requirements, hope other developers can provide their ideas here.

Albert Pascual
  Worldwide Developer Relations.

Thank you for answering!

In the meantime I tried another approach of creating the command line tools via SwiftPM and ran pretty much into the same issue here.

The Package manifest defined two binaries with some dependencies and the build process again complained about multiple commands producing various frameworks.

I fully agree that simplification is the way to go which is why the actual project has about 6 different frameworks into which the functionality is broken down.

It is interesting to note that the error appears for frameworks that link external libraries - in one case it's swift-syntax and swift-system (as one of the libraries defines macros) and the other swift-subprocess.

I wonder if this has any effect on this.

When you have HelperTool and AdditionalHelperTool both linking MyFramework and both having an "Embed Frameworks" or "Copy Files" phase configured to copy MyFramework to Build/Products/Debug/Frameworks/, Xcode sees two distinct commands attempting to write to the identical location, leading to the conflict.

I understand why this error occurring, but I do not set these commands up - Xcode does. Or to be more precise the Swift build system.

When I remove complete references of the libraries from the command line targets (HelperTool and AdditionalHelperTool), I actually get another error about the module _SubprocessCShims (which is part of swift-subprocess library): "Unable to find module dependency".

I've been playing with this for quite a few hours and it's just like playing whack-a-mole - I get rid of one error and get another one. :(

If MyFramework is not a system framework (which it likely isn't if it's from a SwiftPM package), your helper tools will need to find it at runtime.

Yes, this is why I've updated @rpath via the linker settings in Xcode.

OK, so I managed to create a minimal example: https://github.com/charlieMonroe/MultipleCommandsExample

There is an Xcode project MultipleCommandsExampleApp which has multiple dependencies and mainly a package MyTools that defines to executables - HelperTool and AdditionalHelperTool which also have multiple dependencies.

Issue with SwiftPM and multiple targets
 
 
Q