两个oc 第三方静态库冲突库冲突,怎么弄

使用了阿里系某趣 SDK 其中的 GPUImage 与 自己项目中的 GPUImage 库发生冲突,导致大量duplicate symbol 报错(即重复了)
解决思路有两个
1.去除一个
(1)如果是 .a 文件 可以把引用的第三方.a解开,把冲突的.o都干掉 ; 奈何某趣 SDK(1.0.1) .a 还混淆了 ,有熟悉的小伙伴可以给我留言
(2)加入一个链接符号,让编译链接不冲突 ,这个方法比较 hack 应该是可行的 ,即在 Other C Flags 中改写 重复符号的名字 使之不重复;但是我没能实现 -_- ,不过思路应该是正确的,求教实现的小伙伴
/blog/avoiding-duplicate-symbol-issues-when-using-common-utilities-within-a-static-library/
2.改写一个
不是什么黑科技,乖乖把 GPUImage 从 pods 中拉出来 直接源码导入到工程中,然后开始手动改代码吧 (你在逗我么 3k多个重复类名!!!!)
后来 用 Python 写了段改名的代码 (Python 大发好):
# -*- coding: utf-8 -*-#批量修改类名字import osimport reimport stringimport stringmy_path = &/Users/jasper/Desktop/pure/GPUImage1.0.7&my_write_path = '/Users/jasper/Desktop/pure/new'target = &GPU&replace = &WKU&target2 = &GLProgram&replace2 = &GLWKProgram&dict = /
&dataProviderReleaseCallback&: &dataWKProviderReleaseCallback&,
&dataProviderUnlockCallback&: &dataWKProviderUnlockCallback&,
&kColorConversion601&: &kWKColorConversion601&,
&kColorConversion601FullRange&: &kWKColorConversion601FullRange&,
&kColorConversion709&: &kWKColorConversion709&,
&runAsynchronouslyOnVideoProcessingQueue&: &runWKAsynchronouslyOnVideoProcessingQueue&,
&runSynchronouslyOnContextQueue&: &runWKSynchronouslyOnContextQueue&,
&runSynchronouslyOnVideoProcessingQueue&: &runWKSynchronouslyOnVideoProcessingQueue&,}def modify_f(f_path, write_path):
files = os.listdir(f_path)
for f in files:
# 忽略掉杂项
if f[0] == &.&:
sub_path = f_path + '/' + f
file_name = f.replace(target, replace)
file_name = file_name.replace(target2, replace2)
if os.path.isfile(sub_path):
new_write_path = write_path + '/' + file_name
lines = open(sub_path, 'r').readlines()
f_len = len(lines) - 1
for i in range(f_len):
lines[i] = lines[i].replace(target, replace)
lines[i] = lines[i].replace(target2, replace2)
for key in dict.keys():
lines[i] = lines[i].replace(key, dict[key])
open(new_write_path, 'w').writelines(lines)
# 是目录 则 递归
new_write_path = write_path + '/' + file_name
if not os.path.exists(new_write_path):
os.makedirs(new_write_path)
modify_f(sub_path, new_write_path)# startmodify_f(my_path, my_write_path)
# -*- coding: utf-8 -*-#批量修改类名字 importosimportreimportstringimportstring my_path="/Users/jasper/Desktop/pure/GPUImage1.0.7"my_write_path='/Users/jasper/Desktop/pure/new' target="GPU"replace="WKU" target2="GLProgram"replace2="GLWKProgram" dict=/
"dataProviderReleaseCallback":"dataWKProviderReleaseCallback",
"dataProviderUnlockCallback":"dataWKProviderUnlockCallback",
"kColorConversion601":"kWKColorConversion601",
"kColorConversion601FullRange":"kWKColorConversion601FullRange",
"kColorConversion709":"kWKColorConversion709",
"runAsynchronouslyOnVideoProcessingQueue":"runWKAsynchronouslyOnVideoProcessingQueue",
"runSynchronouslyOnContextQueue":"runWKSynchronouslyOnContextQueue",
"runSynchronouslyOnVideoProcessingQueue":"runWKSynchronouslyOnVideoProcessingQueue",}
defmodify_f(f_path,write_path):
files=os.listdir(f_path)
forfinfiles:
# 忽略掉杂项
iff[0]==".":
sub_path=f_path+'/'+f
file_name=f.replace(target,replace)
file_name=file_name.replace(target2,replace2)
ifos.path.isfile(sub_path):
new_write_path=write_path+'/'+file_name
lines=open(sub_path,'r').readlines()
f_len=len(lines)-1
foriinrange(f_len):
lines[i]=lines[i].replace(target,replace)
lines[i]=lines[i].replace(target2,replace2)
forkeyindict.keys():
lines[i]=lines[i].replace(key,dict[key])
open(new_write_path,'w').writelines(lines)
# 是目录 则 递归
new_write_path=write_path+'/'+file_name
ifnotos.path.exists(new_write_path):
os.makedirs(new_write_path)
modify_f(sub_path,new_write_path) # startmodify_f(my_path,my_write_path)
不仅类名可能重复,C 或者shader 的定义也会重复。
最新教程周点击榜
微信扫一扫主题 : 两个第三方库冲突,怎么弄?duplicate symbol _base64_encode
级别: 侠客
可可豆: 776 CB
威望: 776 点
在线时间: 291(时)
发自: Web Page
两个第三方库冲突,怎么弄?duplicate symbol _base64_encode&&&
duplicate symbol base64encode in: ./TencentOpenAPI/TencentOpenAPI.framework/TencentOpenAPI(base64.o) ./ZBarSDK/libzbar.a(symbol.o)ld: 1 duplicate symbol for architecture i386clang: error: linker command failed with exit code 1 (use -v to see invocation)一个是腾讯分享,一个是条码扫描。看网上说可以合并两个库,谁有合并完的?或者改了的(libzbar.a)?能共享一份不?改_all_load不好使。
级别: 侠客
可可豆: 776 CB
威望: 776 点
在线时间: 291(时)
发自: Web Page
ZBarSDK 的源代码什么地方可以下载???
级别: 侠客
可可豆: 776 CB
威望: 776 点
在线时间: 291(时)
发自: Web Page
下载到了ZBarSDK原代码,可是里面并没有找到 _base64_encode。。可能是symbol.c引用来其他东西吧。。这回麻烦可大了。。 怎么解决这个问题呀???
级别: 新手上路
可可豆: 107 CB
威望: 59 点
在线时间: 206(时)
发自: Web Page
Lz解决了吗? 我也遇到了同样的问题i
级别: 侠客
可可豆: 776 CB
威望: 776 点
在线时间: 291(时)
发自: Web Page
回 3楼(4656587) 的帖子
下载源代码,改。。。
级别: 圣骑士
UID: 65410
可可豆: 1851 CB
威望: 1660 点
在线时间: 918(时)
发自: Web Page
Re:回 3楼(4656587) 的帖子
引用 引用第4楼freecunix于 02:59发表的 回 3楼(4656587) 的帖子 :下载源代码,改。。。 不用这么麻烦,直接打开库文件,把符号改成另外一个名字。
上善若水,无欲则刚
关注本帖(如果有新回复会站内信通知您)
苹果公司现任CEO是谁?2字 正确答案:库克
发帖、回帖都会得到可观的积分奖励。
按"Ctrl+Enter"直接提交
关注CocoaChina
关注微信 每日推荐
扫一扫 浏览移动版使用OC runtime解决第三方库冲突且依赖库版本不同 - 简书
使用OC runtime解决第三方库冲突且依赖库版本不同
摘要OC runtime真是一个强大的东西,这次解决了第三方库的冲突问题
前几天在iOS app项目中添加了几个第三方库,各有各的用处,因为一些原因,有些库是不开源的。
添加后,发现app编译不通过,错误如下:
从错误描述中都能看出,app在连接过程中,发现了一些重复的符号,即同样的OC类和方法在不同的库中都有实现:liblibPDRCore.a和libsimpleconfiglib.a这两个库有冲突!恰好,这两个库都要用,而且都不开源,仿佛一下子就走进了死胡同,因为没有办法修改这两个库。
网上搜了一下,碰到这种问题的人还真不少,也提出了解决方案:用lipo命令分解其中一个类,删除重复的符号,再用ar命令重新打包成库,我选择修改liblibPDRCore.a这个库:
1.查看包信息:lipo -info liblibPDRCore.a,提示fat file,那么代表这个包是支持多平台的,例如armv7,armv64等
2.取出armv7包:lipo liblibPDRCore.a -thin armv7 -output armv7/liblibPDRCore_armv7.a
3.解压出object file(.o文件):cd armv7&ar xv liblibPDRCore_armv7.a
4.根据出错信息删除PDRSerAsyncSocket.o:rm PDRSerAsyncSocket.o
5.重新打包:ar rcs liblibPDRCore_armv7.a *.o,记得把旧的库删掉
6.重复1-5把arm64什么的一起改了
7.合并为fat库:lipo -create liblibPDRCore_armv7.a liblibPDRCore_arm64.a -output liblibPDRCore.a
好了,现在用新和成的库替换,并编译,发现编译成功了!
且慢!这和主题OC runtime有什么关系?只是用一些工具去掉了重复符号!
是的,确实没有关系,下面才正式进入主题!
编译是成功了,但实际运行起来呢?非常抱歉,crash了,错误如下:
原因可能是:这两个库虽然有一个名字一样的OC类,有些方法也一样,但并不是完全一样,可以认为,这两个库依赖了另一个开源库,但不是同一个版本,仿佛又走进死胡同鸟!
仔细分析了一些出错信息:liblibPDRCore.a某个地方调用了AsyncSocket类的方法acceptOnAddress:port:error:,但libsimpleconfiglib.a中的AsyncSocket却没有这个方法,造成调用异常。
现在轮到OC runtime上场了,我也只是抱着试一试的态度。前段时间正好看这方面内容,了解到OC可以在运行时动态增加、替换一些类的方法,解决一些实际问题。现在我想到一个思路:用一个空函数,替代AsyncSocket类的方法acceptOnAddress:port:error:,看是否正常运行
1.先获取类类型:Class _asyncSocketClass = NSClassFromString(@"AsyncSocket");
2.给AsyncSocket类添加方法:class_addMethod(_asyncSocketClass, NSSelectorFromString(@"acceptOnAddress:port:error:"), IMP, types);,这个函数中,后面两个参数,一个是替换方法,一个是方法参数类型,替换方法参数好搞,直接定义一个C格式的函数,传函数指针即可;方法参数类型怎么弄?
于是,我想到了从libsimpleconfiglib.a库中找一些蛛丝马迹,虽然它和liblibPDRCore.a使用了不同版本的AsyncSocket类,但某些方法应该是类似的,获取可以帮我完成函数class_addMethod所需的最后一个参数
3.用lipo和ar命令获得libsimpleconfiglib.a中的object file:"AsyncSocket.o"
4.查看"AsyncSocket.o"的导出符号:nm AsyncSocket.o,果不其然,发现一个类似的,方法名不同,参数名却一样
5.再看一下liblibPDRCore.a库中的PDRSerAsyncSocket.o的导出符号,确实有"acceptOnAddress:port:error:"这个方法,我们知道,这个目标文件已经被我们去掉了
6.从名称上判断,这两个方法参数一样,而且方法acceptOnInterface确实存在,用method_getTypeEncoding来获取方法的类型即可得到class_addMethod的最后一个参数,用有了这个思路,完成了如下代码:
void impfunc(Class cls, SEL _cmd){
if([NSStringFromSelector(_cmd) isEqualtoString:@"acceptOnAddress"])
//调用cls的acceptOnInterace的方法
}}- (BOOL)application:...{
Class _asyncSocketClass = NSClassFromString(@"AsyncSocket");
Method _acceptOnInterface = class_getInstanceMethod(_asyncSocketClass,
NSSelectorFromString(@"acceptOnInterface:port:error:"));
class_addMethod(_asyncSocketClass, NSSelectorFromString(@"acceptOnAddress:port:error:"),
(IMP)impfunc, method_getTypeEncoding(_acceptOnInterface));
7.编译并运行起来之后,确实走到了impfunc,程序也不崩溃了,但相关的功能不正常,我想还是要真正调用一下acceptOnInterface这个方法才行
8.我想到了解析_cmd的参数,取出参数值,然后再调用objc_msgSend发送消息,尝试了很多方法,没有成功;实际上,我还是走了弯路,各位应该也看出来了,class_addMethod的第三个参数,直接用acceptOnInterface的实现不就行了!method_getImplementation可以帮我们做到,于是代码变成如下,编译后运行,成功了!
(BOOL)application:...{
Class _asyncSocketClass = NSClassFromString(@"AsyncSocket");
Method _acceptOnInterface = class_getInstanceMethod(_asyncSocketClass,NSSelectorFromString(@"acceptOnInterface:port:error:"));
class_addMethod(_asyncSocketClass,
NSSelectorFromString(@"acceptOnAddress:port:error:"),
method_getImplementation(_acceptOnInterface ),
method_getTypeEncoding(_acceptOnInterface));
9.没有了,散会1309人阅读
iOS(145)
解决TencentOpenAPI.framework与ZbarSDK中&&_base64_encode 函数的冲突
后来在网络上搜寻,删除掉 Other Linker Flag 的&-all_load 就可以解决静态库冲突的问题,
但是这样做的话,会使一些外部的静态库,使用objc扩展函数(catagory)的方法失效。例如BaiduMapApi
如果是有些库使用到了扩展函数(catagory)可以分别对这个库进行加载
使用:-force_load
-force_load BaiduMapApi/libs/Release-iphoneos/libbaidumapapi.a
(BaiduMapApi是添加到当前目录下的)
-force_load $(BUILT_PRODUCTS_DIR)/libxxx.a
(这里是直接添加静态库项目源码的做法)
使用-force_load分别进行加载还是蛮方便的,如果有些函数加入了main函数使用all_load就相当麻烦了。
以上可以解决TencentOpenAPI.framework与ZbarSDK的冲突
如果两个静态库冲突的结构是相同的,可以考虑将两个静态库拆分出来进行合并。
查看文件的架构有哪些
$&lipo -info libzbar.a
Architectures in the fat file: libzbar.a are: armv7 (cputype (12) cpusubtype (11)) i386&
将armv7解压出来
lipo libzbar.a -thin armv7 -output libzbar-armv7.a
新建立一个文件夹出来存放解压的(.o)文件
$ mkdir armv7
$ cd armv7
将静态库中的文件解压
$ ar -x ../libzbar-armv7.a
然后将另一个静态库根据以上的步骤做一遍,然后观察连个解压的静态库中,有那些是一样的就合并在一起,不过注意的是两个静态库冲突的(.o)文件必须一致,否则也会出现错误。
合并完后进行打包了
$ libtool -static -o ../libnew-armv7.a *.o
如果像在虚拟机也使用,进行相同的步骤后,将i386的架构合并再一起就可以了。
合并静态库
$ lipo -create -output lib.a&libnew-armv76.a libi386.a
解决TencentOpenAPI.framework与ZbarSDK中&&_base64_encode 函数的冲突
后来在网络上搜寻,删除掉 Other Linker Flag 的&-all_load 就可以解决静态库冲突的问题,
但是这样做的话,会使一些外部的静态库,使用objc扩展函数(catagory)的方法失效。例如BaiduMapApi
如果是有些库使用到了扩展函数(catagory)可以分别对这个库进行加载
使用:-force_load
-force_load BaiduMapApi/libs/Release-iphoneos/libbaidumapapi.a
(BaiduMapApi是添加到当前目录下的)
-force_load $(BUILT_PRODUCTS_DIR)/libxxx.a
(这里是直接添加静态库项目源码的做法)
使用-force_load分别进行加载还是蛮方便的,如果有些函数加入了main函数使用all_load就相当麻烦了。
以上可以解决TencentOpenAPI.framework与ZbarSDK的冲突
如果两个静态库冲突的结构是相同的,可以考虑将两个静态库拆分出来进行合并。
查看文件的架构有哪些
$&lipo -info libzbar.a
Architectures in the fat file: libzbar.a are: armv7 (cputype (12) cpusubtype (11)) i386&
将armv7解压出来
lipo libzbar.a -thin armv7 -output libzbar-armv7.a
新建立一个文件夹出来存放解压的(.o)文件
$ mkdir armv7
$ cd armv7
将静态库中的文件解压
$ ar -x ../libzbar-armv7.a
然后将另一个静态库根据以上的步骤做一遍,然后观察连个解压的静态库中,有那些是一样的就合并在一起,不过注意的是两个静态库冲突的(.o)文件必须一致,否则也会出现错误。
合并完后进行打包了
$ libtool -static -o ../libnew-armv7.a *.o
如果像在虚拟机也使用,进行相同的步骤后,将i386的架构合并再一起就可以了。
合并静态库
$ lipo -create -output lib.a&libnew-armv76.a libi386.a
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:80363次
积分:1091
积分:1091
排名:千里之外
转载:144篇
(6)(3)(3)(6)(6)(8)(33)(16)(27)(9)(30)(6)

我要回帖

更多关于 python 第三方库 的文章

 

随机推荐