Configuring Cocoapods with an existing static library and iOS application
Asked Answered
C

2

26

I'm having trouble getting my workspace to compile correctly with Cocoapods. There are 3 projects in the workspace, each with their own target:

  1. libPods - Cocoapods static library with all the external dependencies
  2. libCommon - My static library where I keep all my shared code (base controllers, networking code, common UI, etc)
  3. myApp - My iOS application

Both libCommon and myApp require the external dependencies from the libPods. Originally I thought it would work like this:

  1. libPods builds
  2. libCommon links against libPods and builds
  3. myApp links with libCommon and builds

In this scenario libCommon "owns" the pods, and then then myApp just links against libCommon like I've always done pre-Cocoapods... but apparently static libraries don't like to be linked with static libraries (I got a bunch of dynamic library errors). I read on a github issue somewhere that instead I should build libPods and libCommon and then myApp should link against both libraries. Right now my podfile looks something like this:

workspace 'MyApp.xcworkspace'
platform :ios, '5.0'

link_with ['Common', 'MyApp']

target 'MyApp' do
  xcodeproj 'MyApp.xcodeproj'

  pod 'AFNetworking',               '1.1.0'
  pod 'TTTAttributedLabel',         '1.6.0'
  pod 'JSONKit',                    '1.5pre'
  pod 'Reachability',               '3.1.0'
end

With this setup, myApp owns all the pods, and then in the libCommon build settings I specify the path to the pod headers. This builds OK until I attempt to use one of the classes in libCommon. Once I do that, I get one of those _OBJC_CLASS_$_Blah errors (which tells me that although the headers are available, it's still not linked properly). When I try to manually link libCommon in "Build Phases" I get a bunch of duplicate symbol errors (which leaves me to believe it's already linked?). What the heck?

What's the way to do this properly and what should my podfile look like?

Confirm answered 8/5, 2013 at 23:1 Comment(0)
P
11

CocoaPods creates an implicit root target which by default links with the first target of the project. As you are creating another target and the link_with option is not inherited by children target definitions your set up is not working. In order to make the link_with option you can move it inside the block of the MyApp target definition.

As the Common target links with the Pods, if you link those with the MyApp it will result in the duplicate symbols error as the app links with Common. In this case you just need to make the headers available to the MyApp target. This is simple to do but there isn't a proper DSL yet so for the moment is a bit hacky as a solution (but supported).

workspace 'MyApp.xcworkspace'
platform :ios, '5.0'

target 'Common' do
  pod 'AFNetworking',               '1.1.0'
  pod 'TTTAttributedLabel',         '1.6.0'
  pod 'JSONKit',                    '1.5pre'
  pod 'Reachability',               '3.1.0'

  target 'MyApp', :exclusive => true do
    xcodeproj 'MyApp.xcodeproj'
  end
end
Palua answered 9/5, 2013 at 23:1 Comment(9)
I have no idea how you are so quick to answer cocoapods, Fabio, but just a note that it's much appreciated! I've had a similar issue before, and the 'exclusive' option resolves it.Corkboard
I've setup like you've suggested, and the MyApp target compiles successfully until I attempt to use a class from Common (eg: adding this line: MyObject *objectFromCommon = [[MyObject alloc] init]; results in a _OBJC_CLASS_$_MyObject error). The parser/syntax highlighting is fine though, which leads me to believe the headers are available but the lib still isn't linked. Thoughts?Confirm
@user2393462435, you need to link the Common target with the MyApp target in the frameworks build phase manually (CocoaPods doesn't manages your targets).Palua
@Fabio, when I link manually it results in duplicate symbol errors. Ugh, might have to give up on cocoapods. I'm surprised my project setup isn't more common..Confirm
This works for the most part. However, what it fails to do is link all the dependencies for Common in MyApp. So it ultimately doesn't work. I found if I added a link_with 'MyApp' in the root, then after install I deleted the libPod.a from MyApp in the build phases (stops duplicate symbols) it would work. But who wants all that extra work?Estivation
You answer helped me to solve my issue, but Im still trying to figure out whats going on. I thought we have to declare xcodeproj before the target and how does it find 'Common' :$Backlash
When I try this approach and I build MyApp I get an error ld: library not found for -lPods. More detail here github.com/lyahdav/cocoapods_kiwi_shared_library. Any ideas?Marlowe
For anyone who gets the ld: library not found for -lPods error I was getting, I posted a solution here https://mcmap.net/q/537438/-kiwi-and-cocoapods-with-a-static-shared-library.Marlowe
How does this prevent 'Common' (which I presume is a static lib) from acquiring the various pods "-l dynamicLib" linker flags? (e.g. can't locate file for: -licucore)Disenthrone
E
5

The solution I've adopted for this situation is as follows:

I set up the Podfile quite simply:

workspace 'MyApp.xcworkspace'
platform :ios, '5.0'

xcodeproj 'Common.xcodeproj'

pod 'AFNetworking',               '1.1.0'
pod 'TTTAttributedLabel',         '1.6.0'
pod 'JSONKit',                    '1.5pre'
pod 'Reachability',               '3.1.0'

target 'MyApp' do
    xcodeproj 'MyApp.xcodeproj'
    # specific dependencies
end

This way the Common lib and MyApp are set up correctly to use all the dependencies. However, this will still cause duplicate symbols. The way to get around that is to simply delete libPods.a from the Common project's Build Phase. This is fine because we don't really want to link to the Cocoapods static lib to our static lib anyway. All the correct dependencies will be linked when you build the app, and all the correct header paths are set up in the .xccconfig files so Xcode/AppCode will still provide all your auto-completions and everything will compile.

You'll need to delete the libPods.a each time you run pod install which is a bit of a pain, but it might be better suffering that than managing all the dependencies manually.

Update: I'm working on this as I write and I've just noticed it's important not to use the Linker Flags Cocoapods sets up within your static library. By default, my static lib had overridden their value with no value but Cocoapods warns against this and advises you use $(inherited). Just ignore it.

Estivation answered 25/7, 2013 at 22:9 Comment(3)
Do you know of a way to automate the removal? I want to add it so that my build server can do a 'pod install' before every build.Remains
How do you solve this if you have three projects in the same folder. "MyApp-Core", "MyApp-iOS" and "MyApp-Mac" ?Lexington
I'm having an issue where it says 'No such file or directory' for Podfile.lock or Manifest.lock. Also, 'the sandbox is not in sync with the Podfile.lock'Golfer

© 2022 - 2024 — McMap. All rights reserved.