У меня есть статические библиотеки A, B и C, организованные в проекты Xcode. A и B зависят от C. Когда я создаю проект iPhone, который зависит от A и B, я получаю ошибку компоновщика, что дублированный символ (из C) был обнаружен в и B. Как я могу организовать эти три статические библиотеки, чтобы я могут включать их в другие проекты Xcode, не испытывая этой ошибки?
Как избежать ошибок "дублирования символа" в xcode с помощью общих статических библиотек?
Ответ 1
Ответ Carl прав, но по неправильным причинам: на самом деле нет ничего плохого в связывании статических библиотек вместе, как мы можем видеть, используя собственный образец Carl. Создайте образец кода Carl, а затем выполните следующее: (Я использую libtool, потому что это то, что использует 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$
Это ссылки a2.a и b2.a с main.o. По словам Карла, это источник проблемы OPs, а app2 не должен связываться. Но, конечно, это так. Линкер достаточно умен, чтобы игнорировать два экземпляра одного и того же файла. Мы видим, что как a2.a, так и b2.a содержат 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
Но он отлично связывается.
Проблема, я считаю, связана с универсальными бинарниками, либо с универсальными двоичными файлами PPC/x86, либо с универсальными двоичными файлами armv6/armv7 iPhone. Проблема здесь в том, что существует ошибка с категориями, а исправление (add -all_load для флагов компоновщика) - это исправление, которое работает только для единой архитектуры. Использование -all_load прерывает способность компоновщиков игнорировать символы, которые определены для нескольких архитектур, и у вас есть повторяющаяся ошибка символа.
Я написал об этом здесь, включая лучшее решение, чем использование -all_load.
Ответ 2
Эта проблема не обязательно связана с Xcode или Objective-C. Не связывайте/архивируйте библиотеки в другие библиотеки. A и B зависят только от C в момент конечной ссылки, а не когда они построены. Вы хотите:
- построить A
- построить B
- построить C
- создать приложение и ссылку
Вот пример проекта, который я продемонстрировал:
Makefile:
app: main.o a.a b.a c.a
gcc $^ -o [email protected]
%.o: %.c
gcc -Wall -c $^
%.a: %.o
ar -r [email protected] $^
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();
}
к.ц:
#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;
}
Создайте и запустите журнал:
$ 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
Ответ 3
Альтернативой использованию -all_load
является использование -force_load
"path_to_lib" только для библиотек, где это необходимо. Например, вы можете использовать что-то вроде: -force_load "$(PROJECT_DIR)/libname"
.
Это позволяет избежать того, что вам нужно сделать для решения Jamie, которое требует изменения файлов реализации.
Это решение, принятое проектом three20: http://groups.google.com/group/three20/browse_thread/thread/ec208be4ff8b4dcb/0dccf992a26850df
изменить: с Xcode 4.3 необходимость в -all_load
и -force_load
была удалена. Теперь требуется только -ObjC
. Подробнее см. fooobar.com/info/29356/....