导入第三方库编译错误总结
项目最新版本引入了VR拍照相关静态库,编译时遇到一些错误,现做下总结:
- 将静态库拖入项目后,编译报错:
xxx.h file not found
这个是比较常见的错误,一般这个错误可以在Build Settings中设置Framework Search Paths解决。但我检查了项目中相关的设置,确认都是正常的,后来发现是我在将静态库拖入项目中时忽略了一点:
往项目中加文件时,会有以下选项:
Destination和Add to targets选项基本都是可以确定的;Added folders的两个选项有什么区别呢?
- Create groups ,为任何新增加的文件夹创建组,他添加的文件夹对应的工程目录和文件路径不一定是一一对应的。你可以删除文件,也可以删除文件对应的本地文件。这种方式添加的文件夹都是黄色的。当你想要使用文件夹中的某个类的头文件时,你可以直接添加它的引用,例如#import xxx.h,因为groups下的文件是会被编译的。
- Create folder references :这种方法是建立一个文件夹的索引,同时文件夹中的所有文件也会添加到整个工程。他添加的文件夹对应的工程目录和文件路径是一一对应的。你要删除其中的文件的话可以直接到文件目录下把文件删除,然后再刷新一下目录,文件就会被删除了。这种方式添加的文件夹是蓝色的。同时使用Create folder references方法只是将文件单纯的创建了引用,这些文件不会被编译,所以在使用的时候需要加入其路径,比如在我们想要使用Framework文件夹下面某个头文件,则需要按照下面的方法添加声明:#import Framework/xxx.h,否则编译器就会告诉你找不到xxx.h文件。
将报错的库删除,然后重新导入选择Create groups后编译通过。
- 相关功能需要使用opencv,在加入opencv2.framework后,编译报错:
duplicate symbols
后来发现项目中Build Settings中Other Linker Flags加了-all_load, 然后使用-force_load替换-all_load编译通过。
常用的3个flag:-all_load,-force_load,-ObjC,区别如下:
- -ObjC,Unix的标准静态库实现和Objective-C的动态特性之间有一些冲突:Objective-C没有为每个函数(或者方法)定义链接符号,它只为每个类创建链接符号。这样当在一个静态库中使用类别来扩展已有类的时候,链接器不知道如何把类原有的方法和类别中的方法整合起来,就会导致你调用类别中的方法时,出现”selector not recognized”,也就是找不到方法定义的错误。为了解决这个问题,引入了-ObjC标志,它的作用就是将静态库中的类和category都加载进来。
- -all_load,这个flag是专门处理-ObjC的一个bug的。用了-ObjC以后,如果类库中只有category没有类的时候这些category还是加载不进来。变通方法就是加入-all_load。-all_laod会强制链接器把目标文件都加载进来,即使没有objc代码。但是这样在导入多个.a文件的时候,可能会导致你的目标程序大小增大,而且往往容易引起一些冲突,而这些冲突往往你无法解决(常常出现在你链接的各种库中)。
- -force_load,只加载你方法所需要的库不需再添加-ObjC,可以解决上面两个问题,但是使用它需要再添加.a文件的路径。(-force_load$(PROJECT_DIR)/路径 )
- 由于引入相关静态库后,某些地方需要使用C++。在混编时编译报错:
file not found
因为要支持C++编译,我将Complie Sources As设置为Objective-C++:
Objective-C++再度编译,OC的运行时方法全报错:
11最后的解决方法还是将Complie Sources As设置为According to File Type;看字面意思就能理解,这个选项是根据文件类型选择编译类型。因此将引用了C++文件的.m文件后缀改为.mm即可兼容OC和C++。一般引用C++文件地方很多,如果将这些文件都改为.mm后缀也是比较麻烦。所以这时需要封装一个OC类,这个类专门处理有关C++的事情。其他文件只要引用这个OC类即可(这个类引用C++头文件时一定要在.m文件中引用,如果在.h文件中引用,所有引用了这个OC类的文件同样还是会报file not found错误。)
- 切换至模拟器编译报错:
undefined symbols
后来查看了下该静态库支持的架构,发现没有支持x86_64架构,联系静态库的开发者重新打包后就可以了。
查看静态库支持的架构方法如下:
终端命令cd到库所在路径,然后执行lipo -info命令,就能看到支持的架构了。