iOSネイティブアプリでwebRTCを使うために、ライブラリのビルドをしやすくした

WebRTCはウェブサイト用、ブラウザ用のAPIですが、
P2P通信による動画、音声通信APIですから、
ウェブサイト上に限らず、原理上ネイティブアプリからも使用できます。

ありがたいことに、[WebRTC本家](https://webrtc.org/native-code/)がネイティブアプリ向けのC++のライブラリを提供してくれています。

クロスプラットフォームで提供されているのですが、
iOSでの利用という意味では、若干の不便が残る状態になっています。

# ほしいもの

簡単な手順でiOSアプリプロジェクトに、WebRTCライブラリを入れられるようにしたい。

# 現状の問題点

ビルド結果として、iOS実機用のarmv7、arm64、シミュレーター用のi386、x86_64向けのスタティックライブラリがバラバラに生成される。
Xcode開発では、複数アーキテクチャのライブラリをひとまとめにしたfatバイナリ形式のほうが取り扱いやすい。

armv7だけ出力されるライブラリや、i386だけ出力されるライブラリなどがあり、
一貫して4つアーキテクチャ入りのfatバイナリにできない。
アーキテクチャのかけたfatバイナリをXcodeに突っ込むと、ビルド時に警告が出てしまう。

ヘッダーのツリーが整理されておらず、アプリのプロジェクトに突っ込みにくい。

Bitcode Embeddingに対応していない。
AppleはBitcode対応を推奨しており、iOSアプリでも今後必須化される可能性があるので、
ライブラリもできるだけBitcode対応のものを使いたい。

# やったこと

ヘッダーを含むincludeディレクトリと、
スタティックライブラリを含むlibディレクトリを生成するスクリプトをRubyで作った。

スタティックライブラリは、もしもともと特定アーキテクチャ専用であっても、
必ず4つのアーキテクチャを含むfatバイナリを生成するようにした。

Bitcode Embeddingの有効、無効どちらかを選択してビルドできるようにした。

# 使い方

[まず、WebRTCのソースを、こちらの手順にしたがってダウンロードします。](https://webrtc.org/native-code/ios/)

以降では、`~/webrtc-ios`にダウンロードしたという仮定で説明します。

[次に、僕のスクリプトをgithubから取得します。](https://github.com/omochi/webrtc-ios-build)

以降では、`~/webrtc-ios-build`にダウンロードしたという仮定で説明します。

スクリプトのリポジトリに移動します。

```bash
cd ~/webrtc-ios-build
```

スクリプトを実行します。

```bash
./webrtc-ios-build.rb --webrtc ~/webrtc-ios
```

`~/webrtc-ios-build/include`にヘッダが出力されます。
`~/webrtc-ios-build/lib`にライブラリが出力されます。

Xcodeプロジェクトに突っ込むときは、
includeはXcodeのプロジェクトに入れる必要はありません。
`Build Settings > Header Search Paths`に`include`を追加します。
Objective-Cのライブラリも使いたいときは`include/talk/app/webrtc/objc/public`も追加します。

ライブラリは、libディレクトリごとプロジェクトに追加し、
`General > Linked Frameworks And Libraries`および、
`Build Phases > Link Binary With Libraries`に登録します。
加えて、`Build Settings > Librari Search Paths`に`lib`を追加します。

あとは普通にアプリを作ります。

## Bitcode

bitcodeを無効化する場合、スクリプトに`--disable-bitcode`を指定します。

# サンプル

サンプルとして、GoogleのAppRTCDemoのソースと、
このツールで生成したライブラリを突っ込んで、
ビルドできるようにしたものを、
`examples/AppRTCDemo`に入れてあります。

iPhoneとPC(PCは[ウェブ版](https://apprtc.appspot.com/))でビデオチャットできます。

# やったこと詳細

ビルドスクリプトはRubyで実装しました。

おおまかな流れは、WebRTCのビルドを、4つのアーキテクチャで実行した後、
それを結合するというものです。

その他いくつかの手間がかかりました。

## 特定アーキテクチャ用のライブラリのfat化

arm専用のコードや、intel CPU専用のコードは、
そのアーキテクチャのスタティックライブラリしか生成されません。
しかし、アーキテクチャに欠けがあるfatバイナリを使うと、
Xcodeで警告が出てしまいます。

そこで、アーキテクチャに欠けがある場合は、
ダミーのスタティックライブラリを生成するようにしました。	

例えば、`libvpx_intrinsics_sse2.a`であれば、
下記のようなC言語のソースを生成します。

```c
int libvpx_intrinsics_sse2_dummy_symbol() { return 0; }
```

## Bitcodeの対応

WebRTCはchromiumプロジェクトの一部になっているのですが、
chromiumプロジェクトで、Bitcode対応が見送られているようでした。

以下のスレッドで、オープンソース版のclangがBitcodeに対応するまでは、
無効にしておこう、と言っています。

[Disable ENABLE_BITCODE for iOS 9.](https://groups.google.com/a/chromium.org/forum/#!topic/chromium-reviews/MEca51xoey8)

WebRTCのビルド設定は、`src/build/common.gypi`に書かれているのですが、
ここにある`ENABLE_BITCODE`を`YES`にするだけでは、
残念ながら生成されるビルドスクリプトには反映されませんでした。

WebRTCは、クロスプラットフォームにするために、
ninjaスクリプトや、
Visual Studioプロジェクト、
Xcodeプロジェクトを生成するために、
`gyp`というツールを使っています。([gyp公式はこちら](https://gyp.gsrc.io/))
gyp向けの"プロジェクトのソース"を書くと、
gypによって様々な種類のプロジェクトを生成する事ができます。

WebRTCのiOSビルドは、ninjaスクリプトを生成するのが標準とされているのですが、
gypのninjaスクリプトの生成箇所を追っかけてみると、
`gyp/pylib/gyp/xcode_emulation.py`にロジックを追加すれば対応できそうでした。

`xcode_emulation.py`では、`GetCflags`関数で、
`xcode`向けの設定を、Cコンパイラに渡すオプションに変換しています。

例えば下記のような感じです。

```python
    if 'SDKROOT' in self._Settings() and sdk_root:
      cflags.append('-isysroot %s' % sdk_root)
    if self._Test('CLANG_WARN_CONSTANT_CONVERSION', 'YES', default='NO'):
      cflags.append('-Wconstant-conversion')    
```

そこで、このスクリプトではこのあたりに以下のようなコードを挿入します。

```python
    if self._Test('ENABLE_BITCODE', 'YES', default='YES'):
      cflags.append('-fembed-bitcode')
```

幸い、gypはユーザのマシンにインストールされるものではなく、
webrtcのソースと一緒に、webrtcのビルドに使う用のgypが含まれています。
なので、これを変更しても副作用はwebrtcのビルドに限られます。

このようにして、bitcode対応モードで実行された時は、
必要であればgypにパッチを当てて、
その上で`common.gypi`の該当箇所を`YES`にする、
という動作を実装することができました。

# 参考

- [How to get started with WebRTC and iOS without wasting 10 hours of your life](http://ninjanetic.com/how-to-get-started-with-webrtc-and-ios-without-wasting-10-hours-of-your-life/): WebRTCをiOS向けにビルドする手順やトラブルシュートについて書かれています。

- [XcodeでAppRTCDemoをビルドできるようにしてみる](http://qiita.com/tnoho/items/76b5381f439bcc63aa0f): ほぼ同じタスクに取り組んでおられます。