タイトルの通り。duplicate symbol
が出まくって面を食らったので解決策を備忘録として残しておきます。
環境情報
名前 | バージョン |
---|---|
Xcode | 12.3 (12C33) |
Swift | 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28) |
SwiftyTesseract | 4.0.0 |
CMake | 3.19.3 |
Python | 2.7.16 |
xcode-select | 2384 |
OpenCV | 4.5.1 |
SwiftyTesseractとOpenCVを同じプロジェクトで使う
二つを同じプロジェクトで使うための手順を示します。
SwiftyTesseractをプロジェクトに追加する
2021年1月19日現在、SwiftyTesseractはSwift Package Managerからしか追加できませんので、Swift Package Managerから追加します。
Xcode上で「File > Swift Packages > Add Package Dependency...」と選択して、
入力欄に以下のGitHubのURLを入力します。
https://github.com/SwiftyTesseract/SwiftyTesseract
OpenCVをプロジェクトに追加する
iOS用にビルドする
GitHubからOpenCVを入手して、platform/ios/
にある以下のコマンドでiOS用にビルドします。
$ ./platform/ios/build_framework.py <output_dir>
ビルドしたframeworkファイルをプロジェクトに追加する
プロジェクトファイルを選んで、左ペインの「TARGETS」からアプリを選択します。
そして「Build Phases > Link Binary With Libraries (n items)」と選択して、ビルドで出力された「opencv2.framework」をドラッグ&ドロップなどで追加します。
Other Linker Flagsに-all_load
を追加する
プロジェクトファイルを選んで、左ペインの「PROJECT」からアプリを選択します。
「Build Settings」を選択して、「Linking > Other Linker Flags」に-all_load
を追加します。
libc++.tbdをプロジェクトに追加する
同じくプロジェクトファイルの「TARGETS」からアプリを選択します。
そして「General > Frameworks, Libraries, and Embedded Content」と選択して、左下の「+」ボタンを押します。
検索窓に「libc++」と入力すると「libc++.tbd」が出てくると思うのでそれを追加します。
試しにビルドしてみるが…
試しにビルドしてもこの時点ではうまくいきません。エラーを見ると「509 duplicate symbols for architecture x86_64(シミュレータなら×86_64、実機ならarm64)」というものすごい数の競合が起きていることがわかります。
解決方法ですが、__opencv2.frameworkから競合が起きているファイルを削除する__ことで解消できます。
競合が起きているファイル(.oファイル)をまとめる
エラーを頼りに競合が起きてるファイルをまとめます。執筆者の環境では以下のファイル内で競合が起きていました。
jutils.o pngrio.o pngwio.o jdcoefct.o jaricom.o jdmainct.o jdcolor.o pngerror.o jfdctint.o pngget.o pngrutil.o jmemmgr.o jccoefct.o jcmaster.o jidctflt.o pngpread.o jcprepct.o jerror.o pngset.o jctrans.o jcparam.o jdinput.o pngwtran.o jdarith.o jdsample.o jcomapi.o png.o pngrtran.o jchuff.o jddctmgr.o jidctfst.o jfdctfst.o pngwrite.o jfdctflt.o jdatasrc.o jdapistd.o pngmem.o jdapimin.o pngwutil.o jcdctmgr.o jdtrans.o jdhuff.o jdmaster.o jcapistd.o jdatadst.o jquant2.o jdmerge.o jmemnobs.o jccolor.o jdmarker.o jdpostct.o jcmarker.o jidctred.o jcarith.o jcmainct.o pngtrans.o jcinit.o jcsample.o jquant1.o pngread.o jidctint.o jcapimin.o
上記リストは、後でコマンドに引数として食わせるときに使いやすいようテキストファイルなどに書いておきます。
$ echo "jutils.o pngrio.o ..." > duplicate_lib_list
OpenCVをアーキテクチャごとに分解する
lipoコマンドを使って、フレームワークフォルダ内のopencv2をアーキテクチャごとに分解します。
まず何が含まれているか以下コマンドで確認して、
$ cd opencv2.framework
$ lipo -info opencv2
Architectures in the fat file: opencv2 are: armv7 armv7s i386 x86_64 arm64
以下コマンドでバラします。
$ lipo -thin armv7 opencv2 -output opencv2_armv7
$ lipo -thin armv7s opencv2 -output opencv2_armv7s
$ lipo -thin i386 opencv2 -output opencv2_i386
$ lipo -thin x86_64 opencv2 -output opencv2_x86_64
$ lipo -thin arm64 opencv2 -output opencv2_arm64
競合が起きているファイルを削除する
バラしたファイルに対して以下コマンドを実行して、競合が起きているファイルをそれぞれから削除します。
$ cat duplicate_lib_list | xargs ar -dv opencv2_armv7
$ cat duplicate_lib_list | xargs ar -dv opencv2_armv7s
$ cat duplicate_lib_list | xargs ar -dv opencv2_i386
$ cat duplicate_lib_list | xargs ar -dv opencv2_x86_64
$ cat duplicate_lib_list | xargs ar -dv opencv2_arm64
バラしたファイルから再生成する
以下コマンドを実行してopencv2を再生成しましょう。
$ lipo -create opencv2_arm64 opencv2_armv7 opencv2_armv7s opencv2_i386 opencv2_x86_64 -output opencv2
あとは途中作ったテキストファイルなどの余計なファイルを削除してリビルドしましょう。
競合が解消されてビルドできるようになっているはずです!