¿Cómo puedo evitar errores de “símbolo duplicado” en xcode con bibliotecas estáticas compartidas?

Tengo bibliotecas estáticas A, B y C organizadas en proyectos de Xcode. A y B dependen de C. Cuando construyo un proyecto de iPhone que depende de A y B, aparece un error de enlazador al detectar un símbolo duplicado (de C) en A y B. ¿Cómo puedo organizar estas tres bibliotecas estáticas para que yo pueda puede incluirlos en otros proyectos de Xcode sin experimentar este error?

La respuesta de Carl es correcta, pero por las razones equivocadas: no hay nada de malo en vincular las bibliotecas estáticas, como podemos ver utilizando la propia muestra de Carl. Configure el código de muestra de Carl y luego haga esto: (Yo uso libtool porque eso es lo que usa XCode)

neutron:libtest jamie$ libtool -o a2.a aa ca neutron:libtest jamie$ libtool -o b2.a ba ca neutron:libtest jamie$ gcc main.o a2.a b2.a -o app2 neutron:libtest jamie$ ./app2 a c b c neutron:libtest jamie$ 

Esto vincula a2.a y b2.a con main.o. Según Carl, esta es la fuente del problema de OP, y app2 no debería vincularse. Pero por supuesto que sí. El enlazador es lo suficientemente inteligente como para ignorar dos instancias del mismo archivo. Podemos ver que ambos a2.a y b2.a contienen co:

 neutron:libtest jamie$ ar -t a2.a __.SYMDEF SORTED ao co neutron:libtest jamie$ ar -t b2.a __.SYMDEF SORTED bo co 

Sin embargo, vincula bien.

Creo que el problema está relacionado con los binarios universales, los binarios universales PPC / x86 o los binarios universales de iPhone armv6 / armv7. El problema aquí es que hay un error con las categorías y la solución (add -all_load a los indicadores del enlazador) es una solución que solo funciona para architectures únicas. El uso de -all_load rompe la capacidad de los enlazadores de ignorar los símbolos que están definidos para múltiples architectures, y usted tiene el error de símbolo duplicado.

Escribí al respecto aquí, incluida una mejor solución que usar -all_load.

Este problema no es necesariamente relacionado con Xcode o Objective-C. No enlace / archive bibliotecas en otras bibliotecas. A & B solo depende de C en el tiempo del enlace final, no cuando están construidos. Usted quiere:

  1. construir un
  2. construir B
  3. construir C
  4. Desarrollar aplicación y enlace

Aquí hay un proyecto de ejemplo que hice para demostrar:

Makefile:

 app: main.o aa ba ca gcc $^ -o $@ %.o: %.c gcc -Wall -c $^ %.a: %.o ar -r $@ $^ clean: rm -rf *.o *.a app 

C.A:

 #include  void c(void); void a(void) { printf("a\n"); c(); } 

antes de Cristo:

 #include  void c(void); void b(void) { printf("b\n"); c(); } 

cc:

 #include  void c(void) { printf("c\n"); } 

C Principal:

 #include  void a(void); void b(void); int main(int argc, char *argv[]) { a(); b(); return 0; } 

Construir y ejecutar el registro:

 $ make gcc -Wall -c main.c gcc -Wall -c ac ar -r aa ao ar: creating archive aa gcc -Wall -c bc ar -r ba bo ar: creating archive ba gcc -Wall -c cc ar -r ca co ar: creating archive ca gcc main.o aa ba ca -o app rm ao bo co $ ./app a c b c 

Una alternativa para usar -all_load es usar -force_load-force_load ” solo para las bibliotecas donde se necesita. Por ejemplo, puede usar algo como: -force_load "$(PROJECT_DIR)/libname" .

Esto evita lo que necesita hacer para la solución de Jamie, que requiere que modifique los archivos de implementación.

Esta es la solución adoptada por el proyecto three20: http://groups.google.com/group/three20/browse_thread/thread/ec208be4ff8b4dcb/0dccf992a26850df

editar: a partir de Xcode 4.3, se -all_load la necesidad de -all_load y -force_load . Ahora solo se necesita -ObjC . Consulte https://stackoverflow.com/a/2615407/211292 para obtener más detalles.