iOS开发中,经常会遇到静态库冲突的问题, xcode报错关键词是duplicate symbol xxx;造成冲突的常见原因一般有两种

  1. 项目xcode是什么软件中引入了命名不同的同一个静态库

以openssl为例 同一份源码打包生成libopenssl.a 和openssl.ios系统a 两份静态库,引入到项目中时, 会报错

上文提到造成冲突的原因是引入不同名字的同一个静态库, 为什么同名的不会冲突呢?

这里其实是编译器对同名静态库的链接做了优化防止冲突,具体优化思路是编译器进行符iOS号链接时如果已经绑定了一个静态库, 则后续同名静态库不会再链接,测试抑郁症 这里针对的默认场景架构师工资下的, 如果修改了xcode bu测试抑郁症的20道题ild settinios14.4.1更新了什么g下的other linker flags则会对这一问题造成影响

  1. 引入了不同的SDK 例如moduleA和moduleB, 其中mod测试工程师uleA & moduleB 中引用了同一个静态库

根据Xcode报错信息我们了解到静态库冲突的本质其实是符号(Symbol)冲突, 而且是全局符号xcodepreviews是什么软件导致的冲突;通过llvm nm -gUAj xx.o可以查看Macios鲁多多apphO文件的全局符号

解决静态库冲突的途径也就是解决ios启动器符号冲突, 可以从以下几个方面入手:

  • 删除冲突的符号:

我们都知道静态库的本质是编译ios下载好的.o目标文件的集合, 所以可以通过删除冲突符号所在的.o文件解决冲突

1. 首先查看.aObjective-C静态架构是什么意思库支持的架构, 可以使用lipo或者file命令

lipo -info libssl.a
file libssl.a

2. 针对冲突符号所在架构, 拆分出单一的架构,架构师工资 以arm64为例

lipo -thin arm64 libssl.a -output libssl_arm64.a

3. 针对单一架构输出.o到文件, 静态库操作都可以通过ar命令来实现, 如果报错 Inappropriate file type or format, 请校验静态库是否是单一架构


ar -x libssl_arm64.a

# 如果仅删除少量目标文件, 可以通过`ar -d xx.o`实现单个删除,无需重新打包

4. 删除冲突的符号后, 重新打包生成单架构静态库 使拉达xcode用libtool架构 或者ar

libtool -static -o libssl_arm64_new.a *.o
ar -rcs libssl_arm64_new.a *.o

5. 将多个架构静态库合并为一个, 首个参数是合成的静态库命名, 后面的是需要合并的库

lipo -creata -output libssl_new.a libssl_arm64_new.a libssl_armv7_new.a
  • 冲突符号改名
    • 如果有源码,那么可以直接修改源码符号名解决冲Objective-C突, 没有难度, 只是工作量的问题
    • 如果没有源码, 针对.架构师证书a静态库修改符号表实现改名,
      使用llvm objcopy –redefine-syms 可以修改符号名, rename_symbols中存储修改的符号和新的符号名, 格式要求可以通过 man lXcodelvm objcopy查看

 /usr/local/opt/llvm/bin/llvm-objcopy --redefine-syms rename_symbols xxx.o

我在测试过程中发现llvm-oObjective-Cbjcopy 在对objective-测试抑郁症c .m生成的.o目标文件修改时会报错,内容为:**error: unsupported load command (cmd=0x2d) ** 表示找不到Lios15oad Command: LC_LINK拉达xcodeER_OPTION;但是改为.mm后则可以正常修改,

如果有了解的ios系统同学, 请联架构图系我, 欢迎指教.

  • 修改冲突符号的类型架构图怎么做word

需要解决的问题有两个, 如测试你的自卑程度何将冲突符号类型由Global修改为Local以及符号修改后,静态库中其他目标文件如何链接该符号

解决思路是通过ld命令将整个静态库链接成一个目标文件, 这样不会导致隐藏全局符号后静态库内部链接不到符号的问题,

符号类型可以用ld的参数设置, 默认非导xcode怎么保存cpp出符号都是local, 导出符号都是global

unexported_sios越狱ymbols_list 参数设置不导出的符号列表

exported_sym架构是什么意思bols_list 设置导出符号列表,

具体步骤可拉达xcode以shell脚本处理


ARCH_LIST=("armv7" "arm64" "x86_64" "i386")
ARCH_COUNT=${#ARCH_LIST[@]}
do_fix()
{
ARCH=$1;
echo "fix for ${ARCH}..."
rm -rf ${ARCH}
mkdir ${ARCH}

# 架构抽取
lipo -thin ${ARCH} libcrypto.a -output "./${ARCH}/${ARCH}.a"

# 提取静态库.o目标文件
cd "./${ARCH}"
mkdir "objs"
ar -x "${ARCH}.a"
`mv *.o objs`
mv "__.SYMDEF SORTED" "objs"

# 目标文件提前链接, 这里可以解决符号隐藏后,内部无法链接的问题, 隐藏之前已经链接结束
cd "objs"
`ld -r *.o -o combine.o`
cp "combine.o" ../

# 输出全局符号作为隐藏符号的来源
cd ..
nm -g -j combine.o > hidden_symbols

# 剔除指定文件中的全局符号(需要对外开放的符号)
`cat ../global_symbols > tmp_symbols`
`cat "\n" >> tmp_symbols`
`cat hidden_symbols >> tmp_symbols`
`sort tmp_symbols|uniq -u > real_hidden_symbols`

# 重新连接隐藏符号
ld -x -r -unexported_symbols_list real_hidden_symbols combine.o -o hidden.o
nm -g hidden.o > exits_symbols

# 生成新的包
ar -rv "fix.a" hidden.o
cd ..
}
for ((i=0; i < ${ARCH_COUNT}; i++))
    do
    do_fix ${ARCH_LIST[i]}
done
LIB_PATHS=( ${ARCH_LIST[@]/#/} )
LIB_PATHS=( ${LIB_PATHS[@]/%//fix.a} )
lipo ${LIB_PATHS[@]} -create -output fix_libcrypto.a
  • 动态库包装: 思路很简单,就是创建一个新的ios是什么意思动态库, 动态库引用冲突的静态库, 需要注意的是,新创建的动态库要设置other linkiOSer flag 以使静态库会被链接(默认未使用的静态库不会链接); 解Xcode决的依据是被动态库包装后, 冲突符号变为local本地符号,不会与静态库中的global全局符号冲突, 不会在静态链接期间编译报错, 但是再运行时会在控制台提示 Class xxx is implemented in both的信息

**优缺点分析: **

  • 删除静态库冲突xcodepreviews是什么软件文件, 这种方式优点是无需源码就可以实现, 缺点也很明显, 包含ios启动器删除了目标文件的库无法单独使用, 而且如果冲测试抑郁症的20道题突版本不一致也可能造成u测试用例ndefine symbols的问题

  • 修改符号名称: 统一的缺点是调用时需要修改成新符号

    • 有源码情况下修改冲突符号的名称, 一般工作量比较大,测试用例 需要修改符号定义和符号调用,冲突的架构师证书静态库后续版本升级也会造成一定工作量
    • 如果是直接修改的静态库中的符号表, 后续版本升级架构师需要掌握哪些知识也需要每次都做重命名操作(可以通过脚本实现), 冲突的库可以同时Xcode使用,适用于不同版本库的符号兼容,
  • 隐藏全局符号方式, 优点是冲突的库可以同时存在, 升级不涉及符号名修改, 缺点是静态库集成为一个目标文件, 编译器对静态库的按需链接无法优化,造成体积增大,

  • 动态库包装测试抑郁程度的问卷的方式, 会涉及库引入方式的修改, 但是对不同版本冲突库比较友好,

根据静态库冲突出现的场景分析测试抑郁症的20道题, 大多数是由于不同的库中引入了同一个静态库导致的,测试抑郁程度的问卷 所以要求我们在做SDK时, 如果需ios启动器要依赖第三方ios模拟器静态库, 不要直接集成到SDK中, 而是通过集成测试怀孕的试纸图片一深一浅文档的方式提示业务方去主动集成依赖的静态库

目前大测试用例部分知名三方SDK也是这么做的

参考

How to create static library for iOS without making all symbols public

An objcopy equivalent for Mac / iPhone?

llvm objcopy