Chromiumをbuildしよう（libcacaで動くAAなやつを）

# このエントリについて
アドベントカレンダーでソースコード→Issue Tracker→プロセス構成と続いているので、この辺でぜひ一度Chromiumをbuildしてみませんか？というのが本記事の趣旨です。が、ただbuildしても面白くないと思うので、libcacaをバックエンドに使ったアスキーアートで描画するChromiumをbuildしてみましょう。正確にはChromium全体はbuildできず、content shellと呼ばれるレンダリングエンジンに最低限のUIを追加したものになります。

また、Chromiumをbuildするには意外とマシンパワーが必要です。そんなマシンないよ！っていう若者はぜひサンタさんにお願いしてみましょう。「俺、将来Chromium Committerになるんだ。そのためには爆速な~~ゲーミングPC~~開発マシンが必要なんだ。」とかお父さん、お母さんに話してみましょう。手元に爆速マシンとかいらんしー、とかいう大人の方はGCEとかクラウドにインスタンス持つのはどうでしょうか。ただ、チェックアウトが結構でかいので固定ストレージ代は馬鹿にならないかも……。

# まずは普通にbuild
## 公式ドキュメント
[Get the code: check out, build, and run Chromium.](https://chromium.googlesource.com/chromium/src/+/master/docs/get_the_code.md)
上記リンクの通り、現在、公式開発ドキュメントはソースツリーの中でMarkdown形式で管理されています。googlesource.comからアクセスするとHTMLに変換されてブラウザから閲覧できるように工夫されています。数年前までは[The Chromium Projectsのページの中](https://www.chromium.org/developers/how-tos)で、いわゆるGoogle Sitesを使ったページとして管理されていました。ドキュメントの移行は不完全で、一部は旧Sitesページに資料が残っているのが現状です。

Buildに関する公式ドキュメントは、各OSごとに分かれています。今回は一番スタンダードなLinuxを対象にします。Chromiumの開発者の大多数はLinux上で作業しています。Windowsのbuildはかなり時間がかかるので、例え仮想マシンの上であってもLinuxを使うメリットはあるかと思います。もちろんOS依存の開発は各OS上で行う必要がありますが、つい最近ではLinuxからWindowsのクロス開発ができるようになりました。

Windows Subsystem for LinuxはLinux環境のエミュレーション（知る限り、依存する /proc の再現）が不十分なため、buildツール群が動作しません。一度、ツールだけワークアラウンドを入れてbuildしてみたのですが、問題がChromiumのbaseに由来するため、ユニットテストが全然通りませんでした。

## 簡易説明
詳細は[Linux向けの公式ドキュメント](https://chromium.googlesource.com/chromium/src/+/master/docs/linux_build_instructions.md)を適宜参照してください。以下、最低限必要な情報を日本語で書き下しますが、おそらく1年もすれば通用しなくなっているかと思います。うまくいかなくなっていたら、編集リクエストをお願いします。

### 必要な環境
 * Ubuntu 14.04 / x86_64（16.04等でもレイアウトテストの一部が通らないくらいで実害はない）
 * メモリ 最低8GB、推奨16GB以上
 * ディスク 最低100GB

### 事前に必要なツールの取得
```shell-session
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
$ export PATH="$PATH:/path/to/depot_tools"  # パスは各自の環境にあわせて
```

### ソース（とツール群）の取得
```shell-session
$ mkdir ~/chromium && cd ~/chromium
$ fetch --nohooks chromium  # 事前に取得したdepot_toolsの一部
$ cd src
$ gclient runhooks  # 同じくdepot_toolsの一部
```

### 最新バージョンへの更新（適宜、必要な時にどうぞ）
```shell-session
$ git pull && gclient sync
```
gclient syncは、メインのソースのリビジョンに合わせて、適切なサブモジュール群をセットアップする役割を果たします。ローカルで作業ブランチを複数持っている時もブランチ移動後に実行する必要があります。

### build設定
```shell-session
$ gn gen out/Default  # エディタが起動するので、適宜設定を入れる
```
out以下が作業ディレクトリ、設定ごとにサブディレクトリが作られます。今回はDefault。他にはRelease/Debugなどが一般的。個人的にはこれ以外にAndroid/android-intel/android-arm64/gnwinなどのクロス開発環境も持っています。各ディレクトリ以下にargs.gnという名前で設定が作られるので、これをコピーして回れば設定は簡単に持ち越せます。

以下、お勧め設定とその理由。

```ini
# デバッグビルドは1GBを越える実行ファイルが生成されてやばい。
# どうしてもデバッグに必要な時以外は避けてます。
is_debug = false

# その代わりに入れるのがこの設定。本来デバッグビルドでしか発火しないアサート
# いわゆるDCHECKの類がリリースビルドでも有効になります。開発者必携フラグ。
dcheck_always_on = true

# 共有ライブラリ化を積極的に利用する。ユーザー向けbuildでは起動時間短縮のため
# 共有ライブラリ化は最低限になっているが、開発者は共有ライブラリ化を有効にした
# ほうが、buildで特に時間のかかるリンク時間を短縮できる。
# 開発サイクルを速くまわすためだけでなく、依存関係に問題がないか確認するためにも
# 開発者には使用をお勧め。ただ.soではOKだけどWindowsのDLLでは問題となる依存
# もあるため、Linux向けのbuildだけではチェックは不完全。
is_component_build = true

# Native Clientの機能を落とす。わりと大きめかつNaClを使わない限り不要。
enable_nacl = false
```

他にも公式ドキュメントではjumbo build、icecc、ccacheなんかを勧めているけど、使った事ないし、それぞれ設定も手間な（気がする）のでここでは省きます。Google社員の場合、クラウド上で超並列buildするgomaを代わりに使っています。プロジェクトを立ち上げた[鵜飼さんによるGDD 2011での講演](https://www.youtube.com/watch?v=KSYmRacdcwQ)がYouTubeで公開されています。気になる人は見てみると面白いかもしれません。

WindowsやMacの人は、開発ディレクトリをウィルススキャン系のソフト、検索インデックスの作成対象から外すことでも劇的に高速化されます。これはChromium以外でも有効な方法なので、普段色々と開発している人は作業領域全体を対象から外すと良いでしょう。

### build
```shell-session
$ ninja -C out/Default -jN chrome
```
-jは指定しなければninjaがCPU数から適当な値を選んでくれます。ただ、最適値はメモリ容量、ストレージ速度とも関係してくるのと、分散コンパイルやキャッシュを利用していても変わってくるので、自分で調整できる人は最適なNを探してみると良いでしょう。CPUやI/Oの負荷が十分に上がりつつ、メモリが足りなくなってスワップが発生しないあたりを狙ってください。

ターゲットにchromeを指定する事で、いわゆるChromium Browserがbuildされます。ざっくり30K以上のターゲットあるので、かなり時間がかかります。ここでの通常buildの確認は飛ばして、次のlibcacaを使ったbuildを直接試しても良いかと思います。

ターゲットを省略すると、chromeや多くのテストを含む、基本的なターゲットが全てbuildされます。buildルールに変更を入れた場合、全体をbuildしないと何かを壊していても気づけないので、全体をbuildします。

以上で自分でbuildしたchromeが実行できます。

```
$ ./out/Default/chrome
```

で実行できるはずです。以上の手順でうまくいかない場合は連絡ください。
![cr_version.png](https://qiita-image-store.s3.amazonaws.com/0/12843/e36d1b43-a619-1921-0778-6cae05f1e7c0.png)



# libcacaを使ったbuild
## Ozone
Chrome OSの人達が作ったバックエンドの抽象化レイヤーです。Chrome OSのUIはAuraと呼ばれています。現在はWindows版ChromeなどもAuraでUIを組んでいるのですが、このAuraとバックエンドを繋ぐレイヤーとしてOzoneが存在します。詳しくは[公式ドキュメント](https://chromium.googlesource.com/chromium/src/+/master/docs/ozone_overview.md)を見てください。

## Ozone/Caca
このOzone向けのバックエンドの1つとしてネタで用意されたのが[libcaca](http://caca.zoy.org/wiki/libcaca)を使ったバックエンドです。当初はChromiumのチェックアウトに公式に含まれていたのですが、現在はメンテナンスのコストなどを理由に削除されてしまいました。GitHub上に[Ozone/Caca](https://github.com/fred-wang/ozone-caca)としてパッチの形で用意されています。削除された当時のリビジョンではbuildできたのですが、現在はすでにコンパイルできなくなっていたので、refs/heads/master@{#512129} の時点でコンパイルできるようパッチを作りPRを送っておきました。現在は取り込まれており、今日時点での最新チェックアウト（refs/heads/master@{#521224}）でもbuildできました。

## 事前準備・ソースの取得
```shell-session
$ sudo apt-get install libcaca-dev
$ git clone https://github.com/fred-wang/ozone-caca ui/ozone/platform/caca
$ git checkout -b build_caca
$ git apply ui/ozone/platform/caca/ozone_extra_caca.patch
```

### 依存するパッケージのインストール
```shell-session
$ ./tools/install-build-deps.sh
```
Buildに必要なパッケージがインストールされます。use_sysroot=trueの場合には不要になった手順ですが、初めてuse_sysroot=falseでbuildする際には必要なはずです。

## build設定
```shell-session
$ mkdir -p out/OzoneCaca
$ cp out/Default/args.gn out/OzoneCaca
$ gn args out/OzoneCaca
```

エディタが起動するので以下の内容を追加

```ini
is_debug = false
dcheck_always_on = true
is_component_build = true
enable_nacl = false
# ここまでは前回の設定のコピー

use_ozone=true
use_sysroot=false
ozone_auto_platforms=false
toolkit_views=false
```

## build
```shell-session
$ ninja -C out/OzoneCaca -jN content_shell
```

content_shellは最低限のUIしかないので、閲覧したいURLを指定しながら起動してみましょう。ざっくり23KターゲットなのでChromium Browserをbuildするよりは短時間で済みます。

```
$ ./out/OzoneCaca/content_shell \
  --disable-setuid-sandbox \
  --disable-gpu \
  --ozone-platform=caca \
  https://www.google.com/
```

![cr_google.png](https://qiita-image-store.s3.amazonaws.com/0/12843/560a12c4-ec4f-efd2-03b2-b91d471d4bcc.png)

これ自体が役に立つ物かは置いておいて、これをベースに自分だけのバックエンドを実装してみる、なんてのも現実的に思えてきたりしませんか？こんなお遊びを元にChromiumのコードをチェックアウトして、改造して遊ぶ人が増えると良いなぁ、と思います。

# おまけ
## Linux上でChrome OSを疑似体験
Chrome OS上のUIをLinux上で有効にするbuildが存在します。おまけで紹介しておきます。主に開発者向けの機能ですが、Chromebookを手にする機会の少ない日本では珍しい体験をできるかと思います。デバイスの状態を表す部分（例えばバッテリー残量など）はダミーのエミュレーションが入っています。

### build設定
```ini
is_debug = false
dcheck_always_on = true
is_component_build = true
enable_nacl = false
target_os = "chromeos"
```

これだけです。

コメント欄で指摘を頂いたように、もしかしたら事前準備として```./tools/install-build-deps.sh```やJava 8のインストールが必要になるかもしれません。自分の環境ではこれらは大昔に必須だった頃に実行していたり、Android Chromeのbuildに必須のため最初に何も考えずにインストールしていたりで、見落としていました。

![cros.png](https://qiita-image-store.s3.amazonaws.com/0/12843/657d170e-237d-0930-f2e8-4958707d4965.png)

Chrome OS用のファイルマネージャやChrome Appsも動くので、Chrome Apps開発用で重宝するって人もいるかもしれません。

## 開発環境
Visual StudioやXcodeでの開発を期待している人、ごめんなさい。Chromium開発者の多くはvimやemacsを使って開発しています。主な理由はソースの規模が大きすぎるから。何年も前にはVisual StudioやXcode向けのプロジェクトを生成して、統合開発環境上からコンパイルできる環境がありました。が、今よりずっと規模の小さかった当時でもVisual Studioでプロジェクトを開くと、読み込んで解析が終わり、ソースの編集ができる状態になるまでに、何時間も待つ必要がありました。そんなわけで多くの人が早々に諦め、vimかemacsの環境に落ち着きます。僕もvimで開発していますが、そんなvimに便利ツールがあるので紹介。

emacs派の人は[tools/emacs](https://cs.chromium.org/chromium/src/tools/emacs/)があります。おそらく同等のツールが揃っているかと思います。僕の観測範囲ではChromium Projectの中ではvimが最大勢力なのですが、emacs派の主張はまた違うかと思います:)

他にも[Atom向けの設定ガイド](https://chromium.googlesource.com/chromium/src/+/master/docs/atom.md)、[Sublime Text向けの設定ガイド](https://chromium.googlesource.com/chromium/src/+/master/docs/sublime_ide.md)などがあります。[Android Studioを使う](https://chromium.googlesource.com/chromium/src/+/master/docs/android_studio.md)のが実は今時な環境を手に入れる一番の近道かも。

## vimお助けplugin
[tools/vim](https://cs.chromium.org/chromium/src/tools/vim/)以下に便利なpluginがあります。.vimrcからsourceしておくと便利です。

### clang-format.vim
編集中にtabを押すことで周辺のインデントをスタイルガイドに沿った状態に再整形してくれます。ChromiumにはJavaのコードを除き、1行80文字という古典的なルールが適用されていますが、省略を好まないために長い名前が多く、折り返しが大量に発生します。その際の折り返しルールが複雑、かつコード修正中に頻繁に発生するため、ほぼ必須の機能です。コマンドラインから```git cl format```するのと同等の機能になります（depot_toolsをインストールしていればgit経由で使えるサブコマンドが増えます）。

### filetypes.vim
Chromium Project固有のファイル、gyp/gypi/DEPSに対して適切な設定を適用するようになります。

### ninja-build.vim
これも必須。```\-o```で編集中のファイルをコンパイルします。コンパイルエラーは分割された領域に表示され、タグジャンプも利用できます。（というか、自分はできていますが、Chromiumとは関係なく色々とvimに設定を入れているので、もしかしたら別設定が必要な可能性もあります）

### mojom/ftdetect/mojomfiletype.vim
[Mojo](https://chromium.googlesource.com/chromium/src/+/master/mojo/README.md)とは何か、という哲学的な問題は置いておいて、Chromium内では既存のChrome IPCのインフラをMojoで置き換えるプロジェクトが進行中です。要はプログラミング言語に依存せずにインタフェースを記述し、相互に呼び出しするための仕組みです。このpluginではMojoに固有のmojomファイルに対して設定を適用します。

### mojom/syntax/mojom.vim
同じくmojom用のsyntax hilightingです。この辺りは普段Mojoを触らない人には不要かもしれません。

他にも[YCM](http://valloric.github.io/YouCompleteMe/)で補完機能を有効にするpluginなどもありますが、僕は使ってないので紹介を省きます。

# まとめ
libcacaネタを餌に色々と開発者向けネタを紹介してみました。これを機に一人でも多くの人が実際に手を動かし、buildしてコードを変更してみる、って世界に飛び込んでくれたら、と思います。日本人のChrome開発者は本業でやっている中心メンバーは多いものの、ボランティアのOSS開発者、他社からの開発者がほぼ皆無なのが現状です。アジア圏からも沢山の社外開発者が参加しているなか、この状況は日本人としては少しさびしいな、と思っています。