Chromium をゼロから Build して動かしてみる

はじめに

ソフトウェアに対しての理解を深めたい場合、どうするでしょうか?

1つの方法は、ソースコードを読むことです。よく出来たソフトウェアのソースコードを読むことで、様々な学びを得る事が出来ます。

しかし、ソースコードだけでは挙動が掴みづらかったり、自分の理解に自信が持てない時もあります。そういった時は、動かしながら試すというアプローチも選択肢になるでしょう。「少し書き換えて動かしてみる」というサイクルを繰り返す事で、自分の中のメンタルモデルの正しさを確認しながらソースコードを読み進める事が出来ます。

今日は、巨大な OSS として有名な Chromium を対象に、「ソースコードから Build して動かしてみる」ことにします。Build だけでも大変なので、いったんは「Build して動かす」ところまでです。これをきっかけに Chromium に対して理解を深めたいと思います。

TL; DR

  • Checking out and building Chromium on Linux に従って作業を進めれば、特にハマることなく Linux 上で Chromium の Build が可能。ただし、何も高速化の工夫をしない場合は 8core, 32GiB memory の GCP VM instance で 6-7 時間程度かかる。
  • 一度 Build すると、それ以降は変更した file に依存するものだけが Build 対象になるので、Build は十数秒程度に高速化する。
  • Build した Chromium はページの取得やレンダーが可能。「自分が Build した Chromium」がちゃんと動くことを確認できた。

参照するもの: Chromium の Document

Chromium のページを見ていると、様々な Document が見つかります。 その中で、「LinuxChromium を Check out して Build する手順」がまとまっているのが以下の Document です。

今日は、このドキュメントを元に作業を進めてみます。

ステップ1. Linux マシンを用意する

まず始めに、作業を行うための Linux マシンを用意する必要があります。 再現性を持たせるために、今回は GCP の Compute Engine で以下の VM Instance を立ててそこで作業を行うことにします。

  • 8core, 32GiB memory (E2, e2-standard-8)
  • 200GB SSD
  • image: Ubuntu 20.04 LTS
  • zone: asia-northeast1-b

以下のコマンドで ssh して、そこで作業を行います。

$ gcloud beta compute ssh --zone "asia-northeast1-b" <instance 名>

ステップ2. 環境をセットアップ

まずは、Build に必要な様々な tool 群である depot_tools を install します。これで、fetch などのコマンドが使えるようになります。

minami@chromium-experiment:~$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
minami@chromium-experiment:~$ export PATH="$PATH:${PWD}/depot_tools"
minami@chromium-experiment:~$ which fetch
/home/minami/depot_tools/fetch

次に、作業用 dicretory として chromium directory を作ります。

minami@chromium-experiment:~$ mkdir ~/chromium && cd ~/chromium

depot_toolsfetchソースコードを取得します。

minami@chromium-experiment:~/chromium$ fetch --no-history --nohooks chromium
Running: gclient root
WARNING: Your metrics.cfg file was invalid or nonexistent. A new one will be created.
Running: gclient config --spec 'solutions = [
{
"name": "src",
"url": "https://chromium.googlesource.com/chromium/src.git",
"managed": False,
"custom_deps": {},
"custom_vars": {},
},
]
'
Running: gclient sync --nohooks --no-history

________ running 'git -c core.deltaBaseCacheLimit=2g clone --no-checkout --progress https://chromium.googlesource.com/chromium/src.git --depth=1 /home/minami/chromium/_gclient_src_p28570xw' in '/home/minami/chromium'
Cloning into '/home/minami/chromium/_gclient_src_p28570xw'...
remote: Counting objects: 352926, done
remote: Finding sources: 100% (352926/352926)
remote: Total 352926 (delta 78472), reused 232647 (delta 78472)
Receiving objects: 100% (352926/352926), 1.10 GiB | 15.97 MiB/s, done.
Resolving deltas: 100% (78472/78472), done.
Syncing projects: 98% (122/124) src/third_party/tflite/src
[0:07:56] Still working on:
[0:07:56] src/v8
[0:07:56] src/third_party/angle/third_party/VK-GL-CTS/src
.
.
.
Syncing projects: 99% (123/124) src/v8
.
.
.
Syncing projects: 100% (124/124), done.
Running: git submodule foreach 'git config -f $toplevel/.git/config submodule.$name.ignore all'
Running: git config diff.ignoreSubmodules all

これで、Chromiumソースコード取得が完了しました。

次に、dependency の install を行います。まずは、python2 を install します。

minami@chromium-experiment:~/chromium/src$ sudo apt update
minami@chromium-experiment:~/chromium/src$ sudo apt install -y python2
minami@chromium-experiment:~/chromium/src$ which python2
/usr/bin/python2
minami@chromium-experiment:~/chromium/src$ python2 -V
Python 2.7.18

minami@chromium-experiment:~/chromium/src$ sudo ln -s /usr/bin/python2 /usr/local/bin/python
minami@chromium-experiment:~/chromium/src$ which python
/usr/local/bin/python
minami@chromium-experiment:~/chromium/src$ python -V
Python 2.7.18

さらに、./build/install-build-deps.sh を実行します。これで、Build に必要な package などの install が行われます。これはしばらく時間がかかります。

minami@chromium-experiment:~/chromium/src$ ./build/install-build-deps.sh
Running as non-root user.
You might have to enter your password one or more times for 'sudo'.
.
.
.
Installing locales.
Generating locales (this might take a while)...
da_DK.UTF-8... done
en_US.UTF-8... done
fr_FR.UTF-8... done
he_IL.UTF-8... done
zh_TW.UTF-8... done
Generation complete.

さらに、$ gclient runhooks を実行します。

minami@chromium-experiment:~/chromium/src$ gclient runhooks
Hook 'vpython src/build/landmines.py' took 45.92 secs
Running hooks: 6% ( 6/97) nacltools
________ running 'vpython src/build/download_nacl_toolchains.py --mode nacl_core_sdk sync --extract' in '/home/minami/chromium'
INFO: --Syncing arm_trusted to revision 2--
.
.
.
Running hooks: 61% (60/97) subresource-filter-ruleset
________ running 'vpython src/third_party/depot_tools/download_from_google_storage.py --no_resume --no_auth --bucket chromium-ads-detection -s src/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1' in '/home/minami/chromium'
0> Downloading src/third_party/subresource-filter-ruleset/data/UnindexedRules@83bced6c2676ed8d7c57a84c9a8d4f76c08f79e2...
Downloading 1 files took 5.270337 second(s)
Running hooks: 100% (97/97), done.

これで、Chromiumソースコード全体と、Chromium の build に必要な dependency が揃いました。

ステップ3. Chromium の Build を行う

いよいよ Chromium の Build を行います。ChromiumNinja をメインの Build tool として利用するのですが、そのための Build directory および Configuration を GN というツールを利用して生成します。今回は out/Default という Build directory を生成します。

minami@chromium-experiment:~/chromium/src$ gn gen out/Default
Done. Made 17175 targets from 2693 files in 6820ms

Checking out and building Chromium on Linux を見る限りでは、 $ gn args out/Default を実行して、Build を高速化するための様々な設定を追加で行うことが出来るようですが、一旦何も追加設定はせずに進みます。

Ninja を利用した Chromium の Build は、$ autoninja -C out/Default chrome で行うことが出来るようです。このコマンドを実行して Build を開始します。

minami@chromium-experiment:~/chromium/src$ autoninja -C out/Default chrome

これで、Build が開始しました。Chromium の Build はとても時間がかかります(自分の環境だと Build が終わるまでに 5時間半 かかりました。長いです)。

待っている間に別の shell で $ ps fax を実行して Process tree を見てみると、以下のような結果になっていることが分かります。autoninja は内部で ninja-linux64 を実行しているようです。-j 10 がオプションとして渡されてるので、10 並列で Build が行われているように見えます。

 1783 ?        Ss     0:00  \_ sshd: minami [priv]
 1853 ?        S      0:01      \_ sshd: minami@pts/1
 1854 pts/1    Ss     0:00          \_ -bash
56626 pts/1    S+     0:00              \_ bash /home/minami/depot_tools/autoninja -C out/Default chrome
56760 pts/1    S+     0:03                  \_ /home/minami/depot_tools/ninja-linux64 -C out/Default chrome -j 10
61079 pts/1    S      0:00                      \_ /bin/sh -c ../../third_party/llvm-build/Release+Asserts/bin/clang -MMD -MF obj/native_client/src/t
61084 pts/1    R      0:02                      |   \_ ../../third_party/llvm-build/Release+Asserts/bin/clang -MMD -MF obj/native_client/src/trusted/
61090 pts/1    S      0:00                      \_ /bin/sh -c ../../third_party/llvm-build/Release+Asserts/bin/clang -MMD -MF obj/native_client/src/t
61091 pts/1    R      0:02                      |   \_ ../../third_party/llvm-build/Release+Asserts/bin/clang -MMD -MF obj/native_client/src/trusted/
61476 pts/1    S      0:00                      \_ /bin/sh -c python ../../mojo/public/tools/bindings/mojom_bindings_generator.py --use_bundled_pylib
61479 pts/1    R      0:00                      |   \_ python ../../mojo/public/tools/bindings/mojom_bindings_generator.py --use_bundled_pylibs -o ge
61482 pts/1    S      0:00                      \_ /bin/sh -c python ../../mojo/public/tools/bindings/mojom_bindings_generator.py --use_bundled_pylib
61483 pts/1    R      0:00                      |   \_ python ../../mojo/public/tools/bindings/mojom_bindings_generator.py --use_bundled_pylibs -o ge
61486 pts/1    S      0:00                      \_ /bin/sh -c ../../third_party/llvm-build/Release+Asserts/bin/clang++ -MMD -MF obj/ppapi/cpp/objects
61488 pts/1    R      0:00                      |   \_ ../../third_party/llvm-build/Release+Asserts/bin/clang++ -MMD -MF obj/ppapi/cpp/objects/var.o.
61492 pts/1    S      0:00                      \_ /bin/sh -c python ../../mojo/public/tools/bindings/mojom_bindings_generator.py --use_bundled_pylib
61495 pts/1    S      0:00                      |   \_ python ../../mojo/public/tools/bindings/mojom_bindings_generator.py --use_bundled_pylibs -o ge
61506 pts/1    R      0:00                      |       \_ /bin/sh /sbin/ldconfig -p
61497 pts/1    S      0:00                      \_ /bin/sh -c python ../../mojo/public/tools/bindings/mojom_bindings_generator.py --use_bundled_pylib
61498 pts/1    S      0:00                      |   \_ python ../../mojo/public/tools/bindings/mojom_bindings_generator.py --use_bundled_pylibs -o ge
61501 pts/1    S      0:00                      \_ /bin/sh -c ../../third_party/llvm-build/Release+Asserts/bin/clang++ -MMD -MF obj/ppapi/cpp/objects
61502 pts/1    R      0:00                      |   \_ ../../third_party/llvm-build/Release+Asserts/bin/clang++ -MMD -MF obj/ppapi/cpp/objects/var_ar
61503 pts/1    S      0:00                      \_ /bin/sh -c ../../third_party/llvm-build/Release+Asserts/bin/clang++ -MMD -MF obj/ppapi/cpp/objects
61505 pts/1    R      0:00                      |   \_ ../../third_party/llvm-build/Release+Asserts/bin/clang++ -MMD -MF obj/ppapi/cpp/objects/var_ar
61504 pts/1    S      0:00                      \_ /bin/sh -c python ../../mojo/public/tools/bindings/mojom_bindings_generator.py --use_bundled_pylib

待ち続ければ、Build が終わります。終了時には以下のような表示になっています。

minami@chromium-experiment:~/chromium/src$ autoninja -C out/Default chrome
ninja: Entering directory `out/Default'
[52205/52205] LINK ./chrome

Build が終わると、Build directory である out/Default の中に様々な成果物が作られています。

minami@chromium-experiment:~/chromium/src$ ls -1 out/Default/
absl_hardening_tests.runtime_deps
accessibility_perftests.runtime_deps
accessibility_unittests.runtime_deps
.
.
.
zucchini_integration_test.runtime_deps
zucchini_unittests.runtime_deps
zxcvbn_unittests.runtime_deps

その中に chrome という名前の binary があり、それが「chrome browser」になっています。

minami@chromium-experiment:~/chromium/src$ ls -la out/Default/chrome
-rwxrwxr-x 1 minami minami 1058842464 Dec 12 18:22 out/Default/chrome

以下のように version を確認する事もできます。

minami@chromium-experiment:~/chromium/src$ ./out/Default/chrome --version
Chromium 89.0.4354.0

無事、Chromium を Build することが出来ました 🎉

ステップ4. Build した chrome binary を実行してみる

せっかくなので、Build した chrome binary を実行してみましょう。

まず、何も考えずに $ ./out/Default/chrome で実行してみます。すると、以下のようにエラーになります。Unable to open X display. と出ているので、display 周りの設定が必要なようです。

minami@chromium-experiment:~/chromium/src$ ./out/Default/chrome
[203604:203604:1212/184031.352086:INFO:content_main_runner_impl.cc(1027)] Chrome is running in full browser mode.
[203604:203604:1212/184031.944147:ERROR:browser_main_loop.cc(1429)] Unable to open X display.
[203604:203604:1212/184031.944774:FATAL:tracing_controller_impl.cc(390)] Check failed: g_tracing_controller.
.
.
.
Calling _exit(1). Core file will not be generated.

minami@chromium-experiment:~/chromium/src$ ./out/Default/chrome
[203604:203604:1212/184031.352086:INFO:content_main_runner_impl.cc(1027)] Chrome is running in full browser mode.
[203604:203604:1212/184031.944147:ERROR:browser_main_loop.cc(1429)] Unable to open X display.
[203604:203604:1212/184031.944774:FATAL:tracing_controller_impl.cc(390)] Check failed: g_tracing_controller.
#0 0x7fb4a0717aff base::debug::CollectStackTrace()
#1 0x7fb4a04a12fa base::debug::StackTrace::StackTrace()
#2 0x7fb4a04a12b5 base::debug::StackTrace::StackTrace()
#3 0x7fb4a04ed039 logging::LogMessage::~LogMessage()
#4 0x7fb4a04ed779 logging::LogMessage::~LogMessage()
#5 0x7fb4a0460b4b logging::CheckError::~CheckError()
#6 0x7fb498aa543f content::TracingControllerImpl::GetInstance()
#7 0x7fb49780d847 content::BrowserMainRunnerImpl::Shutdown()
#8 0x7fb49780cd14 content::BrowserMainRunnerImpl::~BrowserMainRunnerImpl()
#9 0x7fb49780cd69 content::BrowserMainRunnerImpl::~BrowserMainRunnerImpl()
#10 0x7fb4977fb75c std::__Cr::default_delete<>::operator()()
#11 0x7fb4977fb6ea std::__Cr::unique_ptr<>::reset()
#12 0x7fb4977fb649 std::__Cr::unique_ptr<>::~unique_ptr()
#13 0x7fb4977fb280 content::BrowserMain()
#14 0x7fb4999c16d6 content::RunBrowserProcessMain()
#15 0x7fb4999c2cf9 content::ContentMainRunnerImpl::RunBrowser()
#16 0x7fb4999c25e7 content::ContentMainRunnerImpl::Run()
#17 0x7fb4999bf915 content::RunContentProcess()
#18 0x7fb4999c02ad content::ContentMain()
#19 0x55dd5fee70cb ChromeMain
#20 0x55dd5fee6f82 main
#21 0x7fb46988f0b3 __libc_start_main
#22 0x55dd5fee6e7a _start

Received signal 6
#0 0x7fb4a0717aff base::debug::CollectStackTrace()
#1 0x7fb4a04a12fa base::debug::StackTrace::StackTrace()
#2 0x7fb4a04a12b5 base::debug::StackTrace::StackTrace()
#3 0x7fb4a07175cb base::debug::(anonymous namespace)::StackDumpSignalHandler()
#4 0x7fb46a1f23c0 (/usr/lib/x86_64-linux-gnu/libpthread-2.31.so+0x153bf)
#5 0x7fb4698ae18b gsignal
#6 0x7fb46988d859 abort
#7 0x7fb4a0716c06 base::debug::(anonymous namespace)::DebugBreak()
#8 0x7fb4a0716be5 base::debug::BreakDebugger()
#9 0x7fb4a04ed639 logging::LogMessage::~LogMessage()
#10 0x7fb4a04ed779 logging::LogMessage::~LogMessage()
#11 0x7fb4a0460b4b logging::CheckError::~CheckError()
#12 0x7fb498aa543f content::TracingControllerImpl::GetInstance()
#13 0x7fb49780d847 content::BrowserMainRunnerImpl::Shutdown()
#14 0x7fb49780cd14 content::BrowserMainRunnerImpl::~BrowserMainRunnerImpl()
#15 0x7fb49780cd69 content::BrowserMainRunnerImpl::~BrowserMainRunnerImpl()
#16 0x7fb4977fb75c std::__Cr::default_delete<>::operator()()
#17 0x7fb4977fb6ea std::__Cr::unique_ptr<>::reset()
#18 0x7fb4977fb649 std::__Cr::unique_ptr<>::~unique_ptr()
#19 0x7fb4977fb280 content::BrowserMain()
#20 0x7fb4999c16d6 content::RunBrowserProcessMain()
#21 0x7fb4999c2cf9 content::ContentMainRunnerImpl::RunBrowser()
#22 0x7fb4999c25e7 content::ContentMainRunnerImpl::Run()
#23 0x7fb4999bf915 content::RunContentProcess()
#24 0x7fb4999c02ad content::ContentMain()
#25 0x55dd5fee70cb ChromeMain
#26 0x55dd5fee6f82 main
#27 0x7fb46988f0b3 __libc_start_main
#28 0x55dd5fee6e7a _start
r8: 0000000000000000 r9: 00007ffd3f1f1e30 r10: 0000000000000008 r11: 0000000000000246
r12: 000055dd5fee6e50 r13: 00007ffd3f1f4180 r14: 0000000000000000 r15: 0000000000000000
di: 0000000000000002 si: 00007ffd3f1f1e30 bp: 00007ffd3f1f2080 bx: 00007fb45b9f0340
dx: 0000000000000000 ax: 0000000000000000 cx: 00007fb4698ae18b sp: 00007ffd3f1f1e30
ip: 00007fb4698ae18b efl: 0000000000000246 cgf: 002b000000000033 erf: 0000000000000000
trp: 0000000000000000 msk: 0000000000000000 cr2: 0000000000000000
[end of stack trace]
Calling _exit(1). Core file will not be generated.

そこで、Getting Started with Headless Chrome を参考に、headless mode で Chromium を起動してみることにします。以下のように --headless オプションを渡して chrome binary を実行することで、ちゃんと起動することが確認できました 🎉

minami@chromium-experiment:~/chromium/src$ ./chromium/src/out/Default/chrome --headless --disable-gpu --remote-debugging-port=9222 https://www.chromestatus.com
[0124/153340.940562:WARNING:headless_content_main_delegate.cc(530)] Cannot create Pref Service with no user data dir.
[0124/153340.942433:INFO:content_main_runner_impl.cc(1027)] Chrome is running in full browser mode.

DevTools listening on ws://127.0.0.1:9222/devtools/browser/bab01154-70d7-4b82-8bcb-b8beec05a94b
[0124/153345.275372:WARNING:http_cache_transaction.cc(1192)] Unable to open or create cache entry
[0124/153345.293075:WARNING:http_cache_transaction.cc(1192)] Unable to open or create cache entry

もう少し遊んでみましょう。Chromium は、--dump-dom オプションを渡すことで、指定した URL のページを取得して document.body.innerHTML の内容を標準出力に print してくれます。試しに実行してみると、以下のようにちゃんと https://example.com のページからコンテンツを取得した上で、その内容を print してくれます。自分で Build した Chromium が、ちゃんとページ取得の動作をすることが確認できました 🎉

minami@chromium-experiment:~/chromium/src$ ./out/Default/chrome --headless --disable-gpu --dump-dom https://example.com
[0124/155618.269750:WARNING:headless_content_main_delegate.cc(530)] Cannot create Pref Service with no user data dir.
[0124/155618.271645:INFO:content_main_runner_impl.cc(1027)] Chrome is running in full browser mode.
<!DOCTYPE html>
<html><head>
    <title>Example Domain</title>

    <meta charset="utf-8">
    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style type="text/css">
    body {
        background-color: #f0f0f2;
        margin: 0;
        padding: 0;
        font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;

    }
    div {
        width: 600px;
        margin: 5em auto;
        padding: 2em;
        background-color: #fdfdff;
        border-radius: 0.5em;
        box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
    }
    a:link, a:visited {
        color: #38488f;
        text-decoration: none;
    }
    @media (max-width: 700px) {
        div {
            margin: 0 auto;
            width: auto;
        }
    }
    </style>
</head>

<body>
<div>
    <h1>Example Domain</h1>
    <p>This domain is for use in illustrative examples in documents. You may use this
    domain in literature without prior coordination or asking for permission.</p>
    <p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>


</body></html>
[0124/155619.646701:ERROR:process_posix.cc(335)] Unable to terminate process 2345: No such process (3)
[0124/155619.646976:WARNING:internal_linux.cc(66)] Failed to read /proc/2345/stat
[0124/155619.650882:WARNING:discardable_shared_memory_manager.cc(432)] Some MojoDiscardableSharedMemoryManagerImpls are still alive. They will be leaked.

さらに、--screenshot オプションを渡すことで、スクリーンショットを撮ることもできます。試しに https://example.com に対して実行してみると、以下のように screenshot.png という画像ファイルが生成されます。

minami@chromium-experiment:~/chromium/src$ ./out/Default/chrome --headless --disable-gpu --screenshot https://example.com
[0124/162636.934902:WARNING:headless_content_main_delegate.cc(530)] Cannot create Pref Service with no user data dir.
[0124/162636.936935:INFO:content_main_runner_impl.cc(1027)] Chrome is running in full browser mode.
[0124/162638.402065:INFO:headless_shell.cc(616)] Written to file screenshot.png.
[0124/162638.466196:ERROR:process_posix.cc(335)] Unable to terminate process 3074: No such process (3)
[0124/162638.466571:WARNING:internal_linux.cc(66)] Failed to read /proc/3074/stat
[0124/162638.469149:WARNING:discardable_shared_memory_manager.cc(432)] Some MojoDiscardableSharedMemoryManagerImpls are still alive. They will be leaked.
minami@chromium-dev-20210123:~/chromium/src$ gsutil cp ./screenshot.png gs://chromium-dev-south37/screenshot.png
Copying file://./screenshot.png [Content-Type=image/png]...
/ \[1 files\][ 26.4 KiB/ 26.4 KiB]
Operation completed over 1 objects/26.4 KiB.

minami@chromium-dev-20210123:~/chromium/src$ ls -la screenshot.png
-rw------- 1 minami minami 27069 Jan 24 16:26 screenshot.png

screenshot.png をダウンロードして内容を見てみると、以下のような内容になっています。これは https://example.com を手元の Chrome で開いた時と同一の内容になっています。自分で Build した Chromium が、ちゃんとページを Render し、さらにスクリーンショットまで撮れることが確認できました 🎉

ステップ5. 高速な Build を体感する

Chromium をゼロから Build する」というステップ3では、かなりの時間がかかりました。一方、一度 Build した状態からでは、高速な Build が行えるようになります。これは、Ninja が最終成果物からの依存関係を check していて、「依存先に変更があった場合のみ、再 Build を行う」ようになっているためです(注: Ninja だけでなく、Make も同様の挙動をします)。

例えば、何も書き換えない状態で $ autoninja -C out/Default chrome を実行した場合は、Build は 5 秒程度で終了します。この場合、ソースコードに変更はないので chrome binary にも変更は行われません。

minami@chromium-experiment:~/chromium/src$ time autoninja -C out/Default chrome
ninja: Entering directory `out/Default'
ninja: no work to do.

real    0m5.676s
user    0m4.074s
sys     0m0.919s

次に、chrome/common/channel_info.cc という file を touch して timestamp を更新してみます。以下の document によれば Ninja は Make と同様に file timestamp を利用して更新を check しているらしいので、これで依存する file は Build が行われるはずです。

Ninja is closest in spirit and functionality to Make, relying on simple dependencies between file timestamps.

cf. https://ninja-build.org/manual.html

今度は、以下のように obj/chrome/common/channel_info/channel_info.o の Build が行われる様子が観測できました。さらに、時間経過とともに LINK などの step に進み、15 秒程度で chrome binary の Build が終了します。

minami@chromium-experiment:~/chromium/src$ touch chrome/common/channel_info.cc
minami@chromium-experiment:~/chromium/src$ time autoninja -C out/Default chrome
ninja: Entering directory `out/Default'
[0/4] CXX obj/chrome/common/channel_info/channel_info.o
minami@chromium-experiment:~/chromium/src$ time autoninja -C out/Default chrome
ninja: Entering directory `out/Default'
[2/4] SOLINK ./libvr_common.so
minami@chromium-experiment:~/chromium/src$ time autoninja -C out/Default chrome
ninja: Entering directory `out/Default'
[4/4] LINK ./chrome

real    0m15.238s
user    0m18.995s
sys     0m4.492s

何かしら file を変更した場合でも、依存した file だけが Build 対象となるため、「Chromium をゼロから Build する」というステップ3に比べると 圧倒的に高速に Build が出来る ことが分かります。

また、chrome binary の Build の様子を見ていると、LINK ステップにかかる時間が長いことに気づきます。 lld の作者の rui さんが「Link にかかる時間を減らすことが開発生産性に繋がる」という話をしているのを聞いた記憶がありますが、それが実感できる機会となりました。

まとめ

ChromiumLinux 上でゼロから Build して動かしてみました。トータルでかかった時間は6-7時間程度とかなり長いので気軽に試すのは難しいですが、「巨大なソフトウェアであっても Build して動かすことが出来る」ということが確かめられたと思います。

また、一度動くところまで持っていけば、「少し変えて動かして試す」ということが簡単に出来るようになるので、ソフトウェアに対しての理解を深めやすくなります。これをきっかけに Chromium に対して理解を深めたいと思います。