31

我将静态库 A、B 和 C 组织到 Xcode 项目中。A 和 B 依赖于 C。当我构建依赖于 A 和 B 的 iPhone 项目时,我收到一个链接器错误,指出在 A 和 B 中检测到重复的符号(来自 C)。我该如何组织这三个静态库,所以我可以将它们包含在其他 Xcode 项目中而不会遇到此错误吗?

4

3 回答 3

28

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 链接起来。根据 Carl 的说法,这是 OPs 问题的根源,app2 不应该链接。但当然可以。链接器足够聪明,可以忽略同一文件的两个实例。我们可以看到 a2.a 和 b2.a 都包含 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

然而它链接得很好。

我相信,问题在于与通用二进制文件相关联,无论是 PPC/x86 通用二进制文件,还是 armv6/armv7 iPhone 通用二进制文件。这里的问题是类别存在错误,并且修复(将 -all_load 添加到链接器标志)是仅适用于单一架构的修复。使用 -all_load 会破坏链接器忽略为多个体系结构定义的符号的能力,并且您会遇到重复符号错误。

我在这里写过它,包括比使用 -all_load 更好的解决方案。

于 2010-06-30T20:57:36.183 回答
7

使用“path_to_lib”的另一种方法是仅对需要它的库-all_load使用“path_to_lib”。-force_load例如,您可以使用类似:-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需要。有关更多详细信息,请参阅https://stackoverflow.com/a/2615407/211292

于 2011-02-02T11:33:27.477 回答
6

这个问题不一定与 Xcode 或 Objective-C 相关。不要将库链接/归档到其他库中。A & B 仅在最终链接时依赖于 C,而不是在它们构建时。你要:

  1. 建个
  2. 构建 B
  3. 构建 C
  4. 构建应用程序和链接

这是我为演示而制作的示例项目:

生成文件:

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

交流:

#include <stdio.h>
void c(void);

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

公元前:

#include <stdio.h>
void c(void);

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

抄送:

#include <stdio.h>

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

主.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
于 2010-02-20T03:10:00.670 回答