Open paulyoung opened 8 years ago
cc @gfontenot
Thanks for bringing this here to more attention for those, which it might concern. To my knowing there is no other solution than what you were able to come up with so far. But there is at least a radar to be duplicated.
As the info feels a bit scattered currently, just to summarize if others should come across this, to be perfectly clear what is working here and what not:
You can build an universal framework with dependencies with a single scheme without any problems, when all dependencies are also available as universal frameworks and setup as explicit target dependencies in Xcode and "Find implicit dependencies" is disabled.
But there are limitations in the way you can configure targets in Xcode, which might prevent you from setting up an universal framework in any possible scenario. Most target-specific settings, you'd usually setup in the Xcode GUI, can be moved to the build settings, which can be scoped by the platform. That might not be as intuitive or beginner-friendly, but is a limitation of the GUI and works at least. That doesn't apply for file target memberships. This can be resolved for source code by making use of the preprocessor / language features (#if os(iOS)
). For resources there is no other solution, beside selecting, manually processing and copying them by a script build phase, which is error-prone because you have to redo all what Xcode would take care of automatically for you by the built-in build rules.
If not all dependencies are available as universal frameworks (e.g. Argo
), then you could still unify your framework (e.g. Foo
) over multiple platforms. The way Xcode exposes that via Linked Frameworks and Binaries is not sufficient here, because this selection is platform-specific. You will need to configure the frameworks, which you depend on in your build settings' OTHER_LD_FLAGS
and have to add there each framework (e.g. -framework Argo
). Beside that you need to make sure that:
If the frameworks, you depend on, use the same product name on all platforms, what you would usually do and could expect to work, because the build products directory is already scoped by platform, then you might run into rdar://20490378, which causes that Xcode indeterminately selects a scheme building the correct product, but for any platform. So for example, you might end up that your Foo
scheme can't compile for iOS because there is no Argo
framework, but the build log reveals that Xcode build Argo-Mac
instead of Argo-iOS
.
Because those build products remain until you clean the build folder the next time and it is indeterminate, this might take to be discovered until your CI or a coworker attempts to build the framework.
As a workaround, you can still setup a single universal framework by duplicating just the scheme for each platform. (e.g. Foo-iOS
) This is based on the approach of Implicit Dependencies. Additionally, you need to refer to the platform-specific schemes (e.g. Argo-iOS
) and to universal schemes of your dependencies in each of the platform-specific schemes for your framework.
Beside that you need to disable the option "Find implicit dependencies" in your scheme settings. This makes sure that the right schemes and only the right schemes are built by Xcode.
As you're responsible for setting up the order, the option "Parallelize Build" has to be disabled and common dependencies have to be put first in the list.
@mrackwitz I believe there's a build setting you can use to ignore specific files
I'm aware that this may be par for the course when using this approach but wanted to mention it in case there are workarounds available or radars to be filed.
The details can be found here, but please let me know if you need more info: https://github.com/thoughtbot/Curry/pull/16#issuecomment-158339471