问题
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...
- they don't know of each other,
- use the same third party code,
- can be compiled and tested on their own,
- included in a main project without duplicate issues?
回答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.
回答2:
So, to elaborate on sergio's answer, I was able to succesfully build a test setup as follows.
- I included the Lumberjack code in a separate project that builds Lumberjack as a static library.
- 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.
- I created a second project ProjectB with the analogue setup as ProjectA.
- 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).
- 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.
回答3:
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>
回答4:
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.
回答5:
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.
回答6:
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.
回答7:
Try this.
It is sharing libraries/modules between different projects.
来源:https://stackoverflow.com/questions/19141639/duplicate-symbols-two-projects-in-a-workspace-use-the-same-code