CocoaPods / swift

Issue tracker for CocoaPods with Swift issues
24 stars 3 forks source link

Our experience with CocoaPods+Framework #11

Open fluidsonic opened 9 years ago

fluidsonic commented 9 years ago

This issue's purpose is to share our experience with CocoaPods+Frameworks and to discuss possible improvements. Our app project has 4 app targets (for staging), 3 framework targets (used by the app targets), 1 subproject (another Swift framework), 12 Pod dependencies and 4 transitive Pod dependencies.


Build times are horrible at the moment and even indexing takes 5-10 minutes. Debugging Swift code in the console is completely broken. Swift build & indexing times weren't great before telling CocoaPods to use frameworks, but after the switch they became worse, esp. indexing times. CocoaPods seems to be doing (and allow through Podfile) unnecessary complex configurations which make things worse. I don't know though whether the debugger would work correctly when not using CocoaPods. It's known for problems with Swift code.

One thing I don't understand is why a custom script is necessary to achieve the copying & signing of frameworks. Xcode by itself is capable of resolving dependencies and copying frameworks as long as you configure it that way.

Another thing which is weird is that frameworks targets also have an Embed Pods Frameworks phase which just copies frameworks into other frameworks and pollutes the app bundle with these ghost frameworks that never get loaded anyway. Pod dependencies of framework targets are supposed to be transient dependencies, aren't they?

It's also annoying that when two targets (one app target, one framework target - where the app target depends on the framework target) have the same dependency as per Podfile BUT the dependency is compiled twice by CocoaPods (since they become two distinct Pods targets) - wasting a lot of time.

An Experiment

I was able to manually remove the Embed Pods Frameworks phases and replace them with a Copy Files phase with Destination set to Frameworks. After adding all Pod frameworks to the Copy Files phase the app still builds & runs fine.

I'll try to explain our workspace's structure, how it's configured and what the pros/cons of these changes are.

Workspace Structure

(I simplified the structure a bit since we also have one app target per staging level.)

Projects & Targets

Empty for all targets.

Link With Libraries Phase (Implicit Target Dependencies)

Works as expected! Everything is built in the correct order and copied into the app bundle. It runs fine on the device. It's a simple configuration but CocoaPods seems to make this unnecessary complex.

It also works after deleting the app or wiping DerivedData so there's nothing in the cache which affects this.

Cons

CocoaPods is doing stuff on its own which could also be done by Xcode itself. Xcode can handle things like copying frameworks more effectively which reduces build times. CocoaPods' custom script phases are totally annoying as they run on every build.

I think with frameworks enabled the compilation of storyboards, asset catalogs and the copying of resources could also be done by Xcode without having a custom script. Again this script is executed for every build which takes time and for some reason every target also compiles asset catalogs of non-dependencies.

Simplifying & cleaning up the overall structure could also save build time, improve indexing time & quality and speed up Xcode in general. But I expect that such improvements require overall architectural changes which is a lot of work.

segiddins commented 9 years ago

One comment: as @mrackwitz has pointed out repeatedly, the Embed Frameworks Script is necessarily to allow scoping dependencies per build configuration.

CocoaPods is also not really optimized to be used to build _other_frameworks that are used in your app -- those frameworks ideally would be Pods themselves.

neonichu commented 9 years ago

Thanks for your detailed issue - could you add your Podfile to it to make it more clear?

Does the "Copy Resources" script actually handle resources from Pods which are build as frameworks for you? Using the current swift branch, resources should be part of the frameworks.

fluidsonic commented 9 years ago

@segiddins Working with Development Pods isn't fun and Xcode is more than capable of building modular apps consisting of many frameworks. Why should I make that more complicated with CocoaPods?

@neonichu Using my example above, for some reason the Api app target compiles the asset catalog of the Mixpanel pod. Both are framework targets.

The Mixpanel pods target has all images inside the asset catalog in the Copy Bundle Resources phase instead of the asset catalog itself. This seems to be the problem.

fluidsonic commented 9 years ago

@neonichu Why DO app targets still have a Copy Pods Resources phase when I use use_frameworks!? Just as you said - the resources should be in the frameworks anyway.

neonichu commented 9 years ago

@fluidsonic there are Pods which do not include any source_files - for them no framework target will be created and any possible resources will be copied into the app bundle by the script. Also the script phase will always be present at the moment in case one switches back to not using frameworks. If it is possible to integrate the resources into a suitable framework target, they will be omitted from the script.

The Mixpanel situation sounds like a bug, though.

fluidsonic commented 9 years ago

@neonichu Are there really pods having neither source files, nor public header files nor vendored frameworks? How would you even use them?

It's also funny that for LayerKit no pod target is created but for CrashlyticsFramework one is created. The difference is that LayerKit declares its public headers using public_header_files while CrashlyticsFrameworks declares its public headers using source_files. Both have no real source files (i.e. .c, .m, .swift, etc.).

So why can't LayerKit be a pod target too? Why not all? I find the current behavior inconsistent and confusing. Both pods mentioned above have a vendored_framework and no real source files yet only one of them becomes a pod target.

neonichu commented 9 years ago

@fluidsonic a Pod could contain just vendored_libraries and accompanying resources - or even just package resources, without any code.

Currently, only the presence of any content in the source_files attribute is used to decide the behaviour - that should indeed be changed to omit headers. Then LayerKit and CrashlyticsFramework would behave the same.

neonichu commented 9 years ago

I can't really reproduce the Mixpanel situation you are describing, the Pod doesn't even include any asset catalogues, just plain PNGs. Those simply end up in the framework bundle. Could you share your Podfile to understand the situation better?

fluidsonic commented 9 years ago

Oh, there are two different issues here.

  1. Mixpanel has their PNG files in an asset catalog but in the podspec's resources they include the PNGs directly. No big issue if the file names are correct.

    Yet CocoaPods tries to compile the asset catalog.

    PhaseScriptExecution Copy\ Pods\ Resources /Users/marc/Library/Developer/Xcode/DerivedData/MixpanelTest-dxfigjxrwhagxhgzhgxpaxavltjj/Build/Intermediates/MixpanelTest.build/Debug-iphonesimulator/Framework.build/Script-7B9072465AC6FF5A09E4148E.sh
    cd /Users/marc/Documents/MixpanelTest
    /bin/sh -c /Users/marc/Library/Developer/Xcode/DerivedData/MixpanelTest-dxfigjxrwhagxhgzhgxpaxavltjj/Build/Intermediates/MixpanelTest.build/Debug-iphonesimulator/Framework.build/Script-7B9072465AC6FF5A09E4148E.sh
    
    building file list ... done
    
    sent 29 bytes  received 20 bytes  98.00 bytes/sec
    total size is 0  speedup is 0.00
    2014-12-17 12:01:12.505 IBCocoaTouchImageCatalogTool[1010:11885] CoreUI(DEBUG): CSIGenerator using LZVN Compression coreui version (298.200000)
    /* com.apple.actool.document.warnings */
    /Users/marc/Documents/MixpanelTest/Pods/Mixpanel/Mixpanel/Media.xcassets:./MPArrowLeft.imageset/[][][][][][][MPArrowLeft.png]: warning: The image set "MPArrowLeft" has 2 unassigned images.
    /Users/marc/Documents/MixpanelTest/Pods/Mixpanel/Mixpanel/Media.xcassets:./MPCheckmark.imageset/[][][][][][][MPCheckmark.png]: warning: The image set "MPCheckmark" has 2 unassigned images.
    /Users/marc/Documents/MixpanelTest/Pods/Mixpanel/Mixpanel/Media.xcassets:./MPDismissKeyboard.imageset/[][][][][][][MPDismissKeyboard.png]: warning: The image set "MPDismissKeyboard" has 2 unassigned images.
    /Users/marc/Documents/MixpanelTest/Pods/Mixpanel/Mixpanel/Media.xcassets:./MPLogo.imageset/[][][][][][][MPLogo.png]: warning: The image set "MPLogo" has 2 unassigned images.
    /Users/marc/Documents/MixpanelTest/Pods/Mixpanel/Mixpanel/Media.xcassets:./MPArrowRight.imageset/[][][][][][][MPArrowRight.png]: warning: The image set "MPArrowRight" has 2 unassigned images.
    /Users/marc/Documents/MixpanelTest/Pods/Mixpanel/Mixpanel/Media.xcassets:./MPCloseBtn.imageset/[][][][][][][MPCloseBtn.png]: warning: The image set "MPCloseBtn" has 2 unassigned images.
    /* com.apple.actool.compilation-results */
    /Users/marc/Library/Developer/Xcode/DerivedData/MixpanelTest-dxfigjxrwhagxhgzhgxpaxavltjj/Build/Products/Debug-iphonesimulator/Framework.framework/Assets.car
  2. As you can see in the previous log excerpt it's the Framework target which compiled Mixpanel's asset catalog, although it's not one of its dependencies. I only added it as a dependency of the App target.

Here is the test project.

neonichu commented 9 years ago

Thanks, we definitely need to change the "Copy Resources" script, it compiles and copies asset catalogs unconditionally. //cc @mrackwitz

rjstelling commented 9 years ago

@neonichu @mrackwiz As of 0.36.rc1 the Copy Resource script still "compiles and copies asset catalogs unconditionally".

Are there any work arounds for this, my app bundle is now twice the size it should be.