Homebrewで入れたC++ライブラリはclangでコンパイルしないとダメらしい

## なにこれ
C++をついこの間使い始めました. 外部ライブラリを使おうと思って, Homebrewからぶち込んでGCCでコンパイルして使おうと思ったら使えなかった. そういうお話.

## 環境
こういう困ったことの解決策を共有するときは計算環境を提示しておいたほうがいいよね. 足りなかったら言ってくだいね.

```
OS           : macOS Mojave ver10.14
c++ compiler : gcc version 8.2.0 (Homebrew GCC 8.2.0)
homebrew     : Homebrew 1.8.6
```

## Homebrewってなんぞや
そんなん知ってるわっていう人が大半かもしれないけど一応. 〇〇をインストールしますって言って,

```
brew install 〇〇
```

しか書いてないみたいなのがとても嫌なので.
Homebrewとは, macOS用のパッケージ管理システムの１つで, ソフトウェアを簡単に入れるためのものだそうです. ふむふむ. 手動で入れようと思うとmakeが通らねえーとかパスが違うーとかままありますよね. そういっためんどくさいもんを勝手に解決してコマンド1つでソフトウェアがぶっ込める. そんな素敵なものがHomebrewなんだそうだ.

Homebrew自体のインストールはこちらからどうぞー　[Homebrew](https://brew.sh/index_ja)

## とりあえず最初にコケるまで
外部ライブラリとして[ICU - International Components for Unicode](http://site.icu-project.org/design/cpp)を使おうと思って, とりあえずHomebrewで検索.

```console:brew_search
brew search icu
```

そうすっとicu4cなるものがヒット. 今考えるとこれicu for Cの意味だったのねとわかるんだけど, 始めはなにこの4cってずっと思ってた. まあそんなことはいいとして, わーい見つかったということでインストール.

```console:brew_install
brew install icu4c
```

はい, 完全勝利. あとは使うだけ！そう思っていた頃が僕にもありました. てなわけでコンパイル

```console:compile
g++ icu_test.cpp
```



```console:compile_error
icu_test.cpp:1:10: fatal error: 'unicode/translit.h' file not found
#include <unicode/translit.h>
         ^~~~~~~~~~~~~~~~~~~~
1 error generated.
```

あっるえー？？ヘッダファイルが見つかっていないらしい. 一生懸命調べるとCコンパイラでは`-I`オプションでヘッダファイルのインクルードパス, `-L`でその実装が書かれたライブラリパスを指定するとのこと.
いやそのパスってどこにあんねんということで, `find`コマンドで探した.
`opt`の方でいいんじゃねって思って, 中身を見る.

```console:findコマンド
xxxxxx$ find /usr/local/ -name icu4c
/usr/local//opt/icu4c
/usr/local//Cellar/icu4c
xxxxxx$ ls /usr/local//opt/icu4c
INSTALL_RECEIPT.json	include			readme.html
LICENSE			lib			sbin
bin			license.html		share
```
なんかいかにもなものがある. `include`と`lib`ってのがある. これじゃね？って思ってもう一回コンパイル.

```console:compile
g++ icu_test.cpp -I/usr/local/opt/icu4c/include -L/usr/local/opt/icu4c/lib
```

```console:compile_error
Undefined symbols for architecture x86_64:
  "icu_63::UnicodeString::UnicodeString(char const*)", referenced from:
      katakana2hiragana(icu_63::UnicodeString)       in ccz5k34Q.o
  "icu_63::UnicodeString::~UnicodeString()", referenced from:
      katakana2hiragana(icu_63::UnicodeString)       in ccz5k34Q.o
  "icu_63::Transliterator::createInstance(icu_63::UnicodeString const&, UTransDirection, UErrorCode&)", referenced from:
      katakana2hiragana(icu_63::UnicodeString)       in ccz5k34Q.o
  "icu_63::UnicodeString::extract(int, int, char*, unsigned int, char const*) const", referenced from:
      icu_63::UnicodeString::extract(int, int, char*, char const*) const in ccz5k34Q.o
  "operator new[](unsigned long)", referenced from:
      katakana2hiragana(icu_63::UnicodeString)       in ccz5k34Q.o
  "___gxx_personality_v0", referenced from:
      Dwarf Exception Unwind Info (__eh_frame) in ccz5k34Q.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
```
は？？？ってなった. いやいやインクルードパスとライブラリパスは書いてあるやんけ！！
さらに頑張って調べてみると, これはリンカってもののエラーらしいことがわかった. ライブラリパスを-Lオプションで記載するだけではなく, その中のどのライブラリをくっつけて実行可能バイナリを生成するかってことを`-l`オプションで指定する必要があるらしい.

```console:libraries
xxxxxx$ ls /usr/local/opt/icu4c/lib
icu			libicuio.63.1.dylib	libicutu.63.dylib
libicudata.63.1.dylib	libicuio.63.dylib	libicutu.a
libicudata.63.dylib	libicuio.a		libicutu.dylib
libicudata.a		libicuio.dylib		libicuuc.63.1.dylib
libicudata.dylib	libicutest.63.1.dylib	libicuuc.63.dylib
libicui18n.63.1.dylib	libicutest.63.dylib	libicuuc.a
libicui18n.63.dylib	libicutest.a		libicuuc.dylib
libicui18n.a		libicutest.dylib	pkgconfig
libicui18n.dylib	libicutu.63.1.dylib
```

なんかたくさんある. `lib〇〇`っていうのがそれぞれライブラリらしい. どれを使えばいいかわからないので, とりあえず全部のせしてみよう. コンパイルが通ったら不要な物を減らして再コンパイルすればいいしね.

```console:compile
g++ icu_test.cpp -I/usr/local/opt/icu4c/include -L/usr/local/opt/icu4c/lib -licudata -licui18n -licuio -licutest -licutu -licuuc
```

```console:compile_error
Undefined symbols for architecture x86_64:
  "operator new[](unsigned long)", referenced from:
      katakana2hiragana(icu_63::UnicodeString)       in cc1qyWVv.o
  "___gxx_personality_v0", referenced from:
      Dwarf Exception Unwind Info (__eh_frame) in cc1qyWVv.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
```

これもうわかんねえな. 一旦お手上げもうだめ.

## ライブラリインストール後のコンパイルをGCCにやらせてみる
さらに頑張って調べてみると, どうやらHomebrewで入るライブラリは, デフォルトではmacに最初からインストールされているclangでコンパイルされるらしい. てことは, clangでコンパイルしたライブラリをgccでコンパイルしたコードとgccでリンクしようとして上手く行ってないのではないかと推測.

[stackoverflow - Using Homebrew with alternate GCC
](https://stackoverflow.com/questions/9186033/using-homebrew-with-alternate-gcc)

このあたりを参考にビルド時のコンパイラをgccにしてHomebrewから再インストール

```console:brew_install_with_GCC
brew uninstall icu4c
HOMEBREW_CXX=g++ brew install icu4c
```

これでもう1回コンパイル. だけどダメ. もはやエラーメッセージをとっておくことも忘れた(´•ω•`)

## ソースコードのコンパイルをclangにやらせてみる
ライブラリをgccでコンパイルしてダメなら, 今度はその逆, 自分のコードをclangでコンパイルすればいいのではないか. やってみる.

```console:brew_install_with_clang
brew uninstall icu4c
HOMEBREW_CXX=c++ brew install icu4c
```

これでもう一回コンパイル.

```console:compile
c++ icu_test.cpp -I/usr/local/opt/icu4c/include -L/usr/local/opt/icu4c/lib -licudata -licui18n -licuio -licutest -licutu -licuuc
```

ようやく通った！！やった！もう外部ライブラリなんて怖くない(大嘘)
Homebrewのデフォルトのコンパイラがclangだから, Homebrewからインストールできるソフトウェアはそれで動くようにできているんだろうなぁ.

## まとめ
C++で外部ライブラリを使うときには
* `-I`オプションでヘッダファイルがあるディレクトリのパスを指定する必要がある
* `-L`オプションでライブラリの実装があるファイルへのお明日を指定する必要がある
* `-l`オプションで使用したいライブラリ名を指定する必要がある
* Homebrewからインストールしたライブラリを使用する場合にはgccではなくclangでコンパイルする必要がある

何はともあれ, 解決してよかった.