Organising Objective C Libraries
August 11, 2012

I asked this question on Stack Overflow earlier, but I think it’s worth posting basically the same thing here too.

I’ve been building libraries, and collections of layered libraries, for a long time, and I’m still not totally happy that I’ve found the best way to organise them. The question I asked was aimed at soliciting some insights from others.

Here it is:

Let’s say that I’ve three libraries, A, B, and C.

Library B uses library A. Library C uses library A.

I want people to be able to use A, B, and C together, or to just take any combination of A, B, and C if they wish.

I don’t really want to distribute them together in one large monolithic lump.

Apart from the sheer issue of bulk, there’s a good reason that I don’t want to do this. Let’s say that B has an external dependency on some other library that it’s designed to work with. I don’t want to force someone who just wants to use C to have to link in that other library, just because B uses it. So lumping together A, B and C in one package wouldn’t be good.

I want to make it easy for someone who just wants C, to grab C and know that they’ve got everything they need to work with it.

What are the best ways of dealing with this, given:

This seems like a relatively straightforward question, but before you dive in and say so, can I suggest that it’s actually quite subtle. To illustrate, here are some possible, and possibly flawed, solutions.


The fact that B and C use A suggests that they should probably contain A. That’s easy enough to achieve with git submodules. But then of course the person using both B and C in their own project ends up with two copies of A. If their code wants to use A as well, which one does it use? What if B and C contain slightly different revisions of A?


An alternative is set up B and C so that they expect a copy of A to exist in some known location relative to B and C. For example in the same containing folder as B and C.

Like this:

  libB/ -- expects A to live in ../
  libC/ -- expects A to live in ../

This sounds good, but it fails the “let people grab C and have everything” test. Grabbing C in itself isn’t sufficient, you also have to grab A and arrange for it to be in the correct place.

This is a pain - you even have to do this yourself if you want to set up automated tests, for example - but worse than that, which version of A? You can only test C against a given version of A, so when you release it into the wild, how do you ensure that other people can get that version. What if B and C need different versions?


This is a variation on the above “relative location” - the only difference being that you don’t set C’s project up to expect A to be in a given relative location, you just set it up to expect it to be in the search paths somewhere.

This is possible, particularly using workspaces in Xcode. If your project for C expects to be added to a workspace that also has A added to it, you can arrange things so that C can find A.

This doesn’t address any of the problems of the “relative location” solution though. You can’t even ship C with an example workspace, unless that workspace makes an assumption about the relative location of A!


A variation on the solutions above is as follows:

So CI might contain:

- C.xcworksheet
- modules/
    - A (submodule)
    - C (submodule)

This is looking a bit better. If someone just wants to use C, they can grab CI and have everything.

They will get the correct versions, thanks to them being submodules. When you publish a new version of CI you’ll implicitly be saying “this version of C works with this version of A”. Well, hopefully, assuming you’ve tested it.

The person using CI will get a workspace to build/test with. The CI repo can even contain sample code, example projects, and so on.

However, someone wanting to use B and C together still has a problem. If they just take BI and CI they’ll end up with two copies of A. Which might clash.


The problem above isn’t insurmountable though.

You could provide a BCI repo which looks like this:

- BC.xcworkspace
- modules/
    - A (submodule)
    - B (submodule)
    - C (submodule)

Now you’re saying “if you want to use B and C together”, here’s a distribution that I know works.

This is all sounding good, but it’s getting a bit hard to maintain. I’m now potentially having to maintain, and push, various combinations of the following repos: A, B, C, BI, CI, BCI.

We’re only talking about three libraries so far. This is a real problem for me, but in the real world potentially I have about ten. That’s gotta hurt.

So, my question to you is: