[关闭]
@qidiandasheng 2017-09-25T18:55:23.000000Z 字数 2087 阅读 4601

静态库duplicate symbols

iOS理论


符号表和编译链

一个程序从简单易读的代码到可执行文件往往要经历以下步骤:

源代码 > 预处理器 > 编译器 > 汇编器 > 机器码 > 链接器 > 可执行文件

源文件经过一系列处理以后,会生成对应的.o文件,然后一个项目必然会有许多.o文件,并且这些文件之间会有各种各样的联系,例如函数调用。链接器做的事就是把这些目标文件和所用的一些库链接在一起形成一个完整的可执行文件。

通俗的讲,我们在源码中写的全局变量名函数名类名在生成的*.o对象文件中都叫做符号,存在一个叫做符号表的地方。

举个例子:

我们在a.c文件中写了一个函数叫foo(),然后在main.c文件中调用了foo()函数,在将源码编译生成的对象文件中a.o对象文件中的符号表里保存着foo()函数符号,并通过该符号可以定位到a.o文件中关于foo()方法的具体实现代码。

链接器在链接生成最终的二进制程序的时候会发现main.o对象文件中引用了符号foo(),而foo()符号并没有在main.o文件中定义,所以不会存在与main.o对象文件的符号表中,于是链接器就开始检查其他对象文件,当检查到a.o文件中定义了符号foo(),于是就将a.o对象文件链接进来。这样就确保了在main.c中能够正常调用a.c中实现的foo()方法了。

注意: Objective-C 中方法的执行实在运行时决定的,所以链接器只链接类的符号,不链接方法的符号

.a静态库

一般可能是.a静态库和工程里面的某个类重复了,得到错误比如:

  1. duplicate symbol _OBJC_CLASS_$_GTMBase64 in:
  2. *****
  3. duplicate symbol _OBJC_METACLASS_$_GTMBase64 in:
  4. *****
  5. ld: 2 duplicate symbols for architecture arm64
  6. clang: error: linker command failed with exit code 1 (use -v to see invocation)

从上面错误我们可以看出在arm64这个架构的静态链接库出现了类名重复,我们可以得到对应架构的静态链接库里面所有类和分类的信息(以.o结尾的文件),所以可以把某个重复的类删除了,重新打包成静态库。具体参考处理.a静态库

Other Linker Flags

一般你的工程里Other Linker Flags会设置了-ObjC。如果我们删除了-ObjC,就会发现在编译时不会有duplicate symbols的错误了。但是运行的时候可能会出现unrecognized selector sent to class 0x105494cd8的错误。这是由于静态库中的分类没被链接器链接进可执行文件中。

对于ObjC,官方解释如下:

  1. This flag causes the linker to load every object file in the library that defines an Objective-C class or category. While this option will typically result in a larger executable (due to additional object code loaded into the application), it will allow the successful creation of effective Objective-C static libraries that contain categories on existing classes.

简单的说就是ObjC会把静态库中所有的类和分类都链接进可执行文件,但是它不会去检查此类是否重复了,所以才会出现duplicate symbols的错误。

所以这里我们想要的就是只把分类给链接进去,而ObjC显然会带出其他问题。
这里有另一个配置-force_load,这个的作用其实跟ObjC是类似的。它是只指定某一个静态库才执行链接所有类和分类的操作,而ObjC表示的是所以静态库。

所以理想的状态就是不使用ObjC,只有包含分类的静态库才使用-force_load,这样既能避免一些不必要的文件使包变大,又能使出现duplicate symbols的概率减小。

为什么只是减小呢?因为如果你这个静态库里即有重复文件又存在分类,那只能使用-force_load,同时那个重复的类也链接进来了,这样duplicate symbols就还会出现。

总结解决办法

参考

ios 静态库冲突的解决办法
解决两个静态库冲突 duplicate symbols
How can I avoid “duplicate symbol” errors in xcode with shared static libraries?

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注