03 Mar 2015

Chromium のコードを触ってみる

Contributing to Chromium: an illustrated guide – Monica Dinculescu という記事が面白かったのでやってみた。Chromium へのコントリビューションのガイドということで、環境構築、コードへの手の入れ方から、ビルド、差分の送り方まで解説している記事。

題材としてはこのように、アバターのメニューに項目を追加するというもの。

さすがにパッチを送るわけにはいかないので、コードに差分をいれてビルドするところまでをやってみる。

環境構築

記事にもあるが、基本的に Get the Code: Checkout, Build, Run & Submit - The Chromium Projects の内容が最新の状態に保たれているので、これに従う。

記事中に説明があるが、この wiki に無い情報としては、以下のビルドオプションの設定がおすすめらしい。

export GYP_DEFINES="component=shared_library dcheck_always_on=1"

基本的に書いてあるとおりにするだけでよかったが、一点自分の環境では、以下のように CoreFoundation がないよというエラーが出た。

% ninja -C out/Release chrome && out/Release/Chromium.app/Contents/MacOS/Chromium
ninja: Entering directory `out/Release'
[396/17862] MACTOOL copy-bundle-resource ../../breakpad/src/client/mac/sender/English.lproj/Localizable.strings
FAILED:  ./gyp-mac-tool copy-bundle-resource ../../breakpad/src/client/mac/sender/English.lproj/Localizable.strings crash_report_sender.app/Contents/Resources/English.lproj/Localizable.strings
Traceback (most recent call last):
  File "./gyp-mac-tool", line 601, in <module>
    sys.exit(main(sys.argv[1:]))
  File "./gyp-mac-tool", line 28, in main
    exit_code = executor.Dispatch(args)
  File "./gyp-mac-tool", line 43, in Dispatch
    return getattr(self, method)(*args[1:])
  File "./gyp-mac-tool", line 66, in ExecCopyBundleResource
    self._CopyStringsFile(source, dest)
  File "./gyp-mac-tool", line 105, in _CopyStringsFile
    import CoreFoundation
ImportError: No module named CoreFoundation
[396/17862] ACTION Generating resources from app/generated_resources.grd
ninja: build stopped: subcommand failed.

PyObjC が必要という内容だったので pip でインストールした。

pip install -U pyobjc

また、Chromium は非常に大きいコードベースなので、空間と時間の余裕には注意が必要。特に容量に関しては、リポジトリだけで 7 GB (--no-history オプション付きの場合。そうでなければ倍くらいになる) ほどにもなるし、ビルド時にもさらに容量が必要になる。一度手元の MBA の SSD が一杯になり、環境をかえてやり直すはめになってしまった。

コードに手を入れる

記事の内容に沿ってやってみる。

まずは、アバターのメニューを実装しているファイルを探す。git grep なり ack なりツールは何でもいいが、ここでは google code の code search を使う。

こういう時の常套手段は、ユニークっぽい文字列で検索して対象のファイルをみつけることだ。今回は switch person という文字列で検索してみると、以下のように generated_resources.grd というファイルが見つかる。これは文字列のリソースを管理しているファイルらしい。

ここから IDS_PROFILES_SWITCH_USERS_BUTTON という ID が見つかる。コードからはこの ID を参照していると思われるので、次はこれで検索してみると、以下のファイルが見つかる。

src/chrome/browser/ui/views/profiles/profile_chooser_view.ccsrc/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm が見つかるが、今回は Mac で試しているので、後者を見ていく。

createOptionsViewWithRect: という関数の中で、既存の Switch Person のボタンを作って containeraddSubView している箇所がみつかる。ここを真似するとなんとなくできそうとわかる。

以下のように switchUsersButton を作ってコンテナに追加している部分をコピペして、適当に書き換えてみる。

ボタンをクリックすると onMyButtonClicked が呼び出され、ShowSingletonTabhttp://please-sleep.cou929.nu/ を新しいタブで開くようにした。新しいタブで url を開くメソッド ShowSingletonTab は、本当はちゃんとコードを検索して調べるべきだったけれど、今回は横着して記事を参考にした。

これでビルドし直すと、意図したとおりにボタンを追加できた。

(py27)[22:50 kosei@localmba src (b684380...)]% ninja -C out/Release chrome && out/Release/Chromium.app/Contents/MacOS/Chromium --enable-new-avatar-menu
ninja: Entering directory `out/Release'
[4/12] SOLINK "Chromium Framework.framework/Versions/A/Chromium Framework", POSTBUILDS
[12/12] STAMP Chromium.app
[64001:1299:0302/232010:ERROR:profile_chooser_controller.mm(1873)] Hello, Chromium!

記事ではこのあとレビューの出し方などの説明が続くが、ここでは割愛。

参考