ofxTurboJpegをiOSデバイスで使おうとしたところ、いろんなエラーに悩まされた末に解決した記録。
環境
- macOS Sierra 10.12.2
- iPhone 6
- iOS 9.3.1
- Xcode 8.2.1
- openFrameworks 0.9.8(8c7ddba)
- ofxTurboJpeg(a0b432f)
最短手順
-
ここから
libjpeg.a
とlibturbojpeg.a
をDLしてofxTurboJpeg/libs/turbo-jpeg/lib/ios/
に上書きコピー -
Build Settings
のOther Linker Flags
でlibjpeg.a
の行を$(OF_CORE_LIBS)
より上に移動させる
試行錯誤の記録(再現手順)
ここから下は暇な人だけ読んで下さい
何かしらofxTurboJpegを使うコードを書いてビルドするとarm64用のシンボルが見つかりませんよ、とのリンクエラーが出る。
でない人はシミュレーターなりiPhoneなりのアーキテクチャがarmv7とかなんだと思います。
Undefined symbols for architecture arm64:
"_tjDestroy", referenced from:
ofxTurboJpeg::~ofxTurboJpeg() in ofxTurboJpeg.o
"_tjInitCompress", referenced from:
ofxTurboJpeg::ofxTurboJpeg() in ofxTurboJpeg.o
"_tjInitDecompress", referenced from:
ofxTurboJpeg::ofxTurboJpeg() in ofxTurboJpeg.o
"_tjGetErrorStr", referenced from:
ofxTurboJpeg::ofxTurboJpeg() in ofxTurboJpeg.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ここにarm64版をいれてビルドしてくれてる人がいるのでDLして上書きコピーする。
すると、実行はできるものの、下記エラーを見ることになる。
[ error ] ofxTurboJpeg: Error in tjInitCompress():Wrong JPEG library version: library is 90, caller expects 62
[ error ] ofxTurboJpeg: Error in tjInitDeCompress():Wrong JPEG library version: library is 90, caller expects 62
ここで、エラーメッセージの通りにJPEG library
のバージョンを合わせに行ったのが間違いだった。
長い旅の始まり。
いろいろ調べたところ、oF098のFreeImageが使っているlibjpegのバージョンが90(9a)で、libturbojpegが使っているlibjpegのバージョンが62(6b)ということらしい。
まずはlibturbojpegの方でlibjpeg9aを使えないか調べたところ、公式が否定していた。
libturbojpegのビルド時に--with-jpeg8
オプションをつけるとlibjpeg80(8d)を"Emulate"したものが書き出せるという情報があったのでやってみた。
ソースをここからDLしてビルド。
ビルド自体はここの手順ほぼそのままでいけました。
シェルが${IOS_SYSROOT[0]}
を展開してくれなくてそこだけ書き換えましたが。
書き出されたlibjpeg.a
とlibtuebojpeg.a
をofxTurboJpeg/libs/turbo-jpeg/lib/ios
以下にコピーして実行すると、下記エラーが出る。これは思惑通り。
[ error ] ofxTurboJpeg: Error in tjInitCompress():Wrong JPEG library version: library is 90, caller expects 80
[ error ] ofxTurboJpeg: Error in tjInitDeCompress():Wrong JPEG library version: library is 90, caller expects 80
そして、FreeImageをlibjpeg80を使ったものに差し替えればいけるはず、と踏んでいました。
FreeImageのChanges Logを読むと、Ver.3.16.0以降でlibjpeg9aを使っているようなのでそれより前のソースかビルド済みバイナリを探すことに。
まずはoFの過去バージョンから探す。
コミットログを辿るとoF080でFreeImage3.15.3を使っているようなのでそれをDLしてoF/libs/FreeImage
以下に上書き。
すると下記エラーに遭遇する。
ここでエラーに遭遇しない人は、ソースにofImage i;
と書くだけで見えるようになります。
もしこれじゃなくて50個超えのリンクエラーをみた人はBuild Settings
のBuild Active Architecture Only
をYes
に設定すると見えるようになります。
Undefined symbols for architecture arm64:
"_FreeImage_Initialise", referenced from:
ofInitFreeImage(bool) in libofxiOS_iphoneos_Debug.a(ofImage.o)
"_FreeImage_DeInitialise", referenced from:
ofInitFreeImage(bool) in libofxiOS_iphoneos_Debug.a(ofImage.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
エラーを素直に読んで、arm64版のFreeImageを探すか作るかします。
ここからソースをDL。
含まれるMakefile.iphone
はarmv6用の設定ファイルなので、自力で書き換えるかこれをDLしてbuild_ios.sh
を叩く。
ビルドエラーが出るのでSource/LibRawLite/internal/dcraw_common.cpp
の9158行目を以下に変更して再度ビルド("dcraw v"
とDCRAW_VERSOIN
の間にスペースを追加)。
strcpy (th->soft, "dcraw v" DCRAW_VERSION);
出来上がったlibfreeimage.a
とFreeImage.h
をoF/libs/FreeImage
以下にコピー。
実行できるようになるが下記エラーが出る。
[ error ] ofxTurboJpeg: Error in tjInitCompress():JPEG parameter struct mismatch: library thinks size is 568, caller expects 584
[ error ] ofxTurboJpeg: Error in tjInitDeCompress():JPEG parameter struct mismatch: library thinks size is 624, caller expects 656
バージョンは同じはずなのになんでだ・・・?!としばらく悩んだ末に、
libturbojpegのビルド時に作られるlibjpeg.aはピュアなlibjpegではなく、libjpegと同じインターフェースを持った別物なのだ
ということに気づく。恥ずかしながらいままで知らなかった。
--with-jpeg8
云々の説明に__Emulate__と書いてあったことの意味がここで氷解。
そしてここで起こっている問題の根本は
libturbojpegが参照するlibjpegが、turbo用にカスタマイズされたものではなくて通常の(FreeImageに含まれる)libjpegになってしまっていること
であるのだ!ということに気づく。
じゃあ、なぜそうなるのかっていうとリンク順ですよね、ということで冒頭に書いた通りにリンク順を変えて解決。
いろいろ勉強になりました。