I have static libraries A, B and C organized into Xcode projects. A and B depend on C. When I build an iPhone project that depends on A and B, I get a linker error that a duplicate symbol (from C) was detected in A and B. How can I organize these three static libraries so I can include them in other Xcode projects without experiencing this error?
-
surely when building the library targets for A and B, you should only include the headers of C. You would only link to C when building the iPhone project? – Max MacLeod Feb 14 '13 at 09:43
3 Answers
Carl's answer is right, but for the wrong reasons: there's actually nothing wrong with linking static libraries together, as we can see using Carl's own sample. Set-up Carl's sample code and then do this: (I use libtool because that is what XCode uses)
neutron:libtest jamie$ libtool -o a2.a a.a c.a
neutron:libtest jamie$ libtool -o b2.a b.a c.a
neutron:libtest jamie$ gcc main.o a2.a b2.a -o app2
neutron:libtest jamie$ ./app2
a
c
b
c
neutron:libtest jamie$
This links a2.a and b2.a with main.o. According to Carl, this is the source of OPs problem, and app2 shouldn't link. But of course it does. The linker is smart enough to ignore two instances of the same file. We can see that both a2.a and b2.a contain c.o:
neutron:libtest jamie$ ar -t a2.a
__.SYMDEF SORTED
a.o
c.o
neutron:libtest jamie$ ar -t b2.a
__.SYMDEF SORTED
b.o
c.o
Yet it links fine.
The problem is, I believe, linked to Universal Binaries, either PPC/x86 universal binaries, or armv6/armv7 iPhone universal binaries. The problem here is that there is a bug with categories and the fix (add -all_load to the linker flags) is a fix that only works for single architectures. Using -all_load breaks the linkers ability to ignore symbols that are defined for multiple architectures, and you have your duplicate symbol error.
I wrote about it here including a better solution than using -all_load.
-
2Here's a working link to your blog entry: http://blog.binaryfinery.com/universal-static-library-problem-in-iphone-sd – ThomasW Mar 31 '11 at 15:10
-
Nope, that link is broken too. It's the final "k" that keeps being deleted. Bug with SO? Trying again: http://binaryfinery.wordpress.com/2010/06/11/universal-static-library-problem-in-iphone-sdk/ – Adam Nov 30 '13 at 16:58
-
1This also still happens with Xcode 10 and using the `-ObjC` flag instead of `-all_load`. – Frederik Nov 14 '18 at 14:15
A alternative to using -all_load
is to use -force_load
"path_to_lib" just for the libraries where it is needed. For example, you can use something like: -force_load "$(PROJECT_DIR)/libname"
.
This avoids what you need to do for Jamie's solution which requires you to modify implementation files.
This is the solution adopted by the three20 project: http://groups.google.com/group/three20/browse_thread/thread/ec208be4ff8b4dcb/0dccf992a26850df
edit: as of Xcode 4.3 the need for -all_load
and -force_load
has been removed. Now only -ObjC
is needed. See https://stackoverflow.com/a/2615407/211292 for more details.
-
`-all_load` and `-force_load` are no longer necessary, see here: http://stackoverflow.com/a/2615407/211292 – ThomasW Feb 10 '16 at 01:12
This problem isn't necessarily Xcode or Objective-C related. Don't link/archive libraries into other libraries. A & B only depend on C at final link time, not when they're built. You want:
- build A
- build B
- build C
- build app & link
Here's an example project I made to demonstrate:
Makefile:
app: main.o a.a b.a c.a
gcc $^ -o $@
%.o: %.c
gcc -Wall -c $^
%.a: %.o
ar -r $@ $^
clean:
rm -rf *.o *.a app
a.c:
#include <stdio.h>
void c(void);
void a(void)
{
printf("a\n");
c();
}
b.c:
#include <stdio.h>
void c(void);
void b(void)
{
printf("b\n");
c();
}
c.c:
#include <stdio.h>
void c(void)
{
printf("c\n");
}
main.c:
#include <stdio.h>
void a(void);
void b(void);
int main(int argc, char *argv[])
{
a();
b();
return 0;
}
Build and run log:
$ make
gcc -Wall -c main.c
gcc -Wall -c a.c
ar -r a.a a.o
ar: creating archive a.a
gcc -Wall -c b.c
ar -r b.a b.o
ar: creating archive b.a
gcc -Wall -c c.c
ar -r c.a c.o
ar: creating archive c.a
gcc main.o a.a b.a c.a -o app
rm a.o b.o c.o
$ ./app
a
c
b
c

- 219,201
- 40
- 422
- 469
-
1So far as I can tell, Xcode doesn't allow/support this? If it does, I think you should correct your answer to explain how to achieve it (seeing as the original question is tagged "xcode") -- I came here from Google because I cannot get Xcode to handle this simple setup! If not, this answer is useless, as it does nothing to solve the question. – Adam Nov 30 '13 at 16:56