CocoaPods 1.0 Migration Guide

Major 1.0 changes TL:DR

  • You now have to define targets. Previously there was an available implicit target.
  • A target has to represent an Xcode target.
  • When you want to represent a collection of pods that go to multiple targets, use an abstract_target then add targets inside that. Pod dependencies are inherited by nested targets.
  • Targets that want to know about the pods for a target but don't need linking (for example, Test targets) can define that they inherit pods via their search paths (inherit! :search_paths).
  • :exclusive => true and link_with have been removed in favour of the above.
  • xcodeproj is renamed project to make the DSL vocabulary consistent.
  • We've removed the ability to declare :head on a pod—you can either use the :podspec option or point directly to the upstream repo (via git, :svn, etc.).
  • You can now declare installation options inside the Podfile via install! (e.g. install! 'cocoapods', :deterministic_uuids => false, :integrate_targets => false).
  • We've removed all DSL attributes that were classed as deprecated.
  • pod trunk delete and pod trunk deprecate have been introduced.
  • pod search improvements (this is great because it searches all your private spec repos too).
  • pod lib lint and pod spec lint will verify that your pod can actually be imported.

Re-targeting

A large fraction of the bug reports we receive is due to ambiguity in the Podfile. It gave a lot of freedom to create all kinds of CocoaPods setups that would work by luck of implementation details, or work but are significantly more complex than they needed to be.

In the 0.x branches the name of a target could be anything. If it was the name of a matching target then it would automatically link to the target, but if not it would create a Pods-[Name] target and you could use link_to to connect it to targets.

In 1.0+ a target has to correspond to a real Xcode target. In order to support use cases where Pods can be shared among multiple targets we added abstract_target. For example:

# Note: There are no targets called "Shows" in any Xcode projects
abstract_target 'Shows' do
  pod 'ShowsKit'
  pod 'Fabric'

  # Has its own copy of ShowsKit + ShowWebAuth
  target 'ShowsiOS' do
    pod 'ShowWebAuth'
  end

  # Has its own copy of ShowsKit + ShowTVAuth
  target 'ShowsTV' do
    pod 'ShowTVAuth'
  end
end

Note: In this example, it would be simpler to just not use the abstract_target at all, but it's an example, so let me off.

This change enforces a much stronger connection between the CocoaPods target, and makes it impossible to make a Podfile like this:

pod 'ShowsKit'

due to it having ambiguous behavior. However, the following is possible, as it declares what target to link to:

pod 'ShowsKit'
target 'ShowsiOS'

This works because the root level is classed as an unnamed abstract_target.

More Examples

Let's take a look at a really common example that is shipped as the 0.x pod lib create.

source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!

target 'ORStackView_Example', :exclusive => true do
  pod 'ORStackView', :path => '../'
end

target 'ORStackView_Tests', :exclusive => true do
  pod 'ORStackView', :path => '../'

  pod 'Quick'
end

This sets up two completely independent CocoaPods targets that are exclusive to each other. Both have a copy of the library ORStackView. There is a lot going on in this Podfile; contrast that to the simpler 1.0 version.

source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!

target 'ORStackView_Example' do
  pod "ORStackView", :path => "../"

  target 'ORStackView_Tests' do
    inherit! :search_paths

    pod 'Quick'
  end
end

It has an obvious hierarchy, so you can see that Pods included in ORStackView_Example will be included in the ORStackView_Tests target. The only new thing is inherit! :search_paths which means "don't link Pods into here, but let this target know they exist." This Podfile is easier to read, simpler and has less redundant information.

Off with pods :head

Adding :head to a pod nearly always worked, except when it didn't. It is documented as this:

Finally, instead of a version, you can specify the :head flag. This will use the pod’s latest version spec version, but force the download of the ‘bleeding edge’ version. Use this with caution, as the spec might not be compatible with the source material anymore.

It was a tool that was really useful back when CocoaPods was small and it was hard to persuade people it was worth supporting any dependency manager for their projects. That time has long passed and now the flexibility that this attribute originally offered has fallen onto the side of "not worth keeping around." It would introduce extremely hard-to-debug issues for developers expecting it to mean "use the latest version of their code repo." You can either use the :podspec option or point directly to the upstream repo (via git, :svn, etc.).

Options to install!

In the past when we have had to support configuration options for CocoaPods we have used environment variables. These act like NSUserDefaults in that someone who knows the key can make a change, but otherwise they remain quite hidden. Though, sometimes they could be command line APIs too like --no-integrate. While these were conscious choices they eventually added up to being inconsistent over time, and we've opted to move in favour of centralizing the information in the Podfile. You can see all the available options in the guides.

This means that every developer on your team will have the same output on pod install regardless of their environment, whether in CocoaPods.app or in the command line. We've left the DSL attribute install! quite open so that future features can be built with this attribute.

Building for stability

A lot of the work for 1.0 has been around trying to simplify CocoaPods in order to provide long-lasting infrastructure. This is especially important given that the foundations that CocoaPods builds upon often shifts every June and the project is run by a handful of people in their spare time.

We also understand that running CocoaPods is about dealing with humans. With our default CocoaPods Specs repo, for example, we've had a policy of it being read-only since it was introduced CocoaPods Trunk. In reality though we've had to support editing and deleting Pods by hand on a relatively regular basis with the CocoaPods dev team being the ones having to make those decisions. With 1.0.0 we've built the infrastructure to support deleting and deprecating a CocoaPod and a CocoaPod version. We don't recommend it, but it's now there, and it's up to library owners to make the decisions around whether it's fine for their users to remove dependencies.

1.0

Finally, and probably the most important point. Once the betas are finished, I can get rid of this FAQ entry:

"CocoaPods is not ready for prime-time yet.”

Correct. Version 1.0.0 will be the milestone where we feel confident that all the basic requirements of a Cocoa dependency manager are fulfilled.

Once we reach the 1.0.0 milestone we will –for the first time ever– contact the community at large through mailing-lists such as cocoa-dev.

Which has been annoying me for as long as I've been working on CocoaPods' infrastructure / design.

🎉