如何避免“重复符号”共享静态库的 xcode 中出现错误?

发布于 2024-08-22 15:35:12 字数 154 浏览 10 评论 0原文

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

知你几分 2024-08-29 15:35:12

Carl 的答案是正确的,但原因是错误的:将静态库链接在一起实际上没有任何问题,正如我们使用 Carl 自己的示例所看到的那样。设置 Carl 的示例代码,然后执行以下操作:(我使用 libtool,因为 XCode 使用的是 libtool)

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 的说法,这是 OP 问题的根源,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 更好的解决方案。

Carl's answer is right, but for the wrong reasons: there's actually nothing wrong with linking static libraries together, as we can see using Carl's own sample. Set-up Carl's sample code and then do this: (I use libtool because that is what XCode uses)

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$ 

This links a2.a and b2.a with main.o. According to Carl, this is the source of OPs problem, and app2 shouldn't link. But of course it does. The linker is smart enough to ignore two instances of the same file. We can see that both a2.a and b2.a contain 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

Yet it links fine.

The problem is, I believe, linked to Universal Binaries, either PPC/x86 universal binaries, or armv6/armv7 iPhone universal binaries. The problem here is that there is a bug with categories and the fix (add -all_load to the linker flags) is a fix that only works for single architectures. Using -all_load breaks the linkers ability to ignore symbols that are defined for multiple architectures, and you have your duplicate symbol error.

I wrote about it here including a better solution than using -all_load.

╭⌒浅淡时光〆 2024-08-29 15:35:12

使用 -all_load 的替代方法是仅对需要的库使用 -force_load“path_to_lib”。例如,您可以使用类似以下内容的内容:-force_load "$(PROJECT_DIR)/libname"

这避免了您需要对 Jamie 的解决方案执行的操作,该解决方案需要您修改实现文件。

这是 Three20 项目采用的解决方案:http://groups。 google.com/group/third20/browse_thread/thread/ec208be4ff8b4dcb/0dccf992a26850df

编辑:从 Xcode 4.3 开始,需要 -all_load-force_load 已被删除。现在只需要 -ObjC 。有关更多详细信息,请参阅 https://stackoverflow.com/a/2615407/211292

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.

浮世清欢 2024-08-29 15:35:12

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

  1. 构建 A
  2. 构建 B
  3. 构建 C
  4. 构建应用程序 &链接

这是我用来演示的示例项目:

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

ac:

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

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

bc:

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

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

cc:

#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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文