Courgette スタンドアローン化について
これはなに
筆者はサイボウズラボユース開発支援制度を受けつつ、実行バイナリの差分生成についていろいろと調べています。 今日は、その活動紹介の一環として、最近やったことを記しておきたいとおもいます。 なお、以下の内容は 3月にやった成果発表スライドhttps://blog.cybozu.io/entry/2021/04/02/170042 を先に眺めてもらってからのほうが理解しやすいかと思います。
Courgette という Google Chrome に附属した高性能な実行バイナリ差分ソフトウエアがあります。これはGoogle Chrome のソフトウエアアップデートの高速化に使われています。
効果としては公式サイトを読んでもらえたらと思いますが、Chromium 190.1 -> 190.6 のアップデート容量が以下のように大幅に減少しています。
Full update 10,385,920
bsdiff update 704,512
Courgette update 78,848
しかし、これはChromium のソースコードと密結合していて普通に使えるものではないので、ソースコードが4万個以上ある Chromium のソースコードから、実行バイナリ差分生成プログラム Courgette のソースコードから肝心なものを取り出し、100ファイルほどと簡単に利用できるようにしました。
本稿では、どのようにやってきたかの概要を記したいと思います。リポジトリはここにあります: https://github.com/hiromi-mi/standalone-courgette
まず、先に使い方だけ紹介しておきます。
使い方
ビルド方法
$ git clone --recurse-submodules https://github.com/hiromi-mi/standalone-courgette $ cd standalone-courgette $ bash build.sh
こうすると courgette
が out/Default
以下に生成されます。
$ ./out/Default/courgette --help
パッチ生成
パッチを それぞれ
old_file
と new_file
とします。
./courgette -gen $(realpath old_file) $(realpath new_file) $(realpath diff.courgette)
すると diff.courgette という差分ファイルが生成されます。
パッチ適用
生成された差分ファイルの適用は以下でできます:
./courgette -apply $(realpath old_file) $(realpath diff.courgette) $(realpath out_file)
Chromium の大規模さについて
- 翻訳単位の個数が4万個以上
- ビルド時に
/tmp
20GBを使いきる、中間生成物が多すぎてinode不足になる - 独自ビルドシステムを使っていて、使い回しがきかない
- Core i9-10900X で 90分かかる (デバッグシンボルなし)
- 基盤ライブラリ base だけでソースコードが4000ファイル
- モノシリックなソースコード
- base なのにbase 以外に依存している
方法
基本的には、4万以上のソースコードファイルからいかに必要な関数を取り出すかが大事になってきます。
まず、メタビルドシステムを ninja を生成するために、gn というGoogle の独自ビルドシステムのビルドファイルを書きます。
トップレベル BUILD.gn からはじまり、その依存ファイルに沢山 .gn
とか BUILD.gn
とか *.gni
というファイル群があるので、それらを Chromium のビルドファイルをもとに書き換えます。
次に、ビルドエラーを直します。前述の通り Chromium 本体の base/ は4000ファイルぐらいあり、他ライブラリに依存していて、かつインターフェースが頻繁にかわるなどで使いにくいです。 そのため、mini_chromium の利用を試みました。 これは base library の独立して使える縮小版.... のはずが Courgette をビルドするには未対応なものが多くあります。そこでパッチ をあてました。 その方法ですが、以下のとおりとても泥臭い手法です。
- . まず Courgette のビルドエラーになる箇所とその原因関数を特定します
- . その関数やクラスが含まれたファイルを Chromium 本体のbase/からコピーします
- . mini_chromium の base/ と Chromium 本体の base/ とがコンフリクトする箇所を書き換えます
- . 書き換えますが、コピーしたファイルが依存するヘッダファイルが不足するので、やはりビルドエラーになります
- . 1. から 4. をくりかえし、ビルドエラーがなくなるまで修正します。 また、(base のはずなのに) 他ライブラリに依存していることなどがあり、まともに修正できないこともあります。そのときは、Courgetteで使用している関数やクラスや、それに依存しているAPIを全部調べ上げて、使われていない関数定義などを全部コメントアウトしたり、使わないようにソースコードを書き換えます。
以上、1から6をただひたすらに繰りかえしていきました。50ファイルほどは書き換えたと思います。
そして、Courgette 自身にも同様にパッチを書きます。https://github.com/hiromi-mi/courgette/commit/58628c4a839860ca0ad061af96eb3b2cb9260d81
最後に、依存するサードパーティライブラリにパッチを当てて、ビルドシステムを作っていきました。
苦労した点と今後について
苦労した点はいろいろとあるのですが、 - ソースコードの分量が多すぎて、読み解くだけで数十時間 (総和) かかりました。 - ドキュメントが少ない。あるとしてもブラウザーのChromium のソースコード解説だけで、それを取り出すことについては述べられていません。 - モノシリックなソースコードはその中で完結している分には分かりやすいが、一部だけ取り出そうとすると大変です。
今後については: - このアルゴリズムをそのままに、現在再実装に取り組んでいます。いずれできたら公開して別のソフトウエアアップデートシステムに組み込めたらと思っています。 - また、アルゴリズムの改良をしたいと思っています。
宣伝
このソフトウエアは サイボウズラボユース開発支援制度の支援を受け作成されたものです。