iOS目前很大一部分三方库依然是以静态库为发布方式的,在公司内部尤其如此。以本公司为例,算法和通信库都是静态库,对外提供的SDK也往往是静态库。正好最近有同事问怎么解决符号冲突的问题,于是搜集两种场景和解决方案。
###集成方
- 对于三方的静态库,最后链接的时候出现符号冲突,发现某两个静态库发生冲突该怎么办?
这种情况下,一般需要将其中一个静态库中的相同依赖移除,解压静态库并移除相关的.o文件。但这是不保险的,因为前提冲突的函数或者方法定义是相同的或者可替换的。不同的情况下只会造成莫名其妙的崩溃问题。
正确的办法是要求SDK供应商修改冲突问题,或者更换不冲突的SDK。
###提供方
- 为客户提供静态库,如何防止符号冲突?如果需要提供两个静态库给客户,偏偏这两个静态库又依赖公用的静态库,到客户那会不会冲突,冲突的话怎么解决?
当作为提供方时,如果不能确定依赖的三方库会否被客户甚至客户的供应商使用,就坚决不要用,除非有源码能进行处理。客户集成时不一定会冲突,XCode里的-all_load 会加载所有链接符号,这种时候同名函数就会冲突;但如果没有的话,很有可能不会冲突,但这更糟糕,因为相同的连接符号只会加载一个,而且完全是根据加载顺序决定的,这时调用会不会崩溃完全取决于运气好不好。
即使三方库是自己的,比如两个SDK依赖了底层的算法库。也有极高的风险,比如某天算法库版本升了,实现有变动或者修复了bug,结果只更新了一个SDK提供给客户,这时客户最终连接的是哪个版本的算法库依然是不确定的。
那么要如何解决?
解决方法是prelink + 符号隐藏。
其原理在这里不赘述,大家可以自己寻找资料了解。
做法如下:
需要用
__attribute__((visibility("hidden")))
修饰需要隐藏的函数或方法, 另外一种是在源文件compilerFlags 添加-fvisibility=hidden. 不知为什么Xcode Symbols Hidden by Default 设置为YES并没起作用,还是会提示符号冲突。- SDK Build Settings :Perform Single-Object Prelink -> YES
- Prelink libraries $(CONFIGURATION_BUILD_DIR)/libxxxx.a
- Strip Linked Product -> YES
- Deployment Postprocessing -> YES