31

I'm writing a static library that has dependencies on other libraries (in my case SBJSON and ASIHTTPRequest).

If I compile these external dependencies into my library then I can't link against other libraries that have these classes compiled in. As my goal is to create a set of static libraries for my company that can be imported into any new app, compiling these dependencies into the library is obviously not an option.

Does anyone have any advice / best practices for creating a suite of shared static libraries with common dependencies?

deanWombourne
  • 38,189
  • 13
  • 98
  • 110
  • Why don't use dinamyc library instead? – LuisEspinoza Mar 14 '12 at 14:00
  • 3
    (A) That's pretty unhelpful to this question - my problem is to do with avoiding linker duplicate symbols. What about the SBJSON symbols? (B) They don't _hate_ it. They just have an opinion about it. (C) ASI is a pretty commonly used and real-world tested library - my code is almost certainly more buggy. Even the accepted answer from the question you link to has bugs! – deanWombourne Mar 15 '12 at 11:15
  • I would like to know the answer to the OP's question as well. With dynamic (libraries/frameworks), I can just say "Pull in libfoo", and that will automagically pull in all of libfoo's dependencies, recursively, until everything's accounted for. With static libraries, as far as I can tell, I have to tediously manually write out "-lfoo -lfoodep1 -lfoodep2..." for all the dependencies of libfoo, and their dependencies, and so on. This smells bad. But other than "always use dylibs" (which isn't possible on iOS), is there a solution? Can static libs carry their own dependency information? – Quuxplusone Sep 19 '12 at 17:19
  • Sorry @deanWombourne, I didn't see your reply until just now. SBJSON is obsolete in iOS5. Just use the system-provided JSON parser. Problem solved. :) Second, I said that as a comment on the question rather than a proper answer because it is helpful information. Respected people hate ASIHTTPRequest. It isn't an answer to your problem, thus, I didn't use it as an answer. If you're desperate for an NSURLConnection replacement, AFNetworking is good. https://github.com/AFNetworking/AFNetworking – Heath Borders Oct 03 '12 at 03:05
  • 1
    We target iOS 4 devices as well so we can't deprecate SBJSON (yet!) And this problem isn't _just_ SBJSON, I'm more after a good practice for _any_ shared static library. – deanWombourne Oct 03 '12 at 11:05
  • @HeathBorders: Respected people? Kind of an arrogant choice of language. – Chris Hatton Jun 15 '13 at 16:38
  • @Augmental Did you notice the reputation of the user whose post I linked to? He is obviously respected. – Heath Borders Jun 16 '13 at 03:20

3 Answers3

13

A static library is just a collection of object files. In your case you don't want the object files for SBJSON and ASIHTTPRequest to be included in your static library—you want to leave that job to the final application. The only thing your static lib needs is the header files for SBJSON and ASIHTTPRequest.

Since these projects are both distributed as source files (.h and .m files) you just need to tell Xcode not to build the SBJSON/ASIHTTPRequest .m files for your static library target.

The easiest way to do this is to only import the .h header files for these projects into your Xcode project. Alternatively you can import both the .h and .m files but make sure the .m files are not included in the "Compile Sources" build phase of your static library target

Some other relevant SO topics:

How can I avoid "duplicate symbol" errors in xcode with shared static libraries?

Duplicate symbol: Include static lib A in static lib B, also include lib A and B in XCode Project

Community
  • 1
  • 1
Ben Dolman
  • 3,165
  • 3
  • 25
  • 25
  • But what if my static lib use older version of sbjson - 3.0.4 , and the new project uses 3.1 ? it has the same m files but different h files , or one uses ARC and one does not ??? – James Roeiter Jul 24 '12 at 14:59
  • This very simple and apt solution should be the accepted answer. Thanks Ben for sparing me more headaches with this issue! – gchbib Dec 05 '12 at 02:34
9

You could use a dependency manager like CocoaPods or VendorKit to pull in the required library, as well as all it's transitive dependencies - libraries that the library depends on.

It's the job of the dependency manager to manage any conflicts in transitive dependencies - eg if two libraries both use different versions of SBJSON, it will work out what to do. All you have to do is declare the top level library you want in a config file and it will work out what sub-libraries are needed and pull them into your Xcode Project.

CocoaPods has a nice way of managing this by pulling in the all of the libraries as source, and then compiling them all into a single static library - in a separate project. This is then linked into your project via a workspace.

VendorKit takes a similar approach, but uses a single project file.

Both CocoaPods and VendorKit allow you to easily publish your library to a central repository. CocoaPods allows you to maintain your own private or public fork of the central repo, if you wish - ie as an enterprise repository.

Most of the time this will get you out of trouble. In rare cases your library might depend on a very specific, older version of another common library. In this case you could use a tool to rename all of the header/impl files in that library to avoid collisions.

[Edit]: As of January, 2013 there is also a new contender - Maven Xcode plugin.

duan
  • 8,515
  • 3
  • 48
  • 70
Jasper Blues
  • 28,258
  • 22
  • 102
  • 185
2

Create a static framework for each library. Document the dependencies in header files.

[Edit]: I now prefer using Cocoapods. See https://stackoverflow.com/a/10781087/9636

Community
  • 1
  • 1
Heath Borders
  • 30,998
  • 16
  • 147
  • 256