¿Cómo puedo evitar los errores de "símbolo duplicado" en xcode con bibliotecas estáticas compartidas?
objective-c duplicate-symbol (3)
Tengo bibliotecas estáticas A, B y C organizadas en proyectos Xcode. A y B dependen de C. Cuando construyo un proyecto de iPhone que depende de A y B, recibo un error de enlace que indica que se detectó un símbolo duplicado (de C) en A y B. ¿Cómo puedo organizar estas tres bibliotecas estáticas? ¿Se pueden incluir en otros proyectos de Xcode sin experimentar este error?
Este problema no está necesariamente relacionado con Xcode o Objective-C. No vincule / archive bibliotecas en otras bibliotecas. A y B solo dependen de C en el momento del enlace final, no cuando se construyen. Usted quiere:
- construir un
- construir B
- construir C
- construir aplicación y enlace
Aquí hay un proyecto de ejemplo que hice para demostrar:
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
C.A:
#include <stdio.h>
void c(void);
void a(void)
{
printf("a/n");
c();
}
antes de Cristo:
#include <stdio.h>
void c(void);
void b(void)
{
printf("b/n");
c();
}
cc:
#include <stdio.h>
void c(void)
{
printf("c/n");
}
C Principal:
#include <stdio.h>
void a(void);
void b(void);
int main(int argc, char *argv[])
{
a();
b();
return 0;
}
Crear y ejecutar registro:
$ 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
La respuesta de Carl es correcta, pero por los motivos equivocados: en realidad no hay nada de malo en vincular bibliotecas estáticas, como podemos ver usando el propio ejemplo 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 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$
Esto enlaza a2.a y b2.a con main.o. Según Carl, esta es la fuente del problema de los OP, y la aplicación 2 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 tanto a2.a como b2.a contienen co:
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
Sin embargo, se vincula bien.
El problema está, creo, vinculado a los binarios universales, ya sea los binarios universales PPC / x86, o los binarios universales de armv6 / armv7 para iPhone. El problema aquí es que hay un error con las categories y la solución (agregar -todos -cargar a las banderas del vinculador) es una solución que solo funciona para arquitecturas individuales. El uso de -all_load rompe la capacidad de los enlazadores para ignorar los símbolos definidos para múltiples arquitecturas, y tiene su error de símbolo duplicado.
Escribí sobre esto here incluyendo una mejor solución que usar -all_load.
Una alternativa al uso de -all_load
es usar -force_load
" -force_load
" solo para las bibliotecas donde sea necesario. Por ejemplo, puede usar algo como: -force_load "$(PROJECT_DIR)/libname"
.
Esto evita lo que debe 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
edición: a partir de Xcode 4.3 se -all_load
la necesidad de -all_load
y -force_load
. Ahora solo se necesita -ObjC
. Consulte https://.com/a/2615407/211292 para obtener más detalles.