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

Viewed 31875

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?

3 Answers

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.

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:

  1. build A
  2. build B
  3. build C
  4. 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
Related