原文作者:Angel G. Olloqui
原文鏈接:http://angelolloqui.com/blog/31-How-to-fix-a-Duplicated-Symbols-error-on-binary-files
介紹
將第三方庫包含在項目中時,可能會在鏈接過程中遇到“Duplicated Symbols(重復(fù)的符號)”錯誤畔柔。 這個令人討厭的錯誤是由于您的一個或多個類別之間的名稱沖突唬复,通常是由以下兩種之一引起的:
- 您不使用前綴作為命名空間橡淑,并使用通用名稱悉尾,如Ses sion主儡,User或similar暑诸。 這有一個簡單的解決方案,因為所有你需要做的是重命名你的類使用前綴峰搪。 例如岔冀,User可以重命名為AGUser。使用前綴是一個很好的做法概耻,您應(yīng)該始終遵循沒有像C或Objective-C這樣的命名空間的編程語言使套。
- 一個或多個庫包含同一個第三方庫。這在靜態(tài)框架和某些構(gòu)建的庫中是相當(dāng)普遍的鞠柄。 通常侦高,庫的創(chuàng)建者包括通用實用程序,例如SBJON厌杜,Reachability以及編譯二進制內(nèi)的類似內(nèi)容奉呛。然后,您的項目或其他使用它的庫嘗試再次包含它夯尽,導(dǎo)致重復(fù)的符號錯誤瞧壮。 如果您有權(quán)訪問源代碼,可以將重復(fù)的一個從您的目標(biāo)中輕松解決呐萌。不幸的是馁痴,當(dāng)這個問題發(fā)生時,很多次來自編譯的庫或框架肺孤,它們不能讓我們控制源代碼文件,而只是用一個二進制文件替代济欢。解決這個問題可能看起來并不容易赠堵,甚至只是有可能,但正如我們將在這篇文章中提的那樣法褥,并不難看到癥結(jié)所在茫叭。
特別考慮
整個帖子假定兩個重復(fù)的庫是相同的版本,或至少完全向后兼容半等。此外揍愁,我們還假設(shè)兩個重復(fù)的庫都沒有被修改,因為任何修改都可能會破壞注釋的兼容性杀饵。如果庫不兼容莽囤,那么您將需要分析差異,并查看是否可以使用“混合”庫來提供所需的兼容性切距,或者移動其中一個組件以使用其他不兼容的版本朽缎。無論如何,解決方案非常受您的應(yīng)用程序的約束,有點舍本逐末话肖。
舉個栗子
為了提高可讀性北秽,我們將修復(fù)一個真正的項目。 在這個示例項目中最筒,我們有一個名為Serenity的靜態(tài)框架贺氓,其中包含SBJSON庫。將CocoaPods與“unoffical-twitter-sdk”一起使用時床蜘,會出現(xiàn)重復(fù)的符號辙培,這也與SBJSON有關(guān)系。 在這種情況下悄泥,重復(fù)的符號因此包含在Serenity和Pods.a二進制文件中虏冻。
我們可以通過操控Podspecs來解決它,從“unoffical-twitter-sdk”中刪除SBJSON弹囚,但是我們決定將SBJSON從Serenity中刪除厨相,因為它不應(yīng)該被添加在第一個實例中,反正它包含 在CocoaPods中的一個舊版本的SBJSON鸥鹉。
您應(yīng)該能夠在項目中沖突的庫中遵循相同的過程蛮穿。 只需檢查并確定要保留的版本,以及要刪除的版本(通常保留較新的版本)毁渗。
Slimming down the fat binary
大多數(shù)庫實際上是胖二進制文件践磅。 這意味著您可以在同一文件中找到多個架構(gòu)的編譯二進制代碼。例如灸异,在我們的示例項目中府适,Serenity框架包含三種架構(gòu):i386(模擬器),armv7(iPhone 3GS +兼容)和armv7(iPhone 5)肺樟。 注意檐春,在寫這篇文章的時候,armv7不能被lipo工具識別為有效的架構(gòu)(它被顯示為“cputype(12)cpusubtype(11)”)么伯,所以我們需要做一個小技巧來支持它疟暖。希望蘋果將盡快更新這些工具來支持它。 您可以通過運行以下方式檢查庫的體系結(jié)構(gòu):
$ lipo Serenity -info
Architectures in the fat file: Serenity are: armv7 (cputype (12) cpusubtype (11)) i386
為了繼續(xù)整個過程田柔,我們需要在自己的文件中提取每個架構(gòu)俐巴。 我們可以通過運行:
$ lipo Serenity -thin armv7 -output Serenity.armv7
$ lipo Serenity -thin i386 -output Serenity.i386
$ xcrun -sdk iphoneos lipo Serenity -thin armv7s -output Serenity.armv7s
注意在最后一種情況下使用xcrun是由于缺乏對armv7的支持。 在這篇文章中解釋的其余步驟同樣適用于armv7硬爆,armv7s和i386欣舵。
Removing duplicated symbols
現(xiàn)在我們在瘦文件中有兩種不同的架構(gòu),我們可以繼續(xù)刪除每個文件上的重復(fù)符號摆屯。 讓我們先來看看靜態(tài)包中包含的符號:
$ 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
我們選擇了armv7版本邻遏,但是i386和armv7應(yīng)該是一樣的糠亩。
我們懷疑,庫中包含五個符號:
SBJsonBase.o
SBJsonParser.o
SBJsonWriter.o
NSObject+SBJSON.o
NSString+SBJSON.o
我們只需要運行:
$ ar -d -sv Serenity.armv7 SBJsonBase.o
d - SBJsonBase.o
運行其他4個符號的命令准验。 然后赎线,重復(fù)一切與其他架構(gòu)(i386和armv7s在我們的情況)。 如果再次使用ar -t
選項檢查二進制文件糊饱,那么您應(yīng)該看到符號不再存在垂寥。
Fattening the library
好的,我們差不多完成了 我們有三種架構(gòu)沒有重復(fù)的符號另锋。 我們現(xiàn)在需要做的就是將它們重新組合成一個將用于我們項目的胖庫滞项。 所以首先讓我們移動舊版本并保留一個副本,以防出現(xiàn)問題夭坪。
$ mv Serenity Serenity_original
And now lets build the fat library:
$ lipo Serenity.armv7 Serenity.armv7s Serenity.i386 -create -output Serenity
你做到了文判! 你應(yīng)該有一個新的二進制文件沒有重復(fù)的類。 您現(xiàn)在可以刪除中間的Serenity.armv7室梅,Serenity.armv7s和Serenity.i386文件戏仓,因為它們不再需要。
Finishing
如果您現(xiàn)在再次構(gòu)建項目亡鼠,您應(yīng)該可以鏈接赏殃,而不會在之前呈現(xiàn)的重復(fù)符號錯誤(至少沒有這個,也許你有另一個)间涵。
重要的是仁热,您再次測試您的應(yīng)用程序,因為如果上述任何特殊注意事項不能滿足您的應(yīng)用程序可能會發(fā)生故障甚至崩潰勾哩。 測試抗蠢,測試和測試!
最后記住思劳,你只是修改了第三方庫物蝙,所以不要忘記,任何更新都可能會再次包含重復(fù)的符號敢艰。 請不要責(zé)怪我,如果有什么不起作用册赛,只要求你的第三方開發(fā)人員正確地完成工作钠导,并將依賴關(guān)系從二進制文件中刪除:D。
以上森瘪;
分割線---------------------------------------------------------
謝謝牡属!如有出入,敬請見諒扼睬!之前使用融云的庫有過這個沖突逮栅,就依照這個方法順利解決悴势。嗯,就這樣吧措伐,如果還是解決不了特纤,私信我,一起來看看侥加。