openFrameworks 0.10.1でC++17を使いたい

例によってまた需要があるか分からない記事を.

某氏にoFでC++17のビルドが通らない, と聞かれやってみた次第.

環境は
* macOS 10.13.6
* Xcode 10.1
* oF 0.10.1 osx release

LinuxとかWinでは確認してないので悪しからず.
後述するけど特にwinはパッチを無視したりするので（多分大丈夫な気はするけど）ちょっと怪しい.

## TL;DR

取り敢えずビルド通ったけどまだ要検証.

## イントロ

oF自体C++11以降のことはそんなに考えられてなくてでも `filesystem` を使いたいからとC++17以前の場合は `boost::filesystem` を `std::filesystem` のエイリアスにする, とかという本当にそれ大丈夫なのかっていうことやってるわけですが, そういうこと書いてあるからC++17は大丈夫だろうと思ってました.
で, ビルド通らないと聞いてそこらへんで `boost:filesystem` と `std::filesystem` の微妙なAPIの違いが出てるのかと思ったけどそうでも無かった.

## oFのデフォのboostのバージョン

oFの `libs/boost/include/boost/version.hpp` を見てみると

```
#define BOOST_VERSION 106400
...
#define BOOST_LIB_VERSION "1_64"
```

とある. つまり1.64. これはoF0.10.0も同じ.
ちなみに0.9.8は1.58だからまったくアップデートされてないわけではない.

boostの1.64のリリースっていつなのかと言うと [リリースノート](https://www.boost.org/users/history/version_1_64_0.html) によると, 2017/04/19らしい.
oF0.10.0のリリースは2018/05/07だったらしい. （[CHANGELOG](https://github.com/openframeworks/openFrameworks/commit/7232a0e23c8c0901db27456d983f0714e20e5e67#diff-4ac32a78649ca5bdd8e0ba38b7006a1e)のアップデート日より）
その頃にはboostの1.65(2017/08/21), 1.66(2017/12/18)は出てたはずだけど差し変えたらまた検証要るしoFもそこまで最新を求めてるフレームワークではないので仕方ないですね.

## 色々書いたけど本題に.

結局何が問題だったかというと, boost 1.64ではまだ内部的に `std::auto_ptr` が使われてるんですね.
多分問題点はそれだけ. （ちゃんとエラーログ大量に出すぎてたので全部見たわけでは無い）

で, 自分で `std::auto_ptr` を差し替えるのも嫌だし2019/02/19現在で最新のboost 1.69(2018/12/12) に差し替えようと.

## 差し替え準備

そうなると今までよく分からない気がして避けて来た [apothecary](https://github.com/openframeworks/apothecary/) を使うのが多分正攻法なので使ってみた.

* 取り敢えず最新のzipをダウンロード.
* 差し替えるのも怖いのでoF0.10.1環境をもう一個別で作ってそこのscriptsに. 
    * gitのmasterブランチ使ってる場合と揃えた

これで `OF_DIR/scripts/apothecary` という状態に.

apothecaryレポジトリのトップのREADME見ても使い方がいまいちピンと来ないんだけど, `apothecary/apothecary/README.md` はちゃんと書いてあったので結構すんなり出来た.

## 依存パッケージのインストール

`apothecary/scripts/osx/install.sh` があるのでこれ叩けば良いはず.
（昔試したのか普通に必要で入れてるのか分からないけど今回は何もせずに動いたので動かしてない）

## boostのバージョン指定からのビルド

boostのバージョンは1.64に指定されてるのでまずはそれを編集.

`apothecary/apothecary/formulas/boost/boost.sh` の 11行目の `VERSION=1.64.0` を `VERSION=1.69.0` に修正.

## ビルド

```
cd OF_DIR/scripts/apothecary/apothecary
./apothecary update boost
```

を実行するとboostのソースをダウンロードしてきてビルドが始まるので待つ.

## 失敗

なんかパッチ出来ないって怒られた. `visualc.hpp.patch` のせいなので今回はwindowsは知らないので無視する.

もっかい `boost.sh` を開いて 45行目, 

```
...
function prepare() {
	patch -p0 -u < $FORMULA_DIR/visualc.hpp.patch
...
```

をコメントアウト.

```
...
function prepare() {
	# patch -p0 -u < $FORMULA_DIR/visualc.hpp.patch
...
```

もっかいビルドをやり直し.

```
cd OF_DIR/scripts/apothecary/apothecary
./apothecary update boost
```

## 成功

出来た.
これだけだと差し変わってないので出来上がった `scripts/apothecary/boost` を `libs/boost` と差し替え.

意気揚々と `libs/openFrameworksCompiled/project/osx/openFrameworksLib` プロジェクトを開いて `C++ Language Dialect` を C++17に設定してビルド.

## そして失敗.

エラーは何かと見ると `std::ptr_fun` とか無いよ, と.

ということで,

* `ofLog.cpp`
    * `std::ptr_fun(noopDeleter)` を `std::function<void(ofBaseLoggerChannel*)>(noopDeleter)`
* `ofAppRunner.h`
    * `std::ptr_fun(noopDeleter)` を `std::function<void(Window*)>(noopDeleter<Window>)`

に修正. もっかいビルド.

### 追記 (2019/02/25)

上の修正を本家にPR投げてマージされたので恐らく0.10.2からは `ptr_fun` は無くなるはず.

## 成功

ということで適当なプロジェクトを作って

```cpp
#include "ofMain.h"

class ofApp : public ofBaseApp {
public:
    void setup() {
        std::string str = "hoge";
        auto p = std::make_pair(1, str);
        auto [x, y] = p;
        std::cout << x << ", " << y << std::endl;
        ofExit();
    }
};

int main() {
    ofGLFWWindowSettings setting;
#if 10 <= OF_VERSION_MINOR
    setting.setSize(1280, 720);
#else
    setting.width = 1280;
    setting.height = 720;
#endif
    auto window = ofCreateWindow(setting);
    auto app = std::make_shared<ofApp>();
    ofRunApp(window, app);
    ofRunMainLoop();
}
```

こんなコードをビルド.

## 成功！と思いきや.

やったー！と思ってちゃんと見るとプロジェクトの `C++ Language Dialect` が `C++11` のままじゃん？このくらいなら `Decomposition declarations are a C++17 extension ` って警告吐いて動くのね... あと他の警告も無茶出てる.

ということで一旦他の警告は無視して `C++17` に設定してビルド.
無事成功.

```
1, hoge
```

って出力された.

## 他のwarning

```
direct access in function 'boost::system::detail::system_error_category::default_error_condition(int) const' from file '../../../libs/boost/lib/osx/boost_filesystem.a(operations.o)' to global weak symbol 'boost::system::detail::is_generic_value(int)::gen' from file '(中略)/Build/Intermediates.noindex/Cpp17_test_0_10_1.build/Debug/Cpp17_test_0_10_1.build/Objects-normal/x86_64/ofApp.o' means the weak symbol cannot be overridden at runtime. This was likely caused by different translation units being compiled with different visibility settings.
```

色々調べてみると Build Settings の `Symbol Hidden by Default` がboostのビルド時と違うらしい.
ので `Symbol Hidden by Default` を `YES` にしてみたら消えた.

この警告の意味がまだよく理解出来てないのでboostのビルド時の設定を変えるべきか上の修正をすべきか分からない.

ので要調査.

## 締め

ちゃんと使うには最後の `Symbol Hidden by Default` の問題を理解するまでお預けかな...