3

A is a module project. There are some test targets and the relevant reusable code is compiled in a separate (static library) target. A uses the third party Lumberjack logging library. The Lumberjack code was simply dropped into the project.

B is a different module project, but otherwise it has the same properties as A.

C is the main project. It depends on A and B. It links the libraries of A and B.

Compiling C will result in duplicate Lumberjack symbols.

How can I have multiple separate module projects so that...

  1. they don't know of each other,
  2. use the same third party code,
  3. can be compiled and tested on their own,
  4. included in a main project without duplicate issues?
DrummerB
  • 39,814
  • 12
  • 105
  • 142
  • this sounds be a dificult with namespaces in objective-c. [http://stackoverflow.com/questions/15539041/how-does-one-use-namespaces-in-ios-objective-c-code][1] [1]: http://stackoverflow.com/questions/15539041/how-does-one-use-namespaces-in-ios-objective-c-code – Undefined Behavior Oct 08 '13 at 14:52
  • Just to be clear, Both `A` and `B` reference Lumberjack symbols with the exact same function, correct? Or is it that they are referencing different similarly named symbols with different function? – Still.Tony Oct 08 '13 at 18:08
  • Both, `A` and `B` reference the exact same third party library (Lumberjack). So somehow I would have to make them share that library in a way that they can still compile on their own, when used alone. I hope that makes sense. – DrummerB Oct 08 '13 at 18:31

7 Answers7

2

So, to elaborate on sergio's answer, I was able to succesfully build a test setup as follows.

  1. I included the Lumberjack code in a separate project that builds Lumberjack as a static library.
  2. I created a new project ProjectA with a static library target ModuleA and a test app target DemoA. I copied the Lumberjack project folder into the project folder of ProjectA and then added it as a subproject. I didn't make ModuleA dependent on Lumberjack or link Lumberjack in ModuleA. Instead, I made DemoA dependent on both and link both libraries. This way, I am able to compile the test target, but the library target doesn't include Lumberjack.
  3. I created a second project ProjectB with the analogue setup as ProjectA.
  4. In the main project, I included ProjectA, ProjectB and Lumberjack as subprojects. Unfortunately this will make Lumberjack included 3 times in the main project, which is a little bit inconvenient and ugly (for instance when selecting dependent targets, you can't really tell which one is which).
  5. Finally, I made the main project's target dependent on Lumberjack, ModuleA and ModuleB and link all three libraries. Now, the main project can compile without duplicate symbol error and the submodules can also be compiled and tested on their own.
Community
  • 1
  • 1
DrummerB
  • 39,814
  • 12
  • 105
  • 142
1

I hate to reference an existing answer but here's one solution that's cumbersome but works: What is the best way to solve an Objective-C namespace collision?

I have this same problem and I'm working on a better solution though. Another idea that might work but I'm not yet sure how to implement it I asked here: Selectively loading classes in Objective-C

A third idea I had because of something someone said on my question was to wrap one of the libraries in a framework and create functions that reference the functions you need. Then load using something like #import <myFramework/MFMyAliases.h>

Community
  • 1
  • 1
Still.Tony
  • 1,437
  • 12
  • 35
  • 1
    Wouldn't it be possible to put the 3rd party code in a dynamic framework, similarly to how Apple's frameworks can be imported and linked in multiple dependent projects without a problem? – DrummerB Oct 10 '13 at 06:52
  • Depends also what platform he's targeting.. Lumberjack isn't exclusive to Apple. If it isn't Apple, there are more options available. – Still.Tony Oct 10 '13 at 14:46
  • 1
    I'm targeting OS X. Thought that would be clear from the tags, but I'll add this too. – DrummerB Oct 10 '13 at 14:52
  • Yes, it should have been obvious. I didn't RTFQ. On Mac, I've decided it's easier to go with that first link I gave than to keep up the search for a clean simple solution. – Still.Tony Oct 10 '13 at 14:55
1

Have you tried looking at the libraries with ar? If you are very lucky, running for example

ar -t libA.a

gives you a list of files like

__.SYMDEF SORTED
Afile1.o
Afile2.o
Lumberjack1.o
Lumberjack2.o
Afile3.o
SomeOtherLibrary.o

where the Lumberjack files are clearly separable from the rest. Then, you can kick them out with

a -d Lumberjack1.o Lumberjack2.o

and link C against this trimmed library while using the full library when testing A alone.

Roberto
  • 3,003
  • 1
  • 18
  • 25
1

Since you are targeting OSX, the solution to your issue is building Lumberjack as a framework (as opposed to link the sources code in your A and B modules) and then using that framework wherever it is required (i.e., in any project using A or B modules).

Indeed, Lumberjack already includes a project that will build a Lumberjack.framework, check this: CocoaLumberjack/Xcode/LumberjackFramework/Desktop/Lumberjack.xcodeproj.

Elaborating more on this, you would define your A and B modules as you are doing now, but without dropping Lumberjack source code in it. What you do instead is, whenever you want to use the A static library in a executable (say, your test target), you add the library to the target and also the lumberjack framework (exactly as you do with OSX SDK frameworks).

Adding the dynamic framework is just a different way to "drop the sources", if you want, but done properly.

When you want to use both A and B in a C project, you add both static libraries and your Lumberjack framework to C.

As you can see, this way of doing will comply with all your four requirements, at the expense of introducing one dependency: you need to make clear in your static libraries documentation that they depend on the Lumberjack framework. This is actually not a big issue, since the latter is available in its own project and any one will be able to build it on his own.

If you want to improve on the handling of this dependencies, cocoapods are the way to go (a cocoapod is a file associated to your library which describes its dependencies, so when you install your library, the cocoapods system will automatically install also the dependencies). But this is highly optional. One single dependency is not a big issue to document or comply with.

Hope this answers your question.

sergio
  • 68,819
  • 11
  • 102
  • 123
  • While not perfect, I think this is the best solution to this problem. I was able to successfully compile a test setup and I'll write an answer with some details. Considering that my submodules are private anyway (not to be released to the public) I can live with the additional dependency. – DrummerB Oct 11 '13 at 11:22
  • My problem is *very* similar, but with this twist: `X` is the main project; `Y` is a library (Cocos2d) added *as a target dependency.* `Z` is my precompiled framework. `X` requires `Z` and `Y` requires `Z` (I'm tweaking Cocos2d, slightly.) `Y` (Cocos2d) is included in `X` as a framework (not sources.) I have duplicate symbols. I can't figure out how to bend your answer to solve my problem. **HELP!!!** Thanks! :) – Olie Aug 19 '14 at 18:16
  • (Is that worthy of a separate question? Or is it similar enough that a comment here can answer/fix it?) – Olie Aug 19 '14 at 18:17
  • @Olie: are you on iOS? if you include Z sources when building Y, you do not need linking separately Z into X, just make accessible the headers... if this does not help, post a new questions with more details, please.. – sergio Aug 19 '14 at 20:36
1

I was trying to achieve the same thing before few months and "Easy, Modular Code Sharing Across iPhone Apps: Static Libraries and Cross-Project References" article got all what i needed. please check it out if its useful.

Ravi_Parmar
  • 12,319
  • 3
  • 25
  • 36
  • I don't think this approach is flexible enough. As far as I can tell, it uses hard coded paths (in the source tree tab). Wouldn't that require fixed paths for certain parts of the project? I.e. I wouldn't be able to simply move them to an other place, or sent it to a colleague. – DrummerB Oct 11 '13 at 11:18
0

Are A and B binaries?

If not you could simply uncheck the compile checkbox for all *.m files of one of the projects, so as to avoid building duplicate objects.

Also if you could use A and B thorough Cocoapods it would be best.

Rivera
  • 10,792
  • 3
  • 58
  • 102
-1

Try this.

It is sharing libraries/modules between different projects.

Boggarapu
  • 333
  • 2
  • 7
  • 15