[openFrameworks] ライブラリを読み込むためのあれこれ

# 前段
## ライブラリを読み込むためのあれこれ

どんなプログラミング言語で開発するにしても、第三者が作ったライブラリを用いて開発を効率化したり外部依存化することは、間違いなく必要だろう。それなしに様々な要件をクリアするものを作るのは難しい。

openFrameworksでもそれは同じである。ライブラリ利用においては、**addon**や**ProjectGenerator**という便利なしくみがある。C++のビルドについて深く考えることなしにうまく抽象化して、IDEの設定やリンケージの下準備を行ってくれる。しかしリンク方法は制約があり（後述）、必ずしもベストな構成を実現できなかったりする。いざ自前でライブラリを組み込もうとすると以外と手こずったりする。そのあたり自分も深く理解していなかったので、調べて得た気づきなどをここでまとめる。

## C++ライブラリの読みこみはめんどい？

一般にC++をビルドするということは、「**プリプロセス**」、「**コンパイル**」、「**リンク**」という流れが一貫してできた上で [^1] 、「**実行**」時にプログラム（`.app`とか`.exe`の実行ファイル）が期待どおりに動けば成功だ。「プリプロセス」「コンパイル」の時点で、ライブラリから提供されるインターフェースを知るために少なくとも**ヘッダーファイル**の読み込みを必要とし、「リンク」の時点で**静的ライブラリ**（`.a`とか`.lib`とか）の所在と名称を必要とし、「実行」時に**動的ライブラリ**（`.dylib`とか`.dll`とか）の所在が必要となる。

C++のライブラリはかなり豊富で、1990年台に配布されているライブラリがまだ現役で動かせたりするのには驚いたりする。一方で、ライブラリを組み込むために

* まずソースをダウンロードして
* 解凍して、
* [CMake](https://cmake.org/)などでで**ソリューション**（ビルドの構成）をつくって
* ビルドしてライブラリファイルを生成して
* その後に、自分のプロジェクトでリンクのためのソリューション設定をする

といった複数の手間が発生するために、jsやpythonなどの言語に比べて一つのライブラリを導入するのにかなり冗長な印象があった。（OpenCVを入れるだけで何日も溶かすみたいな。）ビルド済みのライブラリファイルをダウンロードできたりするライブラリも多く、結構手順をスキップできたりするのだが、良くも悪くも選択肢として幅が広く、判断にも時間を使ってしまう。

## vcpkg

しかし、2016年からMicrosoftが**[vcpkg](https://github.com/Microsoft/vcpkg)**というパッケージマネージャを用意してくれている。（C++のパッケージマネジャーはこれしか試したことが無いのでそのあたりは了承をお願いした上で、）vcpkgよって、他の言語と遜色なくライブラリの導入が容易になっている印象がある。ライブラリ導入までのプロセスをコマンド一発でおこなえ、Visual Studio上ですぐにライブラリを使った開発ができる。

vcpkgでは、kinectsdk, realsense2といったお仕事直結系や、vtkとかCGALとか外部依存が大量にあるビルド涙目系も、一発でライブラリファイルを生成してくれるので、自分にとっても効率化が見込めるように思えた。

Macの場合は地味にhomebrewでC++ライブラリを簡単にインストールできる。

# oFでライブラリを読み込む方法

前段が長くなってしまったが、必要なライブラリの「ヘッダーの所在（インクルードディレクトリ）」、「静的ライブラリの所在」、「動的ライブラリの所在」の3つを知っている前提とした場合、openFrameworksにライブラリを読みこむ方法は複数ある。代表的なものについて紹介し、それぞれについて若干の解説を加える。（Macでも考えは変わらないが基本的にWindowsを想定している。）

## 1. IDEで設定を手動でおこなう

Visual Studioを例にすると、Solutionのproperties(`alt` + `enter`)から

* `C/C++ > General > Additional Include Directories`にライブラリのヘッダーの所在を記述  
* `Linker > General > Additonal Library Directories`に静的ライブラリの所在を記述
* `Linker > Input > Additonal Dependencies`に静的ライブラリの名称を記述
* 動的ライブラリを`of_pj\bin`配下にコピペするか、もしくは`Debugging > Environment`に動的ライブラリの所在を記述

を行えば、おそらくビルドはできる。しかしこの場合、`Debug|x64`, `Release|x64`, `Debug|Win32`, `Release|Win32`のそれぞれでこのような手動記述が必要になったり、ProjectGeneratorでソリューションファイルを更新すると設定が消えるのでいちいち面倒くさい。確実かつわかりやすいが、しんどみが多発する。

## 2. ofxAddonTemplate通りのディレクトリをつくる

addonの設計思想どおりのディレクトリをつくり、ライブラリファイルを配置し、ProjectGeneratorをもちいてSolutionファイルを生成するというのがこのやり方。
**[ofxAddonTemplate](https://github.com/openframeworks/ofxAddonTemplate)**のリポジトリそれ自体がその構成を表現している。

```
ofxAddon
L src
L libs
   L XXX
       L include: ヘッダーを配置
       L lib
          L vs
             L x64: 64bit win用のライブラリを配置
             L Win32: 32bit win用のライブラリを配置
          L osx: mac用のライブラリを配置
```
上のようにディレクトリを作れば、ProjectGeneratorがよしなに必要な設定を作ってくれ簡単＆便利。ただ、ライブラリファイルをoFのアドオン配下に置かなければ行けないのは少し冗長に感じる。なぜなら、SDKや他のライブラリは、別の場所に配置されている可能性が高く、それを移動してくる必要があるからだ。
oF的には正しいやり方だが、すでにインストール済みのファイル群をoFディレクトリの配下に持ってきたりするのは手間だし、上記のvcpkgとうまく併用するのにすんなりいかない。（まぁコピペだけなので良いっちゃ良いが）

## 3. ofxAddonLibのパターンに従って、VS内でSolutionを並置する（win限定）

Elliot Woods氏が**[ofxAddonLib](https://github.com/elliotwoods/ofxAddonLib)**として提唱する方法。自分のプロジェクトと同じソリューションに、外部ライブラリのソリューションも参照としてに併置しておく、という手法。これによって、以下のメリットがある。

* addon配下にファイルなどをおかなくても良い
* 他のプロジェクトですでにビルドされている場合はそれを流用できるため、ビルド時間にメリットがある
* プロジェクトにあわせてライブラリ自体のビルド構成を見直せる

一方で、参照を追加するための操作が必要になるといったことがあるし、ソリューションファイルに並置するのは少々オーバーキルな気もする。玄人向けのやり方だと言える。

## 4. addon_config.mkに必要な情報を記述していく

これが今回最もおすすめしたいものに近い。**addon_config.mk**はProjectGeneratorが解釈してソリューションに要素を挿入するための設定ファイルで、対象のaddonディレクトリ直下に置くとProjectGeneratorでのUpdate操作時に読み込まれる。ofxAddonTemplateのディレクトリ構成に従わなくても、ライブラリ読み込みに必要な設定を実現できる。公式ドキュメントではあまり説明が無いが、[2bitさんのありがたい解説](https://qiita.com/2bbb/items/962b6d8ada155ac015bc)を参照すると理解が捗る。

ここでは、Realsense SDK 2.0の[インストーラ](https://github.com/IntelRealSense/librealsense/releases)を用いてRealsense SDK 2.0をインストールした場合の記述を例にする。ちなみにこれは[自分用のaddon](https://github.com/nama-gatsuo/ofxRealSenseUtil)で採用している方法。

```addon_config.mk
meta:
	ADDON_NAME = ofxRealSenseUtil
	ADDON_DESCRIPTION = Addon for RealSense
	ADDON_AUTHOR = Ayumu Nagamatsu
	ADDON_TAGS = realsense
	ADDON_URL = https://github.com/nama-gatsuo/ofxRealSenseUtil

common:

vs:
	ADDON_INCLUDES += "$(PROGRAMFILES)/Intel RealSense SDK 2.0/include/"

	# libは↓のように記述すると、
	# Additonal Library Directoriesに"C:\Program Files (x86)\Intel RealSense SDK 2.0\lib\x64"として挿入され
	# Additonal Dependenciesに"realsense2.lib"が入る。
	ADDON_LIBS += "$(PROGRAMFILES)/Intel RealSense SDK 2.0/lib/$(Platform)/realsense2.lib"

	# dllをbin配下にコピーする。これによって、dllはexeから必ず参照できるようになる
	ADDON_DLLS_TO_COPY += "$(PROGRAMFILES)/Intel RealSense SDK 2.0/bin/x64/Intel.Realsense.dll"
	ADDON_DLLS_TO_COPY += "$(PROGRAMFILES)/Intel RealSense SDK 2.0/bin/x64/realsense2.dll"

```
おそらく今後は、vcpkg と addon_config.mk を組み合わせたりすると開発がしやすくなったりするように思う。(ただboost依存とかでoFの内部とぶつかるとやっかいそう。)

## 番外編. xmlの編集プログラムを自前でつくる

これは実際の案件で[早坂あきら](https://twitter.com/Akira_At_Asia)さんが実際におこなっていたやり方だが、結局Visual Studioでリンカ情報を含むソリューションファイルはXMLなので、必要なアイテムに必要な情報を挿入すれば解決できるというワイルドな発想。
jsonなどでリンクの構成などを記述し、それにしたがって`.vcxproj`や`.sln`ファイルを上書きするというものだった。そもそも、ProjectGenerator自体がこの発想でソリューションファイルを生成している。確かにこういうアプリを自作したり、ビルド構成を吐き出せるシステムをつくるといったやり方が実は最も良いのかもしれない…。




以上です。間違いや対案などあればご指摘ください。

[^1]: [[Summary] ビルドとコンパイルとメイク](https://qiita.com/Rowing0914/items/588d3466f36f32bab0df) などが参考になる