Michael Charland

Swift Developer

Home

Using Carthage - The good, the bad, the ugly

Published Jun 15, 2019

When I was on my old team we were trying to bring our build time down as it was getting super long (10+ minutes). Our repository contained frameworks that were directly inserted and ones in CocoaPods. One way to do build faster was to build less. How can you build less? Well every time you build from clean all the projects in CocoaPods are rebuilt. This was common to when switching branches or when the device/simulator was not behaving. So one of my team members investigated Swift Package Manager(SPM) and Carthage as alternatives to CocoaPods. SPM was quickly dropped as most of the frameworks we wanted to use were not supported. Eventually it was decided we would transition as many Cocoapod frameworks over to Carthage as possible. Here is a summary of how well that went and the long term consequences of that decision.

The Good

  • We built the Carthage libraries once, stored them in the repo, and then when building the main project the prebuilt library could be used. This made local builds and the CI faster. A double win. :D
  • We also stored the repo code of the framework in our repo so in case that specific version disappeared (This happened in the past) we could still build the framework. We needed to do this every time a new Swift version came out.

Bad

  • Only the person who built the Carthage framework could debug it. And it took over 2 hours to build all the frameworks so this was an unrealistic ask for people to do.
  • When you change just one project (version or add) in the Carthage configuration file (Cartfile) Carthage will rebuild everything. This was total overkill as the project being changed was completely isolated from the rest. We were able to get around this by hacking the Cartfile to only contain the new project you wanted.
  • Since we couldn’t move everything to CocoaPods we ended up with having some frameworks in three places (directly imported, CocoaPods, and Carthage) this worked fine, but ideally we would’ve been able to use one and roll with it. But this wasn’t realistic in practice. Yes, we could’ve forked the public repos and added Carthage supported. But the repos weren’t being updated and we didn’t want to have to maintain our own.
  • The Cartfile doesn’t dictate what files are stored in the Build and Checkout folders so when a framework was removed you had to manually remove the files. This was inconvenient.

Ugly

  • When every new Swift version was released we had to rebuild all the frameworks. This was before ABI stability. We were really aggressive with supporting new Swift version because they are bundled with Xcode. And when a new Xcode version was released a new iOS version also came out and a majority of our clients would upgrade quickly. This allowed us to fix bugs for them quickly.
  • In the Cartfile you could only specify the repo of the framework you wanted. And if that repo had multiple projects you would build all of them. This was a huge problem with the AWS Amplify repo as we only used I think 3 frameworks and it came with over 30. So all 30 were built.
  • Syncing private repos never worked consistently for me. I kept being told I didn’t have access or the repo didn’t exist. Then I would get it working and next time get the same error.

Summary

So as you can see with any technology there are tradeoffs. We definitely benefited from using Carthage as the build time did come down. Even though some of the tradeoffs are pretty annoying. Hopefully ABI stability will make there lives easier. Knowing how the Apple eco-system works this all might be a short stop until everyone jumps into using SPM. But only time will tell.