ofxTurboJpegをiOSデバイスで使う際の注意

ofxTurboJpegをiOSデバイスで使おうとしたところ、いろんなエラーに悩まされた末に解決した記録。

# 環境

- macOS Sierra 10.12.2
- iPhone 6
- iOS 9.3.1
- Xcode 8.2.1
- openFrameworks 0.9.8(8c7ddba)
- ofxTurboJpeg(a0b432f)

# 最短手順

- [ここ](https://github.com/hjeffrey/turbojpeg)から`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)
```

[ここ](https://github.com/hjeffrey/turbojpeg)に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を使えないか調べたところ、[公式が否定](http://www.libjpeg-turbo.org/About/Jpeg-9)していた。

libturbojpegのビルド時に`--with-jpeg8`オプションをつけるとlibjpeg80(8d)を"Emulate"したものが書き出せるという情報があったのでやってみた。
ソースを[ここ](https://github.com/libjpeg-turbo/libjpeg-turbo)からDLしてビルド。
ビルド自体は[ここ](https://github.com/libjpeg-turbo/libjpeg-turbo/blob/master/BUILDING.md)の手順ほぼそのままでいけました。
シェルが`${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](http://freeimage.sourceforge.net/changeslog.html)を読むと、Ver.3.16.0以降でlibjpeg9aを使っているようなのでそれより前のソースかビルド済みバイナリを探すことに。

まずは[oFの過去バージョン](http://openframeworks.cc/download/older/)から探す。
コミットログを辿ると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を探すか作るかします。
[ここ](https://jaist.dl.sourceforge.net/project/freeimage/Source%20Distribution/3.15.3/)からソースをDL。
含まれる`Makefile.iphone`はarmv6用の設定ファイルなので、自力で書き換えるか[これ](https://gist.github.com/ObjSal/46247c4b20f4d23494974816112d10e8)を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になってしまっていること__

であるのだ！ということに気づく。

じゃあ、なぜそうなるのかっていうとリンク順ですよね、ということで冒頭に書いた通りにリンク順を変えて解決。
いろいろ勉強になりました。