解决 iOS 第三方 SDK 之间重复的 symbols 问题

本文详细记录了解决iOS模拟器上出现的82个DuplicateSymbols问题的过程。通过使用lipo、nm、strip、ar和ld等工具,成功移除了导致冲突的符号。

来源:NEWWORLD

链接:http://www.jianshu.com/p/e857730015cf


前言:今天公司项目准备使用高德导航,其中用到了高德3D地图SDK,然后就出现bug了。在真机上可以完美运行,但是在模拟器上,就出现了一大片的bug:提示有82个Duplicate symbols,仔细一看是MobileVLCKit和高德的MAMapKit之间的问题。(PS:今天是真心累啊,不过解决了bug,还是很值得的。)




现在,我就今天踩过的坑,做个简单的整理,以备以后翻看。 也希望以后遇到类似坑的小伙伴们,可以有些许启发和不同见解。




问题描述及猜想





上图为部分报错内容。两个第三方SDK之间在某些特定平台存在一些duplicate symbols。分析:那是不是除掉其中一个SDK中相应平台上,重复的那部分symbols,是不是就解决问题了呢?且继续向下看。




解决问题




通过查找资料,各种扒论坛,终于发现,跟我一起踩坑的小伙伴们还真不少。

然后通过借鉴他们的经验,在对linux的相关语法实在小白的情况下,终于解决问题了,好感动啊!!!




工具介绍




lipo


lipo是管理Fat File的工具, 可以查看平台列表, 提取特定平台, 重新打包。


nm


nm用来显示一个程序包的符号表, 默认会显示入口地址, 符号类型, 符号名。


strip


strip用来删除程序里的符号表。-R 用来指定一个要删除的符号列表, 使用上述生成的symbols文件.。添加 -S 选项来保留其他符号。


ar


ar可以查看一个程序包里的对象文件列表, 解压出其中的对象文件并重新打包。


ld


ld苹果系统下的链接器, 可以更精确的控制符号表的导出。




具体步骤




因为担心修改MobileVLCKit对已上线的视频播放造成不可估计的影响,因此,此次修改MAMapKit,出现任何bug也可以尽快发现并解决。

下面将进行十分小白式的记录(PS:主要是我太小白了。)


cd path(framework的路径)

lipo -info MAMapKit



lipo info MAMapKit


查看MAMapKit的适用平台,可以发现arm7,i386,x86_64,arm64均可用。并且前面bug只是存在于x86_64平台上,那么就先修改这个平台的内容。


lipo -thin x86_64 MAMapKit -output MAMapKit.x86_64


文件瘦身,提取x86_64平台的MAMapKit到新的文件MAMapKit.x86_64,发现该文件只有3M而已(源文件20.2M),该文件位置与MAMapKit相同,发现确实单个平台的文件比较小。


nm -j MAMapKit.x86_64  | grep png > symbols


  • 获取MAMapKit.x86_64文件中以_png为前缀的所有符号,生成符号列表并存于symbols文件中。( -j 选项控制只输出符号名)

  • 因为上面的symbols内容不是上述bug中包含的内容,因此,需要更改该symbols文件,删除里面所有符号,将报错的所有重复符号


_png_do_invert

_png_set_shift

_png_get_user_transfom_ptr

...


这些符号依次输入到该文件中,每行一个。这就将本次需要删除的符号存在符号列表中了。


ar -t MAMapKit.x86_64



ar -t MAMapKit.x86_64


可以发现整个包中就一个主要文件MAMapKit-x86_64-master.o文件,这也是前面bug中提到的重名符号所在的位置。(PS:更确定找对了方法)



Duplicate symbols path


ar -x MAMapKit.x86_64



MAMapKit.x86_64 File Path


可以发现多出了三个文件,也获得了需要的MAMapKit-86_64-master.o文件。


ld -x -r -unexported_symbols_list symbols MAMapKit-x86_64-master.o -o MAMapKit-x86_64-master.o.strip


可以将symbols文件中的符号列表在MAMapKit-x86_64-master.o文件中删除掉,并生成一个新的文件MAMapKit-x86_64-master.o.strip。


ar -r MAMapKit.x86_64 MAMapKit-x86_64-master.o.strip Pods-MAMapKit-dummy.o


  • 在执行此命令之前,可以将前面获得MAMapKit.x86_64文件放在其他位置作为对比。

  • 然后通过该命令得到一个新打包好的x86_64平台包。

  • 也可以用以前的获取symbols的方式从这个新包中获取相应的_png的所有符号表,查询刚才需要删除的符号,验证那些符号是否已被删除。(很高兴确实已经删除了,这下问题应该可以解决了吧。)


下面将替换原有包中的x86_64平台包。(该文件中只修改了x86_64平台的内容)


lipo MAMapKit -replace x86_64 MAMapKit.x86_64 -output MAMapKitTest


用上面生成的新包替换MAMapKit包中的x86_64平台包,然后生成一个新的文件包,最后将旧的MAMapKit包移除,其他多余内容也一并移除,将MAMapKitTest更名为MAMapKit。至此,MAMapKit.framework看起来跟原来的没有什么区别了。(看事情不能只看表面哦,咱修改的是内在!)


多余的话:如果修改多个平台的包(因为我只需要修改x86_64这一个平台包),可能需要重新生成一个新包更合适。


  • 根据前面的方法,生成每个平台的新包;

  • 将所有新包对应各个平台,生成一个新包。



合成新包


上图红色标记即最后的合成新包方法。在此之前记得将前面更改过的x86_64平台包拷贝到这些包的相同路径下。


最后重新编译工程,就这么完美解决了!!!这一刻的感觉,太激动了。暂时未发现有什么问题,以后有什么由此衍生的bug,到时候再更新了。也希望小伙伴们共同学习,有问题大家一定要指出来哟!欢迎大家找我交流问题一起进步哦。




感谢下面两位大神踩过的坑,有了它们的经验,才让我如此顺利的解决问题!

  • [1]Mac系统下lipo, ar, nm等工具的使用简介

    http://www.bubufx.com/detail-1574404.html

  • [2]Lipo – 如何为ARMv7/ARMv7s/ARM64架构 创建通用文件(Universal Files)]

    http://blog.youkuaiyun.com/volvet/article/details/50097563

<think>好的,用户现在希望在iOS上使用GNU Scientific Library (GSL)。之前用户询问过关于GSL静态库架构的问题,现在可能需要将GSL集成到iOS项目中。我需要回顾之前的对话,确保提供的解决方案适用于iOS开发环境。 首先,用户之前在macOS上使用Homebrew安装的GSL库是arm64架构的静态库,但用户现在转向iOS开发。iOS应用通常需要支持多种架构,尤其是当涉及到设备(如iPhone和iPad)和模拟器时。因此,用户可能需要构建一个支持iOS架构的GSL库,或者找到一个预编译的框架。 接下来,我需要考虑iOS开发的具体需求。iOS应用通常使用Xcode,依赖库需要打包成Framework或者通过CocoaPods等依赖管理工具集成。GSL是一个C库,因此在iOS项目中可能需要编译为静态库或动态库,并支持arm64(设备)、x86_64(模拟器)等架构。 用户可能已经尝试过直接使用Homebrew安装的库,但发现架构不兼容。因为Homebrew的库是为macOS编译的,而不是iOS,所以需要指导用户如何为iOS交叉编译GSL。 我需要分步骤解释如何从源代码编译GSL,支持iOS的架构。可能涉及设置正确的编译工具链、配置编译选项,以及使用脚本自动化构建过程。此外,还需要提醒用户注意Xcode项目的配置,确保头文件路径和库链接正确。 另外,用户可能需要了解如何将编译后的库集成到Xcode项目中,包括设置Header Search Paths和Library Search Paths,以及添加链接库。如果用户不熟悉这些步骤,可能需要详细说明。 最后,需要检查是否有其他可能性,比如使用CocoaPods或Swift Package Manager来简化集成过程,但目前GSL可能没有官方维护的Pod,所以从源码编译可能是更可行的方案。 总结下来,回答需要包括以下内容: 1. 编译GSL为iOS支持的架构。 2. 创建Xcode Framework。 3. 集成到iOS项目的步骤。 4. 注意事项和常见问题解决。 5. 替代方案(如CocoaPods等)。 需要确保步骤清晰,代码示例准确,并提醒用户可能需要调整版本号或路径。同时,检查是否所有命令适用于最新的Xcode和iOS版本,避免过时的指令。</think>--- ### **一、iOS 使用 GSL 的核心挑战** GNU Scientific Library (GSL) 是 C/C++ 编写的科学计算库,要在 iOS 项目中直接使用需解决以下问题: 1. **架构兼容性**:需支持 iOS 设备(`arm64`)和模拟器(`x86_64`)。 2. **编译工具链**:需使用 iOS SDK 和 Clang 编译器,而非 macOS 原生工具链。 3. **静态库封装**:需生成 iOS 可用的静态库(`.a`)或动态库(`.framework`)。 --- ### **二、详细实现步骤** #### **步骤 1:下载 GSL 源码** ```bash # 下载最新源码(替换为实际版本号) curl -LO https://ftp.gnu.org/gnu/gsl/gsl-2.8.tar.gz tar xzf gsl-2.8.tar.gz cd gsl-2.8 ``` #### **步骤 2:配置 iOS 编译环境** 创建编译脚本 `build-ios.sh`,内容如下: ```bash #!/bin/bash # 定义 iOS 支持的架构 ARCHS=("arm64" "x86_64") IOS_SDK_VERSION=$(xcrun --sdk iphoneos --show-sdk-version) OUTPUT_DIR="$(pwd)/ios-build" # 清理旧文件 rm -rf $OUTPUT_DIR mkdir $OUTPUT_DIR # 逐架构编译 for ARCH in ${ARCHS[@]}; do # 设置编译参数 if [ "$ARCH" = "arm64" ]; then SDK="iphoneos" HOST="aarch64-apple-darwin" else SDK="iphonesimulator" HOST="x86_64-apple-darwin" fi # 配置编译目录 BUILD_DIR="build-ios-$ARCH" mkdir $BUILD_DIR && cd $BUILD_DIR # 运行 configure 和 make ../configure \ --host=$HOST \ --prefix="$OUTPUT_DIR/$ARCH" \ CC="clang -arch $ARCH -isysroot $(xcrun --sdk $SDK --show-sdk-path)" \ CXX="clang++ -arch $ARCH -isysroot $(xcrun --sdk $SDK --show-sdk-path)" \ CFLAGS="-Os -fembed-bitcode" \ CXXFLAGS="-Os -fembed-bitcode" make -j8 && make install cd .. done # 合并多架构静态库 lipo -create \ "$OUTPUT_DIR/arm64/lib/libgsl.a" \ "$OUTPUT_DIR/x86_64/lib/libgsl.a" \ -output "$OUTPUT_DIR/libgsl-universal.a" echo "编译完成!输出文件:$OUTPUT_DIR/libgsl-universal.a" ``` #### **步骤 3:执行编译** ```bash # 添加执行权限 chmod +x build-ios.sh # 运行脚本 ./build-ios.sh ``` #### **步骤 4:集成到 Xcode 项目** 1. **添加库文件**: - 将生成的 `libgsl-universal.a` 和头文件目录 `ios-build/arm64/include/gsl` 拖入 Xcode 项目。 2. **配置 Xcode 工程**: - **Build Settings → Header Search Paths**:添加 `$(PROJECT_DIR)/path/to/gsl-headers`。 - **Build Settings → Other Linker Flags**:添加 `-lgsl -lgslcblas`。 - **Build Settings → Architectures**:确保包含 `arm64` 和 `x86_64`。 --- ### **三、验证与调试** 1. **代码测试**: ```c #include <gsl/gsl_sf_bessel.h> void test_gsl() { double x = 5.0; double y = gsl_sf_bessel_J0(x); printf("J0(%g) = %g\n", x, y); } ``` - 编译运行,若输出 `J0(5) = -0.177597` 则成功。 2. **常见错误处理**: - **Undefined symbols**:检查库文件是否正确链接,架构是否匹配。 - **Header not found**:确认头文件搜索路径是否包含 GSL 头文件目录。 --- ### **四、替代方案(推荐)** #### **方案 1:使用 CocoaPods** 如果存在第三方维护的 GSL Pod(需自行搜索): ```ruby # Podfile pod 'GSL', :git => 'https://github.com/第三方仓库/GSL-iOS.git' ``` #### **方案 2:预编译 Framework** 手动创建 `GSL.framework`: ```bash # 合并头文件 mkdir -p GSL.framework/Headers cp -R ios-build/arm64/include/gsl/* GSL.framework/Headers/ # 生成 Framework 结构 cp ios-build/libgsl-universal.a GSL.framework/GSL # 生成 Info.plist(需手动填写) ``` --- ### **五、注意事项** 1. **Bitcode 支持**:编译时需添加 `-fembed-bitcode` 以支持 App Store 提交。 2. **更新维护**:GSL 源码更新后需重新编译。 3. **性能优化**:根据需求调整 `CFLAGS`(如 `-O3` 优化)。 --- 如果需要更具体的 Xcode 工程配置示例或遇到编译错误,请提供详细日志!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值