How to fix a "Duplicated Symbols" error on binary files

How to fix a "Duplicated Symbols" error on binary files

Angel G. Olloqui17 October, 2013

Introduction
When including third party libraries into your project, you can run into a “ Duplicated Symbols” error on the linking process. This annoying error is due to a name collision between one or more of your classes, usually caused by either:
  • You do not use a prefix as namespace and you use a generic name such as SessionUser or similar. This has an easy solution, as all you need to do is rename your classes to use a prefix. For example, User could be renamed into AGUser. Using prefixes is a good practice that you should always follow in programming languages without namespaces like C or Objective-C.
  • One or more of your libraries are including the same third party library. This is quite common on static frameworks and libraries built with little care. Usually, the creator of the library includes generic utilities such asSBJONReachability and similars inside the compiled binary. Then, your project or some other library also making use of it tries to include it again, resulting in the duplicated symbols error. If you have access to the source code, it could be solved easily by leaving the duplicated one out of your target. Unfortunately, when this problem occurs, many times comes from compiled libraries or frameworks that do not give us control on the source code files but just a binary instead. Solving this issue may not seem easy or even possible, but as we are going to see in this post it is not so difficult as it may look.
Special consideration
The whole post assumes that both duplicated libraries are the same version, or at least  fully backwards compatible. Besides, we also assume that both duplicated libraries  have not been modified, as any modification could break the commented compatibility. If the libraries are not compatible then you will need to analyze the differences and see if you can come with a “mixed” library that provides the desired compatibility or move one of your components to use the other incompatible version. In any case, the solution is very bound to your application and exceeds the purpose of this post.
Example
For improving readability we are going to fix a real project.  In this example project we have a static framework called Serenity that contains the  SBJSON library inside. The duplicated symbols appears when using  CocoaPods with the “ unoffical-twitter-sdk”, which also has a dependency to  SBJON. In this case, the duplicated symbols are therefore contained in  Serenity and  Pods.a binaries.
We could fix it by playing with the  Podspecs to leave out the  SBJSON from the “ unoffical-twitter-sdk”, but we have decided to remove the  SBJSON from  Serenity instead as it should not have been added in the first instance and anyway it contains an older version of  SBJSON that the one in  CocoaPods.
You should be able to follow the same process on your conflicting libraries in your project. Just check and decide which version you want to keep and which one you want to remove (usually keep the newer one).
Slimming down the fat binary
Most of the libraries are actually  fat binaries. This means that you can find the compiled binary code for more than one architecture within the same file. For example, in our example project, the  Serenity framework contains three architectures:  i386 (Simulator),  armv7 (iPhone 3GS+ compatible) and  armv7s (iPhone 5). Note that  armv7s at the moment of writing this post is not recognized by the  lipo tool as a valid architecture (it is displayed as “ cputype (12) cpusubtype (11)”) so we will need to make a small trick to support it. Hopefully Apple will update the tools soon to support it. You can check the architectures of your library by running:
$ lipo Serenity -info
Architectures in the fat file: Serenity are: armv7 (cputype (12) cpusubtype (11)) i386
In order to proceed with the whole process, we need to extract each architecture on its own file. We can do it by running:
$ lipo Serenity -thin armv7 -output Serenity.armv7
$ lipo Serenity -thin i386 -output Serenity.i386
$ xcrun -sdk iphoneos lipo Serenity -thin armv7s -output Serenity.armv7s
Note the use of the  xcrun in the last case due to the lack of support for  armv7s. The rest of the steps explained in the post are equally valid for  armv7armv7s and  i386.
Removing duplicated symbols
Now that we have the two different architectures in thin files, we can proceed to remove the duplicated symbols on each file. Lets first take a look to the symbols included in  Serenity:
$ ar -t Serenity.armv7
__.SYMDEF
MainView.o
PushRequest.o
PaymentViewController.o
SBJsonBase.o
SBJsonParser.o
SBJsonWriter.o
NSObject+SBJSON.o
NSString+SBJSON.o
FileManager.o
Barcode.o
qr_draw_png.o
QR_Encode.o
png.o
pngerror.o
pngget.o
pngmem.o
pngpread.o
pngread.o
pngrio.o
pngrtran.o
pngrutil.o
pngset.o
pngtrans.o
pngwio.o
pngwrite.o
pngwtran.o
pngwutil.o
We picked the  armv7 version, but the  i386 and  armv7s should be identical.
As we suspected, the library contains five symbols that are duplicated:
  • SBJsonBase.o
  • SBJsonParser.o
  • SBJsonWriter.o
  • NSObject+SBJSON.o
  • NSString+SBJSON.o
 
We just have to remove them by running:
$ ar -d -sv Serenity.armv7 SBJsonBase.o
d - SBJsonBase.o
Run the command with the other 4 symbols also. Then, repeat everything with the other architectures ( i386 and armv7s in our case). If you check the binaries again with the ` ar -t` option you should see that the symbols are not longer there.
Fattening the library
Ok, we are almost done. We have the three architectures without the duplicated symbols. All we need to do now is combine them back again into a fat library that will be used by our project. So first lets move the old version and keep a copy just in case something goes wrong.
$ mv Serenity Serenity_original
And now lets build the fat library:
$ lipo Serenity.armv7 Serenity.armv7s Serenity.i386 -create -output Serenity
And there you have! you should have a new binary file without the duplicated classes. You can now remove the intermediate  Serenity.armv7Serenity.armv7s and  Serenity.i386 files as they are not longer needed.
Finishing
If you now build your project again, you should be able to link without the duplicated symbols error presented before (at least without this one, maybe you have another one though).
It is extremely  important that you test your app again, because if any of the special considerations mentioned above are not met then your app could malfunction or even crash. Test, test and test!
Finally remember, you just modified a third party library so do not forget that any update on it will probably include the duplicated symbols again. And please, do not blame me if something does not work, just ask your third party developer to do his job properly and leave dependencies out of the binary :D.

Tags: librariestoolserrorslinkingbuildingfix


转自:http://angelolloqui.com/blog/31-How-to-fix-a-Duplicated-Symbols-error-on-binary-files

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值