xcode中接入第三方库,导致duplicate symbol报错

本文记录了在Xcode项目中接入第三方库时遇到的duplicate symbol错误及解决过程。首先尝试拆分静态库,但发现framework与静态库结构不同;接着排除系统库冲突的可能性;最后通过分析Demo和项目代码,发现是另一个第三方库引入了相同符号,移除相关代码后问题解决。
【xcode中接入第三方库,导致duplicate symbol报错】
duplicate symbol _OBJC_CLASS_$_SBJSON in:
    /Users/cldeer/Library/Developer/Xcode/DerivedData/FarmDay-fkwjxaxxooyqhigfylsjjxtgahkg/Build/Intermediates/FarmDay.build/Debug-iphoneos/FarmDay.build/Objects-normal/arm64/SBJSON.o
    /Users/cldeer/Documents/cocos2d-x-2.2.6/projects/FarmDay/proj.ios/Shephertz_App42_iOS_API.framework/Shephertz_App42_iOS_API
【尝试一】
网上比较普遍的做法是将静态库拆分为最小的obj文件,然后删除重复的obj,最后再重新打包
farmework虽然不是静态库,可以尝试一下
1、先找到第三方库文件(或framework),查看其支持的平台
cldeerdeMac-mini:A cldeer$ lipo -info Shephertz_App42_iOS_API 
Architectures in the fat file: Shephertz_App42_iOS_API are: i386 x86_64 armv7 arm64
2、分离出某个单独框架
cldeerdeMac-mini:A cldeer$ lipo -extract_family armv7 -output libv7.a Shephertz_App42_iOS_API
3、将单个框架的库解压,生成.o文件
cldeerdeMac-mini:A cldeer$ ar -x libv7.a 
ar: libv7.a: Inappropriate file type or format
【新问题】分解的库文件无法拆散,折腾好久才发现framework文件跟一般的静态库文件不同
这个是framework分解下来的non-fat库:
cldeerdeMac-mini:A cldeer$ file libv7.a 
libv7.a: Mach-O object arm
这个是静态库分解下来的non-fat库:
cldeerdeMac-mini:v7 cldeer$ file libv7.a 
libv7.a: current ar archive random library
zone.o是静态库分解下来的静态库再次分解产生的:
cldeerdeMac-mini:v7 cldeer$ file zone.o 
zone.o: Mach-O object arm
这个发现说明farmework分解下来的non-fat库跟普通静态库结构不同,直接就是最小单元了
4、到了这里,通过拆开库文件再次打包(libtool)的思路基本被堵死了
【尝试二】
由于代码中没有用到SBJSON.o而且在arm64目录下,断定是系统库所有
(大误区:普通代码生成的object文件就放在这个目录下,如果不是这个误解,问题应该开始【尝试一】早解决了)
App42使用比较广,如果是因为跟系统库冲突,官网上面应该有不少信息
不过最终在上面没找到任何相关的信息
【尝试三】
App42提供了Demo,可以看一下是不是有问题,如果有问题,就可以到官网上请求帮助了
运行Demo后,发现并没有问题(猜测可能是FarmDay工程支持了64位编译导致的)
查看Demo的工程文件,发现也是默认支持64位编译的,应该是之前的判断有问题了
最后检查一下FarmDay的工程文件,在IAP支付的代码中看到了SBJSON一系列的身影,
原来是另外一个第三方库也使用了这些对象,直接把相关代码从工程中移除。
重新编译,OK了
【总结】
这个问题有一定侥幸,如果真的是两个第三方framework冲突,估计要哭起来了
### 三级标题:Xcode C++运行时出现 `duplicate symbol` 错误的原因与解决方法 在使用 Xcode 编译 C++ 程序时,出现 `duplicate symbol` 错误通常意味着链接器在多个目标文件中发现了相同的符号定义。这类错误常见于多文件项目或引入了第三方库的项目中。以下是可能导致该错误的原因及对应的解决方法。 #### 1. **重复定义全局变量或函数** 当多个源文件中定义了相同名称的全局变量或函数时,链接器无法确定使用哪一个定义,从而导致重复符号错误。例如,两个 `.cpp` 文件中都定义了相同的全局函数或变量。 **解决方法:** - 如果是全局变量,确保其仅在单个源文件中定义,并在头文件中使用 `extern` 声明。 - 如果是函数,确保其没有在多个源文件中重复定义。若需共享函数实现,应将其定义放在一个 `.cpp` 文件中,并在头文件中声明[^2]。 #### 2. **头文件中定义了函数体或变量** 在头文件中直接定义函数体或变量会导致包含该头文件的所有源文件都生成相同的符号,从而引发重复符号错误。 **解决方法:** - 将函数的声明和定义分离,函数体应放在 `.cpp` 文件中。 - 如果必须在头文件中定义函数(如 `inline` 函数),则应使用 `inline` 关键字修饰该函数,以避免重复定义问题[^2]。 #### 3. **多个源文件中定义了 `main` 函数** 在 C++ 程序中,`main` 函数是程序的入口点。如果项目中存在多个 `main` 函数定义,链接器将无法确定使用哪一个,从而报错。 **解决方法:** - 检查项目中的所有 `.cpp` 文件,确保只有一个 `main` 函数存在。 - 如果使用了多个可执行目标(如多个测试文件),应为每个目标配置独立的构建目标或使用条件编译控制 `main` 函数的编译路径[^4]。 #### 4. **重复导入源文件** 在 Xcode 项目中,如果错误地将 `.cpp` 或 `.h` 文件多次添加到目标的“编译源”列表中,链接器将处理多个相同的符号定义。 **解决方法:** - 打开项目设置,检查“Build Phases”下的“Compile Sources”部分,确保每个源文件只出现一次。 - 如果使用了拖拽方式导入文件,确认未重复添加相同的文件到项目中[^2]。 #### 5. **静态库或框架之间的符号冲突** 如果项目中使用了多个静态库(`.a` 或 `.framework`),而这些库中存在相同名称的符号定义,链接器也会报出 `duplicate symbol` 错误。 **解决方法:** - 检查错误信息中提到的符号来源,确认冲突是否来自第三方库- 如果冲突来自两个静态库,尝试移除其中一个库或使用 `-ObjC` 和 `-framework` 链接标志进行调整。 - 在某些情况下,可以使用 `nm` 命令检查目标文件或库中的符号表,帮助定位重复符号[^1]。 #### 6. **使用 `#import` 替代 `#include` 避免重复包含** 在 Objective-C/C++ 混合编程项目中,使用 `#include` 导致头文件被多次包含,可能间接导致重复定义问题。 **解决方法:** - 在 Objective-C/C++ 混合项目中,建议使用 `#import "Header.h"` 替代 `#include "Header.h"`,以避免重复包含头文件。 - 如果使用纯 C++,可在头文件中使用 `#ifndef` / `#define` / `#endif` 宏保护机制防止重复包含。 --- ### 示例:检查重复定义的 `main` 函数 ```cpp // main.cpp #include <iostream> int main() { std::cout << "Hello World" << std::endl; return 0; } ``` ```cpp // test.cpp #include <iostream> int main() { // 这里重复定义了 main 函数,将导致链接错误 std::cout << "Test" << std::endl; return 0; } ``` 上述代码中,`main` 函数在两个 `.cpp` 文件中同时定义,编译时将报出 `duplicate symbol _main` 错误[^4]。 --- ### 示例:使用 `inline` 避免头文件中函数重复定义 ```cpp // Utility.h #ifndef UTILITY_H #define UTILITY_H inline void printMessage() { std::cout << "This is an inline function." << std::endl; } #endif // UTILITY_H ``` ```cpp // main.cpp #include "Utility.h" int main() { printMessage(); return 0; } ``` ```cpp // test.cpp #include "Utility.h" void testFunction() { printMessage(); } ``` 由于 `printMessage()` 是 `inline` 函数,即使在多个源文件中包含 `Utility.h`,也不会导致重复符号错误。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值