xcode ld检测静态库中的重复符号

xcode ld检测静态库中的重复符号,xcode,clang,ld,darwin,Xcode,Clang,Ld,Darwin,这个问题以前曾被问过,但达尔文的ld(叮当声?)处理这个问题的方式似乎有所不同 假设我在两个文件main1.cc和main2.cc中定义了一个main()函数。如果我试图同时编译这两个,我将得到(所需的)重复符号错误: $ g++ -o main1.o -c main1.cc $ g++ -o main2.o -c main2.cc $ g++ -o main main1.o main2.o duplicate symbol _main in: main1.o main2.o l

这个问题以前曾被问过,但达尔文的ld(叮当声?)处理这个问题的方式似乎有所不同

假设我在两个文件main1.cc和main2.cc中定义了一个
main()
函数。如果我试图同时编译这两个,我将得到(所需的)重复符号错误:

$ g++ -o main1.o -c main1.cc
$ g++ -o main2.o -c main2.cc
$ g++ -o main main1.o main2.o
duplicate symbol _main in:
    main1.o
    main2.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
但如果我将其中一个粘贴到静态库中,当我链接应用程序时,不会出现错误:

$ ar rcs libmain1.a main1.o
$ g++ -o main libmain1.a main2.o
(no error)
使用gcc,您可以使用
--wholearchive
包装lib,然后gcc的ld将产生一个错误。此选项不适用于带有xcode的ld


是否可以让ld打印错误?

我确信您知道不应该放置对象文件 在静态库中包含
main
函数。以防我们的读者 不:库用于包含可被许多程序重用的函数。 一个程序只能包含一个
main
函数,并且 程序的
main
功能可作为
main
另一个的功能。所以
main
函数不在库中。(这条规则有几个奇怪的例外)

然后再谈谈你担心的问题。为了简单起见, 在本文的其余部分,我将不考虑共享/动态库的链接

链接器检测到重复符号错误(又称多重定义错误) 当竞争定义位于不同的输入对象文件中时,在链接中 但当一个定义是输入对象文件而另一个定义是输入对象文件时,不会检测到它 在输入静态库中。在这种情况下,GNU链接器可以检测到 如果之前传递了
--whole archive
选项,则为多重定义符号 静态库。但是你的链接器, 没有这个选择

请注意,虽然您的链接器不支持
--整个归档文件,但它有一个
等效选项
-所有负载
。但是,不要因此而逃避,因为这种担心无论如何都是毫无根据的。对于两个链接器:

  • [
    foo.o
    中的链接中确实存在多定义错误。。。
    bar.o
    ]外壳

  • 在[
    foo.o
    ..
    libbar.a
    ]案例中,链接中确实没有多定义错误

此外,对于GNU链接器:

  • 中的链接中确实存在多定义错误 [
    foo.o
    ..
    --整个归档libbar.a
    ]案例
在任何情况下,链接器都不允许对符号进行多个定义 在未被发现的情况下进入你的程序,任意使用其中一个

链接
foo.o
和链接
libfoo.o
有什么区别?

链接器将只向程序中添加对象文件。 更准确地说,当它遇到输入文件
foo.o
时,它会添加到您的程序中
foo.o
中的所有符号引用和符号定义。(首先 至少:如果您要求,它可能最终放弃未使用的定义, 如果它能够做到这一点而不附带丢弃任何使用过的)

静态库只是一包对象文件。当链接器遇到输入文件时
libfoo.a
,默认情况下,它不会将包中的任何对象文件添加到 你的节目

只有在必要时,才会在联动装置的该点检查行李内容物

如果已经添加了,则必须检查袋子中的内容物 对程序的某些符号引用没有定义。那些 未解析的符号可能在包中的某些对象文件中定义

如果它必须查看包中的文件,那么它将检查要删除的对象文件 查看其中是否有任何符号包含已在中的未解析符号的定义 节目。如果有任何这样的对象文件,那么它会把它们添加到程序中,重新考虑它是否需要继续在袋子里寻找。当它在包中找不到程序需要的对象文件或找到了程序引用的所有符号的定义(以先到者为准)时,它停止在包中查找

如果包中需要任何对象文件,这将至少再添加一个符号 程序的定义,可能还有更多未解析的符号。然后链接器继续。 一旦它遇到了
libfoo.a
,并考虑了该包中的哪些对象文件(如果有的话)是您的程序所需要的, 它不会再考虑它,除非它再次遇见它,稍后在链接中。 顺序

所以…

案例1。输入文件包含[
foo.o
..
bar.o
]。
foo.o
bar.o
定义符号
A
。两个对象文件都必须链接,因此
A
的两个定义都必须链接 添加到程序中,这是一个多定义错误。两个链接器都检测到它

案例2输入文件包含[
foo.o
..
libbar.a
]

  • libbar.a
    包含对象文件
    a.o
    b.o
  • foo.o
    定义符号
    A
    和引用,但不定义符号
    B
  • a.o
    还定义了
    a
    ,但没有定义
    B
    ,并且没有定义其他符号 由
    foo.o
    引用的
  • b.o
    定义符号
    b
然后:-

  • foo.o
    ,必须链接对象文件。链接器添加
    A
    的定义以及对程序的
    B
    的未解析引用
  • libbar.a
    中,链接器需要为未解析引用
    B
    定义一个定义,以便在包中查找
  • a.o
    不定义
    B
    或任何其他未解析的符号。它没有链接。未添加
    A
    的第二个定义
  • foo.o --whole-archive -lbar
foo.o a.o b.o
$ LIBFOOBAR_OBJS=`ar xv libfoobar.a | sed 's/x - //'g`
$ echo $LIBFOOBAR_OBJS
foo.o bar.o
cc -o prog x.o y.o z.o ... -lfoobar ...
cc -o deleteme x.o y.o z.o ... $LIBFOOBAR_OBJS ...