2021年に読んで印象に残った本について
2021年の振り返りでも書きましたが、昨年は、隙を見ては本を読んだりコードを読んだりして過ごしていました。印象に残っている本について、ジャンルごとにまとめてみたいと思います。
Java 関連の本
昨年転職してから、仕事で本格的に Java を読み書きするようになりました。勉強のためにいくつか本を読んだのですが、印象に残っているのは以下の2つです。
Effective Java
これは、Java プラットフォームの多くの機能の設計及び実装を経験してきた著者ジョシュア・ブロックさんが、Java の様々な機能についてその使い方や注意点を説明した本です。言語の機能を設計する側だった人が著者なので、記述について信頼性や納得感があるのが特徴です。
自分は Java の文法は把握していたものの、「Java にとっての良いコードとはどういったものか」の知見がなかったので、とても勉強になりました。特に、Java は長い歴史の中で機能が追加されてきた背景もあり、同じことをするのにもいくつか異なる記述が可能となっているので(e.g. 配列 vs List、null vs Optional、for loop vs stream、etc)、どういったメリット・デメリットがあるか、どう使い分けるのかについて知見を得られたのが良かったです。
Java パフォーマンス
Java アプリケーションのパフォーマンス改善に必要な知見をまとめた本です。パフォーマンス計測についての一般的な知識から、Java 特有の知識(Java 用のツールや JVM の挙動、etc.)までをまとめています。
個人的には、JVM の挙動について理解が深められた点が有用でした。JVM には JIT コンパイラや GC アルゴリズムとしていくつかの種類があるのですが、その種類や挙動、チューニング方法についてまとめられていて、勉強になりました。
なお、原著が出たのが 2014 年と Java 8 が最新だった時代なので、情報が少し古い点については注意する必要があります。
OS・コンピュータアーキテクチャ関連の本
ゼロからの OS 自作入門
これは、著者が自作した OS のコードが GitHub 上で公開 されていて、動くコードを読み書きしながら、手を動かして OS について学べる本です。あまりに内容が面白かったので、購入してしばらくはずっとこの本を読んでいました。
基本的には「著者が書いた OS のコードについて説明を行う」という内容なのですが、完成形のコードについて説明をするのではなく、とてもシンプルなコードからスタートしてステップバイステップで少しずつ機能を足していく構成となっているのが特徴です。そのため、常に全体像を理解した状態でコードを動かすことができます。
本物の PC で、自分の書いたコードを USB ブートで起動して遊ぶことができるのも素晴らしい点です。自分は昔利用していたノート PC を引っ張り出して動かしてみていたのですが、それだけでもとても楽しかったです。
x86 の仕様や UEFI の機能について、OS を動かす上で必要になる知識を網羅的に学べるので、PC についての「ソフトウェアから見た全体感」を掴むことができるのも良い点でした。「さらなる学び」の出発点となることが出来る本だと感じてます。
構造化コンピュータ構成
「ゼロからの OS 自作入門」を読んで、コンピュータについてもっと詳しくなりたいと感じた時に古本屋で見つけた本です。コンピュータアーキテクチャを「1. デジタルロジックレベル」、「2. マイクロアーキテクチャレベル」、「3. ISA レベル」、「4. オペレーティングシステムマシンレベル」、「5. アセンブリ言語レベル」という5段階の階層からなるものとして捉えた上で、下から順に積み上げる形で説明がなされています。コンピュータアーキテクチャの全体像を下から上まで包括的に理解するための優れた本という印象です。
原著が 1998 年発売なので時代は感じるものの、幅広いトピックについて扱われていてとても勉強になりました。個人的には、バス(特に ISA バスや PCI バス)についての知識が得られた点と、マイクロアーキテクチャを実例を通して学べた点が特に気に入っています。
ディジタル回路設計とコンピュータアーキテクチャ[ARM版]
ARM アーキテクチャを題材に、デジタル回路やコンピュータアーキテクチャについて説明した本です。x86 以外の ISA について知りたくなり、ARM について学ぶために読みました。序盤はデジタルロジックレベルの説明なので ARM は関係ありませんが、説明がかなり丁寧で良い内容でした。中盤以降は ARM の命令セットについて理解を深めることができる内容となっていました。
x86 はよく命令が複雑と呼ばれていますが、実はこれまではあまりピンと来ていませんでした。しかし、後方互換性を保つために増え続けた命令や可変長で複雑なマシン語などを見ていると、確かに ARM(特に AArch64)と比較すると複雑だと感じるようになりました。比較対象が出来たことで理解が深まったように感じています。
Linux デバイスドライバ関連の本
「コンピュータについてもっと詳しくなりたい」と感じた気持ちの延長で、一時期 Linux デバイスドライバ関係の本を読んでいました。
Linuxデバイスドライバの開発
Linux のデバイスドライバについてベーシックな内容を学べる本です。デバイスドライバの書き方自体については、本当に基礎的な部分だけを説明されている印象です。ただし、動かせるコードサンプルがついているので、自分で書き換えながら学べる点が気に入っています。
最初の数ページでいきなり Buildroot を利用した Linux カーネルのビルドを行うことになり、その点については少し驚きました。しかし、そのおかげで Linux カーネルのビルドに対して心理的抵抗が減ったのは結果的には良かったです。
Linux デバイスドライバ 第3版
Linux用のデバイスドライバについて詳細な解説がなされた本です。デバイスドライバについてもう少し詳しい内容が知りたいと思い、買いました。こちらも豊富なサンプルコードをもとに解説されている点がとても良いです。古い本であるため記述やサンプルコードが古いのが難点ですが、以下のレポジトリでは、現在の Linux Kernl で動くサンプルコードが公開されています。(自分の手元の Ubuntu 20.04 でもちゃんと動きました)
https://github.com/martinezjavier/ldd3
Linux デバイスドライバにはいくつか種類があるのですが、基本的には device file としてインターフェースを表現し、必要な callback 関数(e.g. open, read, etc.)を実装することでその機能を実現する、という内容を学べたのが良かったです。
並行プログラミング関連の本
並行プログラミング入門
並行プログラミングというトピック自体が好きなので、発売と同時に買って読んだ本です。最初に並行性、並列性についてきちんと定義を述べた上で、アセンブリ言語のレベルから高級言語のレベルに至るまで並行処理に必要な機能について説明されている点が良かったです。
個人的に、ARM (AArch64) の ldaxr や stlxr などの Load-Link/Store-Conditional 命令については知らなかったので、勉強になりました。x86 のように compare and exchange 命令を持っているものと思い込んでいたので、異なるアプローチをとっていることが驚きでした。
全体的にコードでのサンプルが豊富に掲載されているので、動かしながら学べるのも良い点です。Rust のコードが多数掲載されていて、Rust についての勉強にもなりました。
まとめ
2021年に読んで印象に残った本について、ジャンルごとにまとめてみました。全体的に、コンピュータの基礎について学び直す内容が多かったように思います。すぐに応用には結びつかなくとも大事な部分ではあるので、ゆっくりと学ぶ機会を作れて良かったと考えています。
2021年の振り返り
年が明けて 2022 年になりました。良い機会なので、2021年について簡単に振り返ってみたいと思います。
仕事面の振り返り
仕事面では、転職というとても大きな変化がありました。今の会社で働き始めたのは5月11日なので、8ヶ月弱ほど経ったことになります。初の転職なのでどうなるか少しドキドキしていましたが、とても楽しく仕事が出来ています。
入社以来開発に携わってきたアプリは10月末(日本では11月1日)にリリース出来ました。多くの人に楽しんでもらえて、とても嬉しく思っています。また、身近な友人や知人からも「プレイしているよ」という声を聞くことが出来て、とても幸せなことだと感じています。
5月に Niantic に入社してから、開発に携わってきた「Pikmin Bloom」がついにリリースされました!
— south37/Nao Minami (@south37777) November 1, 2021
今日から日本でも公開されたので、ぜひ遊んでみて欲しいです! 歩くことが楽しくなるアプリです! https://t.co/ea71JUkuun
自分の開発したものを通じて人々の生活にポジティブな変化を与えられていることが純粋に嬉しいです。今後も、より一層この動きを加速させていければと思っています。
プライベートの振り返り
2021年は結婚を機に引っ越しをして、プライベートの生活も大きく変わりました。新しく住み始めたのは閑静な住宅街で、とても住みやすく気に入っています。
プライベートの時間では、平日・休日問わず、隙を見ては本を読んだりコードを読んだりして過ごしていました。学んだことも多くあり、良かったと思います。読んだ本については、また別エントリでまとめたいと思います。追記: 2021年に読んで印象に残った本についてというエントリを書きました。
まとめ
2021年を簡単に振り返ってみました。見返してみると、仕事とプライベートの両方で変化の多い年だったと感じています。
個人的な考えとして、人間は変化を恐れてコンフォートゾーンにとどまってしまいがちだと考えているので、そこを抜け出す動きを出来たのは良かったです。2022 年も、チャレンジを常に心がけて、コンフォートゾーンを抜け出して日々を過ごしていきたいです。
日本のスタートアップで 6 年間働いたあと、シリコンバレーのスタートアップへ転職する話
2021年4月末最終出社で Wantedly を退職して、5月からは Niantic でソフトウェアエンジニアとして働き始めることになりました。
Wantedly へ 2015 年4月に入社してから、ちょうど6年間働いたことになります。良い機会なので、Wantedly に関する思い出を振り返ってみたいと思います。
また、Niantic で働くことに対しての抱負なども書き残しておこうと思います。全体として長くなってしまったのはご容赦ください。
なお、タイトルは少しキャッチーにしてしまいましたが、実際に働くのは Niantic: Tokyo Studio という東京にある開発拠点です。
Wantedly との出会い
自分が Wantedly という会社を最初に認識したのは 2014 年 2 月初頭でした。まだ、大学院修士1年の学生だった頃です。当時は Wantedly の「会社に話を聞きにいくサービス(= 今の Wantedly Visit)」自体を知らなかったのですが、たまたま何かのきっかけで目にすることになりました。
PC 版の Web サイトを眺めていると、「掲載されているのは知らない企業ばかりなのに、どれも魅力的に見える」のが新鮮な体験だったのを覚えています(注: 当時は Wantedly の iOS アプリは開発中で、まだリリースされていませんでした)。しばらく募集を見ていると Wantedly の募集が見つかり、「プラットフォームが自社の募集も出している」というのが面白くて、軽い気持ちで「話を聞きにいきたい」ボタンを押しました。すぐに返事がきて、その日のうちに「話を聞きにいく日程」が決まっていました。
会社に行った際には開発チームのメンバーや開発フローなどを紹介してもらい、さらにエンジニア全員でランチに行きました。当時はまだエンジニアは5名程度、社員全員でも10数名程度だったと記憶しています。色々話をしたのですが、気がつくと3月の春休み中に1週間ほど短期インターンをしようという話になっていました。そして、3月のインターンを経て、面接を受け、内定をもらいました。
当時の自分は(Wantedly 以外では)エンジニアリングのバイトや就業型インターンへの参加経験が無く、そんな自分をスタートアップの Wantedly が採用してくれたことがとても嬉しかったです。少数精鋭のすごいエンジニアが集まる組織に加わることで、自分が成長出来ることへの期待にワクワクしました。
なお、振り返ってみると、当時の経営陣にとって「1年後に入社する学生を採用する」というのはなかなかリスキーな選択肢だったのではないかと思います。リスクをとってくれたお陰で今の自分はあると思うので、感謝しています。
Wantedly での最初の3年間(= プロダクト開発チーム時代)
内定から1年後、2015年に Wantedly に入社しました。同時期に入社したメンバーも含めると、2014年からの1年間でエンジニアは倍以上に増えて、「急成長するスタートアップらしさ」を感じたのを覚えています。
Wantedly に入社してから最初の3年間は、プロダクト開発のエンジニアとして以下の3つのプロダクトのリリースとグロースに携わりました。平均すると毎年1つのサービスを新しくリリースしていた計算になります(注: 実際には最初の2年で3つリリースして、最後の1年はグロースに注力してました)。
- 会いたい候補者に直接メッセージを届ける「Wantedly スカウト」
- 社内で利用するツールを紹介し合う口コミサービス「Wantedly Tools」
- クリエイター向けポートフォリオサービス「CASE」
2015年に入社後、最初は1人のエンジニアとして「スカウト」のリリースとグロースに携わりました。途中からは、チーム内で技術的なリードを行うテックリード的な役割を担うようになりました。さらに、プロダクトの戦略を考えて機能に落とし込むプロダクトマネージャー的な役割も兼務するようになりました。
そもそも、Wantedly には「エンジニアあるいはデザイナーがプロダクトマネージャーの役割を兼務する」という文化があります。その文化の表れとして、エンジニアとデザイナーからなる開発チーム全体を「個別のプロダクト(or 機能)にオーナーシップを持つ小さなチーム」に分割して、その分割されたチームがそれぞれのプロダクト戦略と数字目標に責任を持つ、という体制で開発を行っていました。それぞれのチームにはリーダーがいて、最終的にはリーダーが数字目標やプロダクト(or 機能)の方向性に責任を持ちます。自分もそういったリーダーの1人でした。
プロダクト開発チームにいた時代はやる事が多くて大変でしたが、一方で「プロダクト開発のライフサイクル」や「様々なトレードオフ」、「ステークホルダーと調整しながら上手くプロジェクトを進める方法」など多くのことを学んだように思います。例えば、書籍「アジャイルサムライ」に出てくる「時間(リリーススケジュール)とスコープ(機能)とクオリティのトレードオフ」などは実感を持って体感出来ました。リリーススケジュールや人的リソースなど様々な制約がある中でどうインパクトを出すかを常に考え、そのために「優先度付け」や「小さなコストでの素早い学び」の重要性を強く意識しました。また、継続的にプロダクトの改善を行うために、「ソフトウェアが変更容易な状態を保つためにどういった設計にするか」ということも考え続けていました。
振り返ってみると、プロダクト開発を行った最初の3年間の経験は、その後の自分の仕事の進め方に強く影響を与えたように思います。
(ちなみにこれは余談ですが、最初に名前をあげた3つのプロダクトのうち、「Wantedly Tools」と「CASE」については昨年4月にサービス終了となりました。様々な事情もありしょうがないのですが、立ち上げに関わっていた1人としては少し寂しくもあります。。。)
Wantedly インフラチームへの異動
3年間プロダクト開発を行った後で、2018年にインフラチームへ異動しました。これは、自分の意向と会社の意向が以下のように重なったことで生まれた動きです。
- 自分の意向: プロダクトの数字目標がある中で、分析や戦略の考案に時間を使う場面も多かった。それは楽しくチャレンジングである一方で、「エンジニアリングに使える時間を増やしたい」という気持ちがあった。また、個人的に学んでいた「スケーラブルなシステムの構築方法(e.g. 分散システムの知識、パフォーマンスチューニングの知識、低レイヤの知識、etc.)」などの知識を活かしたいと思ったこと、2010年代のインフラ領域のテクノロジーの発展に強い興味を持っていたことなども後押しをした。
- 会社の意向: システムのマイクロサービス化(= チームごとに固有の Repository と Service を持つ状況)が進む中で、アプリケーションレイヤーにガッツリ手を入れてチーム横断での基盤整備が出来る人が欲しかった。
実はこの時は他社も含めて検討したのですが、最終的には「Wantedly のインフラチームで基盤整備をするのが一番面白そう」だと判断しました。
ここで、インフラチームで取り組んだことについて書く前に、「Wantedly のインフラチームがそもそもどういったチームなのか」について軽く説明しておきます。Wantedly のシステムは基本的に全て Kubernetes Cluster の上で動いていて、インフラチームは Kubernetes を中心に基盤(= 開発ツールや開発環境、CI/CD の仕組み、各種ライブラリ、etc.)の整備を行っています。これは、全体像としては以下のような3レイヤーでシステムを捉えられることを意味します。
[Application (= Microservices)] [Kubernetes] [Cloud (= AWS, GCP)]
一番下は「Cloud レイヤー」で、これは AWS や GCP などのクラウドサービスを表しています。Wantedly は全てのサービスをクラウドに乗せているため、一番下がこのレイヤーになります。下から2つ目は「Kubernetes レイヤー」で、Kubernetes Cluster やその機能拡張を行う各種 Custom Controller、Kubernetes の API サーバーへリクエストしてデプロイなどを行う CLI ツールが該当します。一番上が 「Application レイヤー」で、Kubernetes 上で動く様々なマイクロサービスを表しています。Wantedly のインフラチームは、この3つのレイヤー全てにアプローチするチーム となっています。
強調しておきたいのは、「インフラチームは『依頼を受けて Cloud リソースを用意するチーム』ではない」 ということです。我々は「依頼を受けて何かする」のではなく、「仕組みを作って社内の開発者が自分で必要なものを揃えられるようにする」ということを重要視していました。例えば Cloud リソースは Terraform を利用して Git 管理を行い、「開発者が自分たちに必要なものは自分たちで PR を出して作る」ということを可能にしていました。また、新しくマイクロサービスを追加したい場合も、「開発者が自分たちで Kubernetes 向けの Manifest file を用意して Apply 出来るようにする」ことで、インフラチームがボトルネックにならずに済む様にしていました。マイクロサービス開発が活発になってからは、開発生産性とシステムの信頼性の両方を高めるために、「社内外で利用されるライブラリの開発や、マイクロサービスアーキテクチャの改善」なども行なっていました。
インフラチームは、開発チームのメンバーそれぞれがオーナーシップを持ってマイクロサービス開発の全プロセスに携われる様に「仕組みを整える」ことに注力していました。
なお、この辺りは infrastructure_README.md というドキュメント にもまとめています。これは、Wantedly のインフラチームの活動を社外の方に説明する際に利用していたドキュメントです。CTO や後任のインフラチームリーダーから許可をもらったので、ここに掲載しておきます。詳細が気になる方は、こちらも参照してみてください。
自分がインフラチームで取り組んだプロジェクトのうち、主要なものは以下になります。
- マイクロサービスアーキテクチャ改善
- Cloud Pub/Sub の基盤整備と社内利用促進
- gRPC の基盤整備と社内利用促進
- その他細かいプロジェクト多数
- プロダクト開発チームのマイクロサービス開発サポート
- Kubernetes cluster 管理(ニーズに応じた構成変更、Version up、Custom controller 導入、etc.)
- 新人研修の企画・実施
- etc.
上記のプロジェクトを進める際は、「システムのマイクロサービス化が進む中で開発チームの日々の取り組みをいかにスケールさせるか」、「ツールやライブラリやシステムによる基盤をどのように提供するか」、「高い信頼性と高パフォーマンスを両立するシステムをどう実現するか」を常に考えていました。「様々なマイクロサービスから利用されるコアマイクロサービスの開発」や「社内で利用されるライブラリの開発」は、そのためのアプローチの 1 つです。「基盤として提供する事で、開発者が自然と恩恵が受けられる」という体験を意識していました。
その他、OSS 化や取り組みの発信も積極的に行うようにしていました。結果として、取り組み自体を社外の方に知ってもらう機会を増やせたのは良かったなと思っています。
インフラチームで仕事を進める中で、途中からは技術的なリードや People Management にも取り組むようになりました。数人のチームのマネージャーとして、チームのパフォーマンスを最大化させるための取り組みを出来たのは良い経験となったと思います。「改善され続ける組織やチーム」というものに自分は思い入れが強くて、それを意識しつつ、「チームが目指すゴールの設定、チームの日々のワークフロー改善、Member との 1on1、採用活動、etc.」などに取り組みました。
ここまでが、2021年4月までに Wantedly で仕事として取り組んだ内容です。
Wantedly での日々を振り返ってみて
Wantedly での日々を振り返ってみると、ちょうど3年間の区切りで「プロダクト開発チーム」、「インフラチーム」と新しい環境にチャレンジしていたことが分かります。それぞれに異なる難しさがあったように思いますが、どの時代も「学び」はありました。ここまでに書いてきたことと重なりますが、あえて「学び」を書き出すと以下のような内容になると思います。
- プロダクト開発チーム時代 .. プロダクトをどう成長させるか、様々な制約条件の中でプロジェクトをどう進めるか、ソフトウェアが変更容易な状態を保つためにどういった設計にするか、etc.
- インフラチーム時代 .. プロダクト開発チームの日々の取り組みをどうスケールさせるか、ツールやライブラリやシステムによる基盤をどのように提供するか、高い信頼性と高パフォーマンスを両立するシステムをどう実現するか、etc.
- 注: プロダクト開発チーム時代と同様の学びももちろんある
Wantedly には様々なチャレンジの機会を与えてもらい、そのお陰で成長出来たと思っています。感謝しています。一方で、自分が生み出した価値も相当量あると思っていて、十分に恩返しは出来たのかなとも感じています。
Niantic への転職について
自分にとって、 Wantedly という会社は今でも好きな会社です。一方で、以下のようなモチベーションがあり、それはすぐには達成出来ないというもどかしさもありました。
- 世界中で多数のユーザーに使われるプロダクトの開発に携わりたい
- 「大量のデータを扱い、多数のトラフィックを捌く」という技術的チャレンジをしたい
- 「自分の変更が世界中の人々の活動にポジティブな影響を与える」という実感を得たい
そういったモチベーションを持って検討した結果、縁あって Niantic からオファーをいただけることになりました。
Niantic は自分が Pokémon GO ユーザーだったこともあり、憧れていた会社の1つです。そういった会社で働けることを、とても嬉しく思っています。入社後は、3月にアナウンスがあった「ピクミンを起用したアプリ」のサーバーサイド開発を行うことになりそうです。リリースされた際にはぜひ遊んでいただけると嬉しいです。
実は、Niantic からオファーをもらった直後はあまり実感が湧きませんでした。しかしながら、しばらくすると様々なグッズが会社から送られてきて、現実として認識できるようになりました。送られてきたグッズの中でも以下のトートバッグはお気に入りで、日常生活でも使い始めています。
転職とチャレンジ
今回の転職は、様々な面で自分にとってチャレンジだと思っています。例えば、以下のように多くの観点から「自分にとって初めての取り組み」となっています。
- 初めての転職
- 初めての米国企業
- 初めてのゲーム開発
- 初めての仕事での Java 開発
- 初めての「世界中で使われるプロダクト(= 大量のデータを扱い、多数のトラフィックを捌く必要のあるプロダクト)」の開発
- etc.
不安はゼロではないですが、それも含めて「新しいチャレンジ」をとても楽しみにしています。
オフトピック: 選考プロセスについて
具体的には書きませんが、Niantic の選考プロセスは一般的な外資ソフトウェア企業とあまり変わらないんじゃないかと思います。実は、自分は1年以上前に Google の SWE ポジションで面接を受けて、技術選考は通った(= Phone Interview, Onsite Interview を受けた上で採用委員会から Approve をもらった)ことがあります。2020年はその後色々あり、結局 Google では採用には至りませんでしたが、この経験は役に立ったように思います。
また、これは自分が勝手に思っていることかもしれませんが、選考の中では自分の「スタートアップでの経験」も評価してくれたように感じています。Niantic は(Wantedly よりも大きいとはいえ)まだまだスタートアップなので、経験が活きる部分もあるんじゃないかと期待しています。
まとめ
Wantedly での6年間を振り返ってみました。また、Niantic への転職について、考えをまとめてみました。
自分にとって、この転職は様々な点からチャレンジだと思っています。このチャレンジを楽しみたいと思います。
最後になりますが、今回の転職にあたっては様々な方にお世話になりました。この場を借りてお礼申し上げます。
mold の Build 手順メモ
はじめに
mold と呼ばれる高速なリンカを利用して Chromium を Build してみる という記事の中で、mold と呼ばれる「高速なリンカ」について紹介しました。
https://github.com/rui314/mold
mold は、自分の知る限りでは現時点では特に Binary の配信などは行っていないようです。利用したい場合には repository を git clone して、自分で Build して利用する必要があります。
mold の Build 手順についてメモ程度に記録を残しておこうと思います。
2021年3月20日追記: ちょうど4日ほど前に mold の README に How to build というセクションが追加されたようです。最新のソースコードで Build する場合は、そちらを参照してみてください。cf. https://github.com/rui314/mold#how-to-build
ステップ1. mold のソースコードを取得する
まず、mold の git repository を clone します。
minami@chromium-dev-20210227:~$ git clone https://github.com/rui314/mold.git minami@chromium-dev-20210227:~$ ls mold minami@chromium-dev-20210227:~$ cd mold/
mold は自身が依存する mimalloc と oneTBB を git submodule
として利用しているので、git submodule update --init
を実行してこれらのソースコードを取得します。
minami@chromium-dev-20210227:~/mold$ git submodule update --init Submodule 'mimalloc' (https://github.com/microsoft/mimalloc.git) registered for path 'mimalloc' Submodule 'oneTBB' (https://github.com/oneapi-src/oneTBB.git) registered for path 'oneTBB' Cloning into '/home/minami/mold/mimalloc'... Cloning into '/home/minami/mold/oneTBB'... Submodule path 'mimalloc': checked out '4cc8bff90d9e081298ca2c1a94024c7ad4a9e478' Submodule path 'oneTBB': checked out 'eca91f16d7490a8abfdee652dadf457ec820cc37'
これで、必要なソースコードの取得は完了しました。
ステップ2. 必要な package を install して Build する
make, libssl-dev, zlib1g-dev, cmake, build-essential
を利用するので、apt で install しておきます(cmake, build-essential
は git submodule で取り込んだ mimalloc と oneTBB の Build に利用します)。
minami@chromium-dev-20210227:~/mold$ sudo apt update minami@chromium-dev-20210227:~/mold$ sudo apt install -y make libssl-dev zlib1g-dev cmake build-essential
$ make submodules
で、submodule で取り込んだ oneTBB と mimalloc を Build します。
minami@chromium-dev-20210227:~/mold$ make submodules make -C oneTBB make[1]: Entering directory '/home/minami/mold/oneTBB' Created the ./build/linux_intel64_gcc_cc9.3.0_libc2.31_kernel5.4.0_release directory make -C "./build/linux_intel64_gcc_cc9.3.0_libc2.31_kernel5.4.0_release" -r -f ../../build/Makefile.tbb cfg=release make[2]: Entering directory '/home/minami/mold/oneTBB/build/linux_intel64_gcc_cc9.3.0_libc2.31_kernel5.4.0_release' . . . make[2]: Leaving directory '/home/minami/mold/oneTBB/build/linux_intel64_gcc_cc9.3.0_libc2.31_kernel5.4.0_release' make[1]: Leaving directory '/home/minami/mold/oneTBB' mkdir -p mimalloc/out/release (cd mimalloc/out/release; cmake ../..) . . . [100%] Built target mimalloc-test-api make[2]: Leaving directory '/home/minami/mold/mimalloc/out/release' make[1]: Leaving directory '/home/minami/mold/mimalloc/out/release'
これで、oneTBB と mimalloc の Build は完了しました。
いよいよ、mold の Build を行いたいと思いいます。ただし、この状態では clang++
が無いのでまだ Build できません。
minami@chromium-dev-20210227:~/mold$ make clang++ -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o main.o main.cc make: clang++: Command not found make: *** [<builtin>: main.o] Error 127
clang++
の install では、https://apt.llvm.org/ の「Automatic installation script」である bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
を利用する事にします。
minami@chromium-dev-20210227:~/mold$ sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" --2021-02-27 00:50:07-- https://apt.llvm.org/llvm.sh . . . Processing triggers for install-info (6.7.0.dfsg.2-5) ... Processing triggers for libc-bin (2.31-0ubuntu9.2) ...
これで、clang++-11
が install されます(注: 2021/02/27 時点の話で、時期によって最新 version は違うかもしれません)。
clang++
として利用できるように、symlink を貼っておきます。
minami@chromium-dev-20210227:~/mold$ ls /usr/bin | grep clang clang++-11 clang-11 clang-cpp-11 clangd-11 minami@chromium-dev-20210227:~/mold$ sudo ln -s /usr/bin/clang++-11 /usr/bin/clang++
これで clang++ は使えるようになりましたが、まだ「span header が見つからない」というエラーが出る状態です。
minami@chromium-dev-20210227:~/mold$ make clang++ -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o main.o main.cc In file included from main.cc:1: ./mold.h:17:10: fatal error: 'span' file not found #include <span> ^~~~~~ 1 error generated. make: *** [<builtin>: main.o] Error 1
make
で実行されているコマンドに -v
オプションをつけると詳細が表示されるのですが、この include path の中で span
が見つからないのが原因のようです。
minami@chromium-dev-20210227:~/mold$ clang++ -v -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o main.o main.cc Ubuntu clang version 11.1.0-++20210204121720+1fdec59bffc1-1~exp1~20210203232336.162 Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9 Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9 Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9 Candidate multilib: .;@m64 Selected multilib: .;@m64 (in-process) "/usr/lib/llvm-11/bin/clang" -cc1 -triple x86_64-pc-linux-gnu -emit-obj -disable-free -disable-llvm-verifier -discard-value-names -main-file-name main.cc -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debug-info-kind=limited -dwarf-version=4 -debugger-tuning=gdb -v -resource-dir /usr/lib/llvm-11/lib/clang/11.1.0 -I oneTBB/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/x86_64-linux-gnu/c++/9 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/x86_64-linux-gnu/c++/9 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-11/lib/clang/11.1.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-deprecated-volatile -Wno-switch -std=c++20 -fdeprecated-macro -fdebug-compilation-dir /home/minami/mold -ferror-limit 19 -pthread -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -fcolor-diagnostics -vectorize-loops -vectorize-slp -faddrsig -o main.o -x c++ main.cc clang -cc1 version 11.1.0 based upon LLVM 11.1.0 default target x86_64-pc-linux-gnu ignoring nonexistent directory "oneTBB/include" ignoring nonexistent directory "/include" ignoring duplicate directory "/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/x86_64-linux-gnu/c++/9" #include "..." search starts here: #include <...> search starts here: /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9 /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/x86_64-linux-gnu/c++/9 /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/backward /usr/local/include /usr/lib/llvm-11/lib/clang/11.1.0/include /usr/include/x86_64-linux-gnu /usr/include End of search list. In file included from main.cc:1: ./mold.h:17:10: fatal error: 'span' file not found #include <span> ^~~~~~ 1 error generated.
ここで、おもむろに libstdc++-10-dev
package の install をします。
minami@chromium-dev-20210227:~/mold$ sudo apt install -y libstdc++-10-dev
上記 package を install すると、ちゃんと span
header を見つけることができます。
minami@chromium-dev-20210227:~/mold$ clang++ -v -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o main.o main.cc Ubuntu clang version 11.1.0-++20210204121720+1fdec59bffc1-1~exp1~20210203232336.162 Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10 Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9 Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/10 Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9 Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10 Candidate multilib: .;@m64 Selected multilib: .;@m64 (in-process) "/usr/lib/llvm-11/bin/clang" -cc1 -triple x86_64-pc-linux-gnu -emit-obj -disable-free -disable-llvm-verifier -discard-value-names -main-file-name main.cc -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debug-info-kind=limited -dwarf-version=4 -debugger-tuning=gdb -v -resource-dir /usr/lib/llvm-11/lib/clang/11.1.0 -I oneTBB/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-11/lib/clang/11.1.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-deprecated-volatile -Wno-switch -std=c++20 -fdeprecated-macro -fdebug-compilation-dir /home/minami/mold -ferror-limit 19 -pthread -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -fcolor-diagnostics -vectorize-loops -vectorize-slp -faddrsig -o main.o -x c++ main.cc clang -cc1 version 11.1.0 based upon LLVM 11.1.0 default target x86_64-pc-linux-gnu ignoring nonexistent directory "/include" ignoring duplicate directory "/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10" #include "..." search starts here: #include <...> search starts here: oneTBB/include /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward /usr/local/include /usr/lib/llvm-11/lib/clang/11.1.0/include /usr/include/x86_64-linux-gnu /usr/include End of search list.
少し探してみると /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10
の中に span header があるのを見つけました。これが重要だったようです。
minami@chromium-dev-20210227:~/mold$ ls -la /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/span -rw-r--r-- 1 root root 13251 Aug 8 2020 /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/span
この状態で make を実行すると、mold の Build が行われて、mold
Binary が生成されるはずです。
minami@chromium-dev-20210227:~/mold$ make clang++ -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o output_chunks.o output_chunks.cc clang++ -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o mapfile.o mapfile.cc clang++ -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o perf.o perf.cc clang++ -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o linker_script.o linker_script.cc clang++ -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o archive_file.o archive_file.cc clang++ -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o output_file.o output_file.cc clang++ -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o subprocess.o subprocess.cc clang++ -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o gc_sections.o gc_sections.cc clang++ -g -IoneTBB/include -pthread -std=c++20 -Wno-deprecated-volatile -Wno-switch -O2 -c -o icf.o icf.cc clang++ main.o object_file.o input_sections.o output_chunks.o mapfile.o perf.o linker_script.o archive_file.o output_file.o subprocess.o gc_sections.o icf.o -o mold -L/home/minami/mold/oneTBB/build/linux_intel64_gcc_cc9.3.0_libc2.31_kernel5.4.0_release/ -Wl,-rpath=/home/minami/mold/oneTBB/build/linux_intel64_gcc_cc9.3.0_libc2.31_kernel5.4.0_release/ -L/home/minami/mold/mimalloc/out/release -Wl,-rpath=/home/minami/mold/mimalloc/out/release -lcrypto -pthread -ltbb -lmimalloc
以下のように mold
Binary が生成されていれば成功です 🎉
minami@chromium-dev-20210227:~/mold$ ls -la mold -rwxrwxr-x 1 minami minami 11142376 Feb 27 01:43 mold
まとめ
「高速なリンカである mold」について、Build 手順をまとめました。
今後、mold が広く使われるようになり、package での配信などが行われるようになればここに記載した手順はおそらく不要になると思います。しかしながら、mold はまだ開始したばかりの project であり、開発環境なども未整備の状態です。しばらくは、「自分で Build して動かしてみる」という状態が続くでしょう。
このブログが、「試しに mold を利用してみる」ことへの一助となれば幸いです。
mold と呼ばれる高速なリンカを利用して Chromium を Build してみる
はじめに
現在、広く使われているリンカの中でもっとも高速なものとして有名なのは LLVM project の LLD でしょう。LLD のパフォーマンスについては、公式 document に以下のような benchmark が掲載されていて、GNU ld, GNU gold などと比較して圧倒的に早いという結果が示されています。
Program | Output size | GNU ld | GNU gold w/o threads | GNU gold w/threads | lld w/o threads | lld w/threads |
---|---|---|---|---|---|---|
ffmpeg dbg | 92 MiB | 1.72s | 1.16s | 1.01s | 0.60s | 0.35s |
mysqld dbg | 154 MiB | 8.50s | 2.96s | 2.68s | 1.06s | 0.68s |
clang dbg | 1.67 GiB | 104.03s | 34.18s | 23.49s | 14.82s | 5.28s |
chromium dbg | 1.14 GiB | 209.05s [1] | 64.70s | 60.82s | 27.60s | 16.70s |
cf. https://lld.llvm.org/#performance
Chromium を Checking out and building Chromium on Linux の手順にしたがって Build する場合、デフォルトで LLD が利用されるようになっています。そのため、何もせずとも「高速なリンク」という恩恵を受けることができるようになっています。
一方、LLD の author である Rui Ueyama さんが最近活発に開発しているのが mold と呼ばれるリンカです。
https://github.com/rui314/mold
こちらは個人 project として開発を進めているようなのですが、既にかなりの完成度のようで、「LLD 以上に高速なリンク」を実現しているようです。
mold、完全に目処がついたと言ってよさそう。Chromeをリンクするのに2.5秒、直前に同一コマンドを実行してファイルをプリロードしておくと、ほとんどの入力ファイルが同じ場合に0.8秒という結果になった(16スレッドでテスト)。ほかのリンカだと最低10秒かかるから、めちゃくちゃ速いといっていい。
— Rui Ueyama (@rui314) 2020年12月22日
今日は、この「最も高速なリンカである mold」を利用した Chromium の Build を試してみたいと思います。
ステップ1. Linux マシンを用意する
この部分は 前回 と同様です。
GCP の Compute Engine で以下の VM Instance を立ててそこで作業を行うことにします。
以下のコマンドで ssh して、そこで作業を行います。
$ gcloud beta compute ssh --zone "asia-northeast1-b" <instance 名>
ステップ2. mold を Build する
mold は、自分の知る限りでは現時点では特に Binary の配信などは行っていないようです。利用したい場合には https://github.com/rui314/mold を git clone して、自分で Build して利用する必要があります。
この部分の手順は別途またブログにまとめたいと思います。 追記: この部分の手順は mold の Build 手順メモ に記載しました。そちらを参照してみてください。
mold
Binary が生成されて、以下のように利用できるようになっていれば OK です。
minami@chromium-dev-20210227:~$ git clone https://github.com/rui314/mold.git # ここで、mold を Build minami@chromium-dev-20210227:~$ ls -l /home/minami/mold/mold -rwxrwxr-x 1 minami minami 11142376 Feb 27 01:43 /home/minami/mold/mold
ステップ3. Chromium の Build 環境を整える。
Chromium を Build して動かすまでの待ち時間を「7 時間」から「30 分」まで高速化してみる を参照して、Chromium の Build 環境を整えます。30分 もかからずに、chrome
Binary を Build できる環境が整うはずです。
ステップ4. chrome Binary の Build に利用されているリンカを確認しておく
ここでは、事前に「$ autoninja -C out/Default chrome
で Build をしたときに chrome
Binary のリンクに利用されていたリンカは何者なのか」をチェックしてみます。
$ autoninja -C out/Default chrome
を実行して、[4/4] LINK ./chrome
のタイミングで起動している process を $ ps fax
で見てみます。そうすると、以下のように /home/minami/chromium/src/out/Default/../../third_party/llvm-build/Release+Asserts/bin/ld.lld
が利用されていることが分かります。
minami@chromium-dev-20210227:~$ ps fax PID TTY STAT TIME COMMAND . . . 1343 pts/0 S+ 0:00 | \_ bash /home/minami/depot_tools/autoninja -C out/Default chrome 1455 pts/0 S+ 0:07 | \_ /home/minami/depot_tools/ninja-linux64 -C out/Default chrome -j 10 1484 pts/0 S 0:00 | \_ /bin/sh -c python "../../build/toolchain/gcc_link_wrapper.py" --output="./chrome" -- ../../third_party/llvm-build/Release+Asserts/bin/clang++ -fuse-ld=lld -Wl,--fatal-warnings -Wl,--build-id -fPIC -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,defs -Wl,--as-needed -Wl,--color-diagnostics -Wl,--no-call-graph-profile-sor 1485 pts/0 S 0:00 | \_ python ../../build/toolchain/gcc_link_wrapper.py --output=./chrome -- ../../third_party/llvm-build/Release+Asserts/bin/clang++ -fuse-ld=lld -Wl,--fatal-warnings -Wl,--build-id -fPIC -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,defs -Wl,--as-needed -Wl,--color-diagnostics -Wl,--no-call-graph-profile-sort -m64 -Wer 1486 pts/0 S 0:00 | \_ ../../third_party/llvm-build/Release+Asserts/bin/clang++ -fuse-ld=lld -Wl,--fatal-warnings -Wl,--build-id -fPIC -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,defs -Wl,--as-needed -Wl,--color-diagnostics -Wl,--no-call-graph-profile-sort -m64 -Werror -Wl,--gdb-index -rdynamic -nostdlib++ --sysroot=../../build/li 1487 pts/0 D 0:03 | \_ /home/minami/chromium/src/out/Default/../../third_party/llvm-build/Release+Asserts/bin/ld.lld @/tmp/response-96ee6b.txt
/home/minami/chromium/src/out/Default/../../third_party/llvm-build/Release+Asserts/bin
direcotory は以下のように clang や lld が入っていて、「LLVM project の toolchain が格納された directory」のようです。
minami@chromium-dev-20210227:~$ cd /home/minami/chromium/src/out/Default/../../third_party/llvm-build/Release+Asserts/bin minami@chromium-dev-20210227:~/chromium/src/third_party/llvm-build/Release+Asserts/bin$ ls clang clang++ clang-cl ld64.lld ld64.lld.darwinnew ld.lld lld lld-link llvm-ar llvm-objcopy llvm-pdbutil llvm-symbolizer llvm-undname
ld.lld
は lld
への symlink
が貼られています。これが LLVM project の高速なリンカである LLD です。
minami@chromium-dev-20210227:~/chromium/src/third_party/llvm-build/Release+Asserts/bin$ ls -la ld.lld lrwxrwxrwx 1 minami minami 3 Dec 12 12:50 ld.lld -> lld
minami@chromium-dev-20210227:~/chromium/src/third_party/llvm-build/Release+Asserts/bin$ ./ld.lld --help OVERVIEW: lld USAGE: ./ld.lld [options] file... . . . ./ld.lld: supported targets: elf
LLD が利用されていることは、生成された chrome Binary からも確かめることができます。LLVM project の document である Using LLD - LLVM には以下のように「readelf
コマンドで .comment
section を読み取ると Linker: LLD
という記述があるはず」と記載されています。
LLD leaves its name and version number to a .comment section in an output. If you are in doubt whether you are successfully using LLD or not, run
readelf --string-dump .comment <output-file>
and examine the output. If the string “Linker: LLD” is included in the output, you are using LLD.
実際に「Build した chrome
Binary」に対して readelf
を実行してみると、確かに Linker: LLD 12.0.0
という記述を見つけることができます。
minami@chromium-dev-20210227:~/chromium/src$ readelf --string-dump .comment out/Default/chrome String dump of section '.comment': [ 0] GCC: (Debian 7.5.0-3) 7.5.0 [ 1c] clang version 12.0.0 (https://github.com/llvm/llvm-project/ 6ee22ca6ceb71661e8dbc296b471ace0614c07e5) [ 82] Linker: LLD 12.0.0 (https://github.com/llvm/llvm-project/ 6ee22ca6ceb71661e8dbc296b471ace0614c07e5)
ここまで、利用されているリンカが何なのかを確認しました。それ以外に、chrome
Binary の Build の際に実行される script もチェックしておきます。これは、autoninja
コマンドに -v
オプションをつけることで出力することができます。この情報は後々利用します。
minami@chromium-dev-20210227:~/chromium/src$ time autoninja -v -C out/Default chrome ninja: Entering directory `out/Default' [1/4] ../../third_party/llvm-build/Release+Asserts/bin/clang++ -MMD -MF obj/chrome/common/channel_info/channel_info.o.d -DUSE_UDEV -DUSE_AURA=1 -DUSE_GLIB=1 -DUSE_NSS_CERTS=1 -DUSE_OZONE=1 -DUSE_X11=1 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_GNU_SOURCE -DCR_CLANG_REVISION=\"llvmorg-12-init-12923-g6ee22ca6-1\" -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DCOMPONENT_BUILD -D_LIBCPP_ABI_UNSTABLE -D_LIBCPP_ABI_VERSION=Cr -D_LIBCPP_ENABLE_NODISCARD -D_LIBCPP_DEBUG=0 -DCR_LIBCXX_REVISION=375504 -DCR_SYSROOT_HASH=22f2db7711f7426a364617bb6d78686cce09a8f9 -D_DEBUG -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_40 -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_40 -DWEBP_EXTERN=extern -DABSL_CONSUME_DLL -DBORINGSSL_SHARED_LIBRARY -I../.. -Igen -I../../third_party/perfetto/include -Igen/third_party/perfetto/build_config -Igen/third_party/perfetto -I../../third_party/libwebp/src -I../../third_party/abseil-cpp -I../../third_party/boringssl/src/include -I../../third_party/protobuf/src -Igen/protoc_out -fno-delete-null-pointer-checks -fno-strict-aliasing --param=ssp-buffer-size=4 -fstack-protector -funwind-tables -fPIC -pthread -fcolor-diagnostics -fmerge-all-constants -fcrash-diagnostics-dir=../../tools/clang/crashreports -mllvm -instcombine-lower-dbg-declare=0 -fcomplete-member-pointers -m64 -march=x86-64 -msse3 -Wno-builtin-macro-redefined -D__DATE__= -D__TIME__= -D__TIMESTAMP__= -Xclang -fdebug-compilation-dir -Xclang . -no-canonical-prefixes -Wall -Werror -Wextra -Wimplicit-fallthrough -Wunreachable-code -Wthread-safety -Wextra-semi -Wno-missing-field-initializers -Wno-unused-parameter -Wno-c++11-narrowing -Wno-unneeded-internal-declaration -Wno-undefined-var-template -Wno-psabi -Wno-ignored-pragma-optimize -Wno-implicit-int-float-conversion -Wno-final-dtor-non-final-class -Wno-builtin-assume-aligned-alignment -Wno-deprecated-copy -Wno-non-c-typedef-for-linkage -Wmax-tokens -O0 -fno-omit-frame-pointer -g2 -Xclang -debug-info-kind=constructor -gsplit-dwarf -ggnu-pubnames -ftrivial-auto-var-init=pattern -fvisibility=hidden -Xclang -add-plugin -Xclang find-bad-constructs -Xclang -plugin-arg-find-bad-constructs -Xclang check-ipc -Wheader-hygiene -Wstring-conversion -Wtautological-overlap-compare -isystem../../build/linux/debian_sid_amd64-sysroot/usr/include/glib-2.0 -isystem../../build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu/glib-2.0/include -DPROTOBUF_ALLOW_DEPRECATED=1 -Wno-undefined-bool-conversion -Wno-tautological-undefined-compare -std=c++14 -fno-trigraphs -Wno-trigraphs -fno-exceptions -fno-rtti -nostdinc++ -isystem../../buildtools/third_party/libc++/trunk/include -isystem../../buildtools/third_party/libc++abi/trunk/include --sysroot=../../build/linux/debian_sid_amd64-sysroot -fvisibility-inlines-hidden -c ../../chrome/common/channel_info.cc -o obj/chrome/common/channel_info/channel_info.o [2/4] touch obj/chrome/common/channel_info.stamp [3/4] python "../../build/toolchain/gcc_solink_wrapper.py" --readelf="readelf" --nm="nm" --sofile="./libvr_common.so" --tocfile="./libvr_common.so.TOC" --output="./libvr_common.so" -- ../../third_party/llvm-build/Release+Asserts/bin/clang++ -shared -Wl,-soname="libvr_common.so" -fuse-ld=lld -Wl,--fatal-warnings -Wl,--build-id -fPIC -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,defs -Wl,--as-needed -Wl,--color-diagnostics -Wl,--no-call-graph-profile-sort -m64 -Werror -Wl,--gdb-index -rdynamic -nostdlib++ --sysroot=../../build/linux/debian_sid_amd64-sysroot -L../../build/linux/debian_sid_amd64-sysroot/usr/local/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu -Wl,-rpath=\$ORIGIN -o "./libvr_common.so" @"./libvr_common.so.rsp" [4/4] python "../../build/toolchain/gcc_link_wrapper.py" --output="./chrome" -- ../../third_party/llvm-build/Release+Asserts/bin/clang++ -fuse-ld=lld -Wl,--fatal-warnings -Wl,--build-id -fPIC -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,defs -Wl,--as-needed -Wl,--color-diagnostics -Wl,--no-call-graph-profile-sort -m64 -Werror -Wl,--gdb-index -rdynamic -nostdlib++ --sysroot=../../build/linux/debian_sid_amd64-sysroot -L../../build/linux/debian_sid_amd64-sysroot/usr/local/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu -pie -Wl,--disable-new-dtags -Wl,-rpath=\$ORIGIN -o "./chrome" -Wl,--start-group @"./chrome.rsp" ./libbase.so ./libabsl.so ./libboringssl.so ./libperfetto.so ./libbindings.so ./libbindings_base.so ./libmojo_public_system_cpp.so ./libmojo_public_system.so ./libmojo_cpp_platform.so ./libmessage_support.so ./libmojo_mojom_bindings.so ./libmojo_mojom_bindings_shared.so ./liburl_mojom_traits.so ./libmojo_base_mojom_shared.so ./libmojo_base_shared_typemap_traits.so ./libmojo_base_lib.so ./libbase_i18n.so ./libicui18n.so ./libicuuc.so ./liburl.so ./libui_base.so ./libui_base_features.so ./libui_data_pack.so ./libskia.so ./libgfx.so ./libcolor_space.so ./libcolor_utils.so ./libgeometry.so ./libgeometry_skia.so ./libgfx_switches.so ./libanimation.so ./libcodec.so ./librange.so ./libcc_paint.so ./libcc_base.so ./libcc_debug.so ./libfile_info.so ./libevents_base.so ./libplatform.so ./libkeycodes_x11.so ./libui_base_x.so ./libcontent_public_common_mojo_bindings_shared.so ./libmojom_platform_shared.so ./libandroid_mojo_bindings_shared.so ./libauthenticator_test_mojo_bindings_shared.so ./libcolor_scheme_mojo_bindings_shared.so ./libmojom_mhtml_load_result_shared.so ./libscript_type_mojom_shared.so ./libweb_feature_mojo_bindings_mojom_shared.so ./libservice_manager_mojom_shared.so ./libservice_manager_mojom_constants_shared.so ./libdom_storage_mojom_shared.so ./libframe_mojom_shared.so ./libblink_gpu_mojom_shared.so ./libservice_worker_storage_mojom_shared.so ./libtokens_mojom_shared.so ./libusb_shared.so ./libmojo_base_mojom.so ./libmojo_base_typemap_traits.so ./libcontent_settings_features.so ./libipc.so ./libipc_mojom.so ./libipc_mojom_shared.so ./libprotobuf_lite.so ./libtracing_cpp.so ./libstartup_tracing.so ./libtracing_mojom.so ./libtracing_mojom_shared.so ./libnet.so ./libcrcrypto.so ./libskia_shared_typemap_traits.so ./libcontent.so ./libgpu.so ./libmailbox.so ./libcrash_key_lib.so ./libchrome_zlib.so ./libvulkan_info.so ./libgfx_ipc.so ./libgfx_ipc_geometry.so ./libvulkan_ycbcr_info.so ./liburl_ipc.so ./libviz_common.so ./libviz_resource_format_utils.so ./libviz_vulkan_context_provider.so ./libdisplay.so ./libdisplay_types.so ./libgl_wrapper.so ./libmedia.so ./libshared_memory_support.so ./libleveldb_proto.so ./libkeyed_service_core.so ./libleveldatabase.so ./libgfx_ipc_color.so ./libgfx_ipc_buffer_types.so ./libgfx_ipc_skia.so ./libgfx_native_types_shared_mojom_traits.so ./libgfx_shared_mojom_traits.so ./libgpu_shared_mojom_traits.so ./liblearning_common.so ./libmedia_learning_shared_typemap_traits.so ./libmedia_session_base_cpp.so ./libcookies_mojom_support.so ./libnetwork_cpp_base.so ./libcrash_keys.so ./libcross_origin_embedder_policy.so ./libip_address_mojom_support.so ./libschemeful_site_mojom_support.so ./libwebrtc_component.so ./libservice_manager_mojom.so ./libservice_manager_mojom_constants.so ./libservice_manager_cpp_types.so ./libservice_manager_mojom_traits.so ./libservice_manager_cpp.so ./libmetrics_cpp.so ./libui_base_clipboard_types.so ./libevents.so ./libui_base_cursor_base.so ./libdisplay_shared_mojom_traits.so ./libcc.so ./libvideo_capture_mojom_support.so ./libcapture_base.so ./liblatency_shared_mojom_traits.so ./libprediction.so ./libblink_common.so ./libprivacy_budget.so ./libnetwork_cpp.so ./libweb_feature_mojo_bindings_mojom.so ./libmojom_modules_shared.so ./libmojom_core_shared.so ./libfido.so ./libbluetooth.so ./libscript_type_mojom.so ./libcc_ipc.so ./libcc_shared_mojom_traits.so ./libdom_storage_mojom.so ./libframe_mojom.so ./libblink_gpu_mojom.so ./libservice_worker_storage_mojom.so ./libtokens_traits.so ./libime_shared_mojom_traits.so ./libui_base_ime_types.so ./libui_events_ipc.so ./libweb_bluetooth_mojo_bindings_shared.so ./libax_base.so ./libui_accessibility_ax_mojom.so ./libui_accessibility_ax_mojom_shared.so ./libui_base_ime.so ./libcontent_common_mojo_bindings_shared.so ./libaccessibility.so ./libgfx_x11.so ./libxprotos.so ./libaura.so ./libcompositor.so ./libblink_features.so ./libsurface.so ./libpolicy.so ./libnetwork_service.so ./libmemory_instrumentation.so ./libresource_coordinator_public_mojom.so ./libresource_coordinator_public_mojom_shared.so ./libstorage_common.so ./libpublic.so ./libinterfaces_shared.so ./libstorage_service_filesystem_mojom_shared.so ./libstorage_service_filesystem_mojom.so ./libstorage_service_typemap_traits.so ./libmedia_session_cpp.so ./libstorage_browser.so ./libvr_public_cpp.so ./libdevice_vr_isolated_xr_service_mojo_bindings.so ./libdevice_vr_isolated_xr_service_mojo_bindings_shared.so ./libdevice_vr_test_mojo_bindings_shared.so ./libdevice_vr_service_mojo_bindings_shared.so ./libgamepad_mojom_shared.so ./libdevice_vr_test_mojo_bindings.so ./libdevice_vr_service_mojo_bindings.so ./libgamepad_mojom.so ./libgamepad_shared_typemap_traits.so ./libshared_with_blink.so ./libdevice_vr_public_typemaps.so ./libchrome_features.so ./libprefs.so ./libvariations_features.so ./liburl_matcher.so ./libcapture_lib.so ./libmedia_webrtc.so ./libwtf.so ./libcommon.so ./libnetwork_session_configurator.so ./libsql.so ./libchromium_sqlite3.so ./libwebdata_common.so ./libos_crypt.so ./libomnibox_http_headers.so ./libcloud_policy_proto_generated_compile.so ./libpolicy_component.so ./libpolicy_proto.so ./libgcm.so ./libnative_theme.so ./libservice_provider.so ./libui_message_center_cpp.so ./libppapi_shared.so ./libmojo_core_embedder.so ./libprinting.so ./libsandbox_services.so ./libsuid_sandbox_client.so ./libseccomp_bpf.so ./libsecurity_state_features.so ./libui_base_clipboard.so ./libui_base_data_transfer_policy.so ./libkeyed_service_content.so ./libuser_prefs.so ./libextras.so ./libsessions.so ./libcaptive_portal_core.so ./libdevice_features.so ./libweb_modal.so ./libdevice_event_log.so ./libshell_dialogs.so ./libui_base_idle.so ./libdbus.so ./libonc.so ./libhost.so ./libukm_recorder.so ./libcrdtp.so ./libuser_manager.so ./libperformance_manager_public_mojom.so ./libperformance_manager_public_mojom_shared.so ./libviews.so ./libui_base_ime_init.so ./libui_base_cursor_theme_manager.so ./libui_base_cursor.so ./libx11_window.so ./libui_touch_selection.so ./libproxy_config.so ./libtab_groups.so ./libmanager.so ./libmessage_center.so ./libfontconfig.so ./libx11_events_platform.so ./libdevices.so ./libevents_devices_x11.so ./libevents_x.so ./libffmpeg.so ./libwebview.so ./libdomain_reliability.so ./liblookalikes_features.so ./libui_devtools.so ./libdata_exchange.so ./libgesture_detection.so ./libsnapshot.so ./libweb_dialogs.so ./libcolor.so ./libmixers.so ./libdiscardable_memory_service.so ./libAPP_UPDATE.so ./libozone.so ./libozone_base.so ./libdisplay_util.so ./libvulkan_wrapper.so ./libplatform_window.so ./libui_base_ime_linux.so ./libfreetype_harfbuzz.so ./libmenu.so ./libproperties.so ./libthread_linux.so ./libgtk.so ./libgtk_ui_delegate.so ./libbrowser_ui_views.so ./libwm.so ./libmedia_message_center.so ./libtab_count_metrics.so ./libui_gtk_x.so ./libwm_public.so ./libppapi_host.so ./libppapi_proxy.so ./libcertificate_matching.so ./libdevice_base.so ./libswitches.so ./libcapture_switches.so ./libmidi.so ./libmedia_mojo_services.so ./libmedia_gpu.so ./libgles2_utils.so ./libgles2.so ./libgpu_ipc_service.so ./libgl_init.so ./libcert_net_url_loader.so ./liberror_reporting.so ./libevents_ozone.so ./libschema_org_common.so ./libmirroring_service.so ./libvr_common.so ./libvr_base.so ./libdevice_vr.so ./libblink_controller.so ./libblink_core.so ./libblink_mojom_broadcastchannel_bindings_shared.so ./libwtf_support.so ./libweb_feature_mojo_bindings_mojom_blink.so ./libmojo_base_mojom_blink.so ./libservice_manager_mojom_blink.so ./libservice_manager_mojom_constants_blink.so ./libblink_platform.so ./libcc_animation.so ./libresource_coordinator_public_mojom_blink.so ./libv8.so ./libblink_embedded_frame_sink_mojo_bindings_shared.so ./libperformance_manager_public_mojom_blink.so ./libui_accessibility_ax_mojom_blink.so ./libgin.so ./libblink_modules.so ./libgamepad_mojom_blink.so ./liburlpattern.so ./libdevice_vr_service_mojo_bindings_blink.so ./libdevice_vr_test_mojo_bindings_blink.so ./libdiscardable_memory_client.so ./libcbor.so ./libpdfium.so ./libheadless_non_renderer.so ./libc++.so -Wl,--end-group -ldl -lpthread -lrt -lgmodule-2.0 -lgobject-2.0 -lgthread-2.0 -lglib-2.0 -lnss3 -lnssutil3 -lsmime3 -lplds4 -lplc4 -lnspr4 -latk-1.0 -latk-bridge-2.0 -lcups -ldbus-1 -lgio-2.0 -lexpat real 0m15.202s user 0m19.157s sys 0m4.398s
ステップ5. mold を利用して chrome
Binary をリンクしてみる
さて、ここまでで「chrome
のリンクに LLD が利用されていること」、「コマンドとしては /home/minami/chromium/src/out/Default/../../third_party/llvm-build/Release+Asserts/bin/ld.lld
が利用されていること」が確認できました。
次は、LLD の代わりに mold を利用してみたいと思います。ここでは、「ld.lld
の symlink の向き先を lld
から mold
に切り替えて、Build する」というアプローチをとってみます。
以下のように ld.lld
を消して、symlink の向き先を /home/minami/mold/mold
に変えてみます。
minami@chromium-dev-20210227:~$ cd /home/minami/chromium/src/out/Default/../../third_party/llvm-build/Release+Asserts/bin minami@chromium-dev-20210227:~/chromium/src/third_party/llvm-build/Release+Asserts/bin$ rm ld.lld minami@chromium-dev-20210227:~/chromium/src/third_party/llvm-build/Release+Asserts/bin$ ln -s /home/minami/mold/mold ld.lld minami@chromium-dev-20210227:~/chromium/src/third_party/llvm-build/Release+Asserts/bin$ ls -la ld.lld lrwxrwxrwx 1 minami minami 22 Feb 28 03:06 ld.lld -> /home/minami/mold/mold
これで、mold が利用されるようになるはずです。この状態で再度 chrome の Build をしてみます。
ただ、この状態で $ autoninja -C out/Default chrome
を実行すると、以下のように [3/4] SOLINK ./libvr_common.so
のステップでリンクに失敗してしまします。
minami@chromium-dev-20210227:~/chromium/src$ time autoninja -C out/Default chrome ninja: Entering directory `out/Default' [3/4] SOLINK ./libvr_common.so FAILED: libvr_common.so libvr_common.so.TOC python "../../build/toolchain/gcc_solink_wrapper.py" --readelf="readelf" --nm="nm" --sofile="./libvr_common.so" --tocfile="./libvr_common.so.TOC" --output="./libvr_common.so" -- ../../third_party/llvm-build/Release+Asserts/bin/clang++ -shared -Wl,-soname="libvr_common.so" -fuse-ld=lld -Wl,--fatal-warnings -Wl,--build-id -fPIC -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,defs -Wl,--as-needed -Wl,--color-diagnostics -Wl,--no-call-graph-profile-sort -m64 -Werror -Wl,--gdb-index -rdynamic -nostdlib++ --sysroot=../../build/linux/debian_sid_amd64-sysroot -L../../build/linux/debian_sid_amd64-sysroot/usr/local/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu -Wl,-rpath=\$ORIGIN -o "./libvr_common.so" @"./libvr_common.so.rsp" mold: unknown command line option: -soname=libvr_common.so clang: error: linker command failed with exit code 1 (use -v to see invocation) ninja: build stopped: subcommand failed. real 0m5.480s user 0m4.577s sys 0m0.746s
mold が -soname
オプションをサポートしてないために、エラーが出ているようです。
上記の python "../../build/toolchain/gcc_solink_wrapper.py" ...
という部分が [3/4] SOLINK ./libvr_common.so
のステップとして実際に実行されているコマンドです。ここから、「mold がサポートしていないオプション」を消して、同じコマンドを手動で実行してみます。具体的には、-soname
, --color-diagnostics
, --no-call-graph-profile-sort
, --gdb-index
オプションの指定を消して、以下のように実行します。こうすると、ちゃんと mold によるリンクに成功して、 libvr_common.so
という Shared Object File が生成されます。
minami@chromium-dev-20210227:~/chromium/src/out/Default$ time python "../../build/toolchain/gcc_solink_wrapper.py" --readelf="readelf" --nm="nm" --sofile="./libvr_common.so" --tocfile="./libvr_common.so.TOC" --output="./libvr_common.so" -- ../../third_party/llvm-build/Release+Asserts/bin/clang++ -shared -fuse-ld=lld -Wl,--fatal-warnings -Wl,--build-id -fPIC -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,defs -Wl,--as-needed -m64 -Werror -rdynamic -nostdlib++ --sysroot=../../build/linux/debian_sid_amd64-sysroot -L../../build/linux/debian_sid_amd64-sysroot/usr/local/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu -Wl,-rpath=\$ORIGIN -o "./libvr_common.so" @"./libvr_common.so.rsp" real 0m0.563s user 0m0.033s sys 0m0.029s minami@chromium-dev-20210227:~/chromium/src/out/Default$ ls -la libvr_common.so -rwxrwxr-x 1 minami minami 192508187 Feb 28 03:14 libvr_common.so
上記の python script の実行が、[3/4] SOLINK ./libvr_common.so
に相当する処理でした。さらに、 [4/4] LINK ./chrome
に相当する処理も、直接 python script の実行を行う事にします。これは、ステップ4の最後に $ autoninja -v -C out/Default chrome
コマンドで出力したコマンドの、[4/4] python "../../build/toolchain/gcc_link_wrapper.py" --output="./chrome" -- ...(長いので省略)
が該当します。
ただ、この状態で [4/4] LINK ./chrome
に相当する python script を実行しても、以下のように chrome.rsp
という File が無いことで失敗してしまいます。
minami@chromium-dev-20210227:~/chromium/src/out/Default$ python "../../build/toolchain/gcc_link_wrapper.py" --output="./chrome" -- ...(長いので省略) clang: error: no such file or directory: '@./chrome.rsp'
そこで、一度 ld.lld
の symlink 先を lld に戻してから、$ autoninja -C out/Default chrome
の実行中に [4/4] LINK ./chrome
のタイミングで Ctrl-C で python script を強制 exit してみます。
こうすることで、「libvr_common.so
とchrome.rsp
が存在する状態(ちょうど [4/4] LINK ./chrome
の開始前の状態」を再現することが出来ます。
minami@chromium-dev-20210227:~/chromium/src$ ls out/Default/libvr_common.so out/Default/libvr_common.so minami@chromium-dev-20210227:~/chromium/src$ ls out/Default/chrome.rsp out/Default/chrome.rsp
この状態で、再度 ld.lld
の symlink 先を mold にしてから、[4/4] LINK ./chrome
に相当する python script を手動で実行します。mold でサポートされてない --color-diagnostics
, --no-call-graph-profile-sort
, --gdb-index
オプションの指定は消しておきます。
こうすると、以下のようにちゃんとリンクに成功します。chrome
Binary が生成されたことも確認できます。
minami@chromium-dev-20210227:~/chromium/src/out/Default$ time python "../../build/toolchain/gcc_link_wrapper.py" --output="./chrome" -- ../../third_party/llvm-build/Release+Asserts/bin/clang++ -fuse-ld=lld -Wl,--fatal-warnings -Wl,--build-id -fPIC -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,defs -Wl,--as-needed -m64 -Werror -rdynamic -nostdlib++ --sysroot=../../build/linux/debian_sid_amd64-sysroot -L../../build/linux/debian_sid_amd64-sysroot/usr/local/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu -pie -Wl,--disable-new-dtags -Wl,-rpath=\$ORIGIN -o "./chrome" -Wl,--start-group @"./chrome.rsp" ./libbase.so ./libabsl.so ./libboringssl.so ./libperfetto.so ./libbindings.so ./libbindings_base.so ./libmojo_public_system_cpp.so ./libmojo_public_system.so ./libmojo_cpp_platform.so ./libmessage_support.so ./libmojo_mojom_bindings.so ./libmojo_mojom_bindings_shared.so ./liburl_mojom_traits.so ./libmojo_base_mojom_shared.so ./libmojo_base_shared_typemap_traits.so ./libmojo_base_lib.so ./libbase_i18n.so ./libicui18n.so ./libicuuc.so ./liburl.so ./libui_base.so ./libui_base_features.so ./libui_data_pack.so ./libskia.so ./libgfx.so ./libcolor_space.so ./libcolor_utils.so ./libgeometry.so ./libgeometry_skia.so ./libgfx_switches.so ./libanimation.so ./libcodec.so ./librange.so ./libcc_paint.so ./libcc_base.so ./libcc_debug.so ./libfile_info.so ./libevents_base.so ./libplatform.so ./libkeycodes_x11.so ./libui_base_x.so ./libcontent_public_common_mojo_bindings_shared.so ./libmojom_platform_shared.so ./libandroid_mojo_bindings_shared.so ./libauthenticator_test_mojo_bindings_shared.so ./libcolor_scheme_mojo_bindings_shared.so ./libmojom_mhtml_load_result_shared.so ./libscript_type_mojom_shared.so ./libweb_feature_mojo_bindings_mojom_shared.so ./libservice_manager_mojom_shared.so ./libservice_manager_mojom_constants_shared.so ./libdom_storage_mojom_shared.so ./libframe_mojom_shared.so ./libblink_gpu_mojom_shared.so ./libservice_worker_storage_mojom_shared.so ./libtokens_mojom_shared.so ./libusb_shared.so ./libmojo_base_mojom.so ./libmojo_base_typemap_traits.so ./libcontent_settings_features.so ./libipc.so ./libipc_mojom.so ./libipc_mojom_shared.so ./libprotobuf_lite.so ./libtracing_cpp.so ./libstartup_tracing.so ./libtracing_mojom.so ./libtracing_mojom_shared.so ./libnet.so ./libcrcrypto.so ./libskia_shared_typemap_traits.so ./libcontent.so ./libgpu.so ./libmailbox.so ./libcrash_key_lib.so ./libchrome_zlib.so ./libvulkan_info.so ./libgfx_ipc.so ./libgfx_ipc_geometry.so ./libvulkan_ycbcr_info.so ./liburl_ipc.so ./libviz_common.so ./libviz_resource_format_utils.so ./libviz_vulkan_context_provider.so ./libdisplay.so ./libdisplay_types.so ./libgl_wrapper.so ./libmedia.so ./libshared_memory_support.so ./libleveldb_proto.so ./libkeyed_service_core.so ./libleveldatabase.so ./libgfx_ipc_color.so ./libgfx_ipc_buffer_types.so ./libgfx_ipc_skia.so ./libgfx_native_types_shared_mojom_traits.so ./libgfx_shared_mojom_traits.so ./libgpu_shared_mojom_traits.so ./liblearning_common.so ./libmedia_learning_shared_typemap_traits.so ./libmedia_session_base_cpp.so ./libcookies_mojom_support.so ./libnetwork_cpp_base.so ./libcrash_keys.so ./libcross_origin_embedder_policy.so ./libip_address_mojom_support.so ./libschemeful_site_mojom_support.so ./libwebrtc_component.so ./libservice_manager_mojom.so ./libservice_manager_mojom_constants.so ./libservice_manager_cpp_types.so ./libservice_manager_mojom_traits.so ./libservice_manager_cpp.so ./libmetrics_cpp.so ./libui_base_clipboard_types.so ./libevents.so ./libui_base_cursor_base.so ./libdisplay_shared_mojom_traits.so ./libcc.so ./libvideo_capture_mojom_support.so ./libcapture_base.so ./liblatency_shared_mojom_traits.so ./libprediction.so ./libblink_common.so ./libprivacy_budget.so ./libnetwork_cpp.so ./libweb_feature_mojo_bindings_mojom.so ./libmojom_modules_shared.so ./libmojom_core_shared.so ./libfido.so ./libbluetooth.so ./libscript_type_mojom.so ./libcc_ipc.so ./libcc_shared_mojom_traits.so ./libdom_storage_mojom.so ./libframe_mojom.so ./libblink_gpu_mojom.so ./libservice_worker_storage_mojom.so ./libtokens_traits.so ./libime_shared_mojom_traits.so ./libui_base_ime_types.so ./libui_events_ipc.so ./libweb_bluetooth_mojo_bindings_shared.so ./libax_base.so ./libui_accessibility_ax_mojom.so ./libui_accessibility_ax_mojom_shared.so ./libui_base_ime.so ./libcontent_common_mojo_bindings_shared.so ./libaccessibility.so ./libgfx_x11.so ./libxprotos.so ./libaura.so ./libcompositor.so ./libblink_features.so ./libsurface.so ./libpolicy.so ./libnetwork_service.so ./libmemory_instrumentation.so ./libresource_coordinator_public_mojom.so ./libresource_coordinator_public_mojom_shared.so ./libstorage_common.so ./libpublic.so ./libinterfaces_shared.so ./libstorage_service_filesystem_mojom_shared.so ./libstorage_service_filesystem_mojom.so ./libstorage_service_typemap_traits.so ./libmedia_session_cpp.so ./libstorage_browser.so ./libvr_public_cpp.so ./libdevice_vr_isolated_xr_service_mojo_bindings.so ./libdevice_vr_isolated_xr_service_mojo_bindings_shared.so ./libdevice_vr_test_mojo_bindings_shared.so ./libdevice_vr_service_mojo_bindings_shared.so ./libgamepad_mojom_shared.so ./libdevice_vr_test_mojo_bindings.so ./libdevice_vr_service_mojo_bindings.so ./libgamepad_mojom.so ./libgamepad_shared_typemap_traits.so ./libshared_with_blink.so ./libdevice_vr_public_typemaps.so ./libchrome_features.so ./libprefs.so ./libvariations_features.so ./liburl_matcher.so ./libcapture_lib.so ./libmedia_webrtc.so ./libwtf.so ./libcommon.so ./libnetwork_session_configurator.so ./libsql.so ./libchromium_sqlite3.so ./libwebdata_common.so ./libos_crypt.so ./libomnibox_http_headers.so ./libcloud_policy_proto_generated_compile.so ./libpolicy_component.so ./libpolicy_proto.so ./libgcm.so ./libnative_theme.so ./libservice_provider.so ./libui_message_center_cpp.so ./libppapi_shared.so ./libmojo_core_embedder.so ./libprinting.so ./libsandbox_services.so ./libsuid_sandbox_client.so ./libseccomp_bpf.so ./libsecurity_state_features.so ./libui_base_clipboard.so ./libui_base_data_transfer_policy.so ./libkeyed_service_content.so ./libuser_prefs.so ./libextras.so ./libsessions.so ./libcaptive_portal_core.so ./libdevice_features.so ./libweb_modal.so ./libdevice_event_log.so ./libshell_dialogs.so ./libui_base_idle.so ./libdbus.so ./libonc.so ./libhost.so ./libukm_recorder.so ./libcrdtp.so ./libuser_manager.so ./libperformance_manager_public_mojom.so ./libperformance_manager_public_mojom_shared.so ./libviews.so ./libui_base_ime_init.so ./libui_base_cursor_theme_manager.so ./libui_base_cursor.so ./libx11_window.so ./libui_touch_selection.so ./libproxy_config.so ./libtab_groups.so ./libmanager.so ./libmessage_center.so ./libfontconfig.so ./libx11_events_platform.so ./libdevices.so ./libevents_devices_x11.so ./libevents_x.so ./libffmpeg.so ./libwebview.so ./libdomain_reliability.so ./liblookalikes_features.so ./libui_devtools.so ./libdata_exchange.so ./libgesture_detection.so ./libsnapshot.so ./libweb_dialogs.so ./libcolor.so ./libmixers.so ./libdiscardable_memory_service.so ./libAPP_UPDATE.so ./libozone.so ./libozone_base.so ./libdisplay_util.so ./libvulkan_wrapper.so ./libplatform_window.so ./libui_base_ime_linux.so ./libfreetype_harfbuzz.so ./libmenu.so ./libproperties.so ./libthread_linux.so ./libgtk.so ./libgtk_ui_delegate.so ./libbrowser_ui_views.so ./libwm.so ./libmedia_message_center.so ./libtab_count_metrics.so ./libui_gtk_x.so ./libwm_public.so ./libppapi_host.so ./libppapi_proxy.so ./libcertificate_matching.so ./libdevice_base.so ./libswitches.so ./libcapture_switches.so ./libmidi.so ./libmedia_mojo_services.so ./libmedia_gpu.so ./libgles2_utils.so ./libgles2.so ./libgpu_ipc_service.so ./libgl_init.so ./libcert_net_url_loader.so ./liberror_reporting.so ./libevents_ozone.so ./libschema_org_common.so ./libmirroring_service.so ./libvr_common.so ./libvr_base.so ./libdevice_vr.so ./libblink_controller.so ./libblink_core.so ./libblink_mojom_broadcastchannel_bindings_shared.so ./libwtf_support.so ./libweb_feature_mojo_bindings_mojom_blink.so ./libmojo_base_mojom_blink.so ./libservice_manager_mojom_blink.so ./libservice_manager_mojom_constants_blink.so ./libblink_platform.so ./libcc_animation.so ./libresource_coordinator_public_mojom_blink.so ./libv8.so ./libblink_embedded_frame_sink_mojo_bindings_shared.so ./libperformance_manager_public_mojom_blink.so ./libui_accessibility_ax_mojom_blink.so ./libgin.so ./libblink_modules.so ./libgamepad_mojom_blink.so ./liburlpattern.so ./libdevice_vr_service_mojo_bindings_blink.so ./libdevice_vr_test_mojo_bindings_blink.so ./libdiscardable_memory_client.so ./libcbor.so ./libpdfium.so ./libheadless_non_renderer.so ./libc++.so -Wl,--end-group -ldl -lpthread -lrt -lgmodule-2.0 -lgobject-2.0 -lgthread-2.0 -lglib-2.0 -lnss3 -lnssutil3 -lsmime3 -lplds4 -lplc4 -lnspr4 -latk-1.0 -latk-bridge-2.0 -lcups -ldbus-1 -lgio-2.0 -lexpat real 0m3.312s user 0m0.064s sys 0m0.027s minami@chromium-dev-20210227:~/chromium/src/out/Default$ ls -la chrome -rwxrwxr-x 1 minami minami 1296141738 Feb 28 03:46 chrome
この chrome
の .comment
section を見て、出自を確認してみましょう。LLD でリンクした時は Linker: LLD 12.0.0
という記述があったのに対して、この chrome Binary にはその記述がありません。逆説的に、「LLD 以外のリンカ(= mold)でリンクしたこと」が確認できたと言えそうです。
minami@chromium-dev-20210227:~/chromium/src$ readelf --string-dump .comment out/Default/chrome String dump of section '.comment': [ 1] GCC: (Debian 7.5.0-3) 7.5.0 [ 1d] clang version 12.0.0 (https://github.com/llvm/llvm-project/ 6ee22ca6ceb71661e8dbc296b471ace0614c07e5)
2021年3月27日追記: mold の README の How to use を見ると、今では .comment
section に mold
という文字列が commit hash つきで記載されるようになったようです(ただし、自分は動作未検証です)。
生成した chrome Binary の挙動も確認してみましょう。以前のブログ記事 のように、「headless mode での実行」を試してみます。以下のようにちゃんと動作をすることが確認できました 🎉
minami@chromium-dev-20210227:~/chromium/src$ ./out/Default/chrome --headless --disable-gpu --dump-dom https://example.com [0228/035317.179292:WARNING:headless_content_main_delegate.cc(530)] Cannot create Pref Service with no user data dir. [0228/035317.194952:INFO:content_main_runner_impl.cc(1027)] Chrome is running in full browser mode. <!DOCTYPE html> . . .
ということで、無事「mold による chrome Binary のリンク」に成功しました。
既存の Build の仕組みに組み込もうと思うと「mold ではサポートされてない option の扱い」などいくつか考える必要がありそうですが、試しにリンクをするだけであれば比較的簡単に実行ができることが分かりました。
LLD と mold の速度比較
mold は「LLD よりも高速なリンカ」として開発されています。実際に、リンクにかかる時間がどれだけ変わったのか、比較してみましょう。ここでは、上記の「リンカに渡す option を減らした状態でのリンクの実行」を mold と LLD の両方で行って、time で計測した結果を載せています。
LLD
[3/4] SOLINK ./libvr_common.so
相当の処理
minami@chromium-dev-20210227:~/chromium/src/out/Default$ time python "../../build/toolchain/gcc_solink_wrapper.py" --readelf="readelf" --nm="nm" --sofile="./libvr_common.so" --tocfile="./libvr_common.so.TOC" --output="./libvr_common.so" -- ../../third_party/llvm-build/Release+Asserts/bin/clang++ -shared -fuse-ld=lld -Wl,--fatal-warnings -Wl,--build-id -fPIC -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,defs -Wl,--as-needed -m64 -Werror -rdynamic -nostdlib++ --sysroot=../../build/linux/debian_sid_amd64-sysroot -L../../build/linux/debian_sid_amd64-sysroot/usr/local/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu -Wl,-rpath=\$ORIGIN -o "./libvr_common.so" @"./libvr_common.so.rsp" real 0m1.265s user 0m1.391s sys 0m0.837s
[4/4] LINK ./chrome
相当の処理
minami@chromium-dev-20210227:~/chromium/src/out/Default$ time python "../../build/toolchain/gcc_link_wrapper.py" --output="./chrome" -- ...(長いので省略) real 0m7.777s user 0m8.309s sys 0m3.664s
mold
[3/4] SOLINK ./libvr_common.so
相当の処理
minami@chromium-dev-20210227:~/chromium/src/out/Default$ time python "../../build/toolchain/gcc_solink_wrapper.py" --readelf="readelf" --nm="nm" --sofile="./libvr_common.so" --tocfile="./libvr_common.so.TOC" --output="./libvr_common.so" -- ../../third_party/llvm-build/Release+Asserts/bin/clang++ -shared -fuse-ld=lld -Wl,--fatal-warnings -Wl,--build-id -fPIC -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,defs -Wl,--as-needed -m64 -Werror -rdynamic -nostdlib++ --sysroot=../../build/linux/debian_sid_amd64-sysroot -L../../build/linux/debian_sid_amd64-sysroot/usr/local/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/lib/x86_64-linux-gnu -L../../build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu -Wl,-rpath=\$ORIGIN -o "./libvr_common.so" @"./libvr_common.so.rsp" real 0m0.563s user 0m0.033s sys 0m0.029s
[4/4] LINK ./chrome
相当の処理
minami@chromium-dev-20210227:~/chromium/src/out/Default$ time python "../../build/toolchain/gcc_link_wrapper.py" --output="./chrome" -- ...(長いので省略) real 0m3.312s user 0m0.064s sys 0m0.027s
mold と LLD の比較
[3/4] SOLINK ./libvr_common.so
相当の処理については 1.265s -> 0.563s、[4/4] LINK ./chrome
相当の処理については 7.777s -> 3.312s とそれぞれ 2倍以上の高速化が達成できています 🎉
なお、上記の比較を見ると十分に早いですが、それでも「はじめにで掲載した Rui Ueyama さんの Tweet」の 2.5秒という記述に比べると遅いです。これはおそらく、今回利用した GCP VM instance の「8core」という構成に起因するのではないかと考えています。mold は複数 CPU core をうまく活用する作りになっているようなので、CPU core 数が増えることで近いパフォーマンスが出るのだと思われます。
まとめ
Rui Ueyama さんが開発してる mold を利用して、Chromium の Build をしてみました。
実験の結果、試しにリンクをするだけであれば比較的簡単に実行ができることが分かりました。また、CPU core 数が 8 とそれほど多くない構成であっても、 LLD に比べてリンクが2倍以上高速化する という改善が見られることが分かりました。
Rui Ueyama さんは自分が尊敬するエンジニアの1人なのですが、彼のエンジニアリングによって世界がより良くなっている事を体感できたように思います。
Chromium を Build して動かすまでの待ち時間を「7 時間」から「30 分」まで高速化してみる
Chromium をゼロから Build して動かしてみる という前回のブログでは、Chromium を Build して動かすという一連のフローを試してみました。
この時は、Checking out and building Chromium on Linux の手順に従って作業をしました。これは、「最新の Chromium」を Linux 上で Build する事が出来るしっかりした公式手順です。しかしながら、8core, 32GiB memory の GCP VM instance でも Build に 6-7 時間程度かかってしまうのがネックでした。
そこで今日は、Chromium を Build して動かすまでのサイクルを 30 分で試せるようにすること を目指します。7時間と比較すると約15倍の高速化です!
なお、具体的には 事前に Build 済みの Object File を GCS に置いておき、ダウンロードして再利用することで再ビルドの手間を避ける というアプローチをとります。そのため、「最新の Chromium ではなく事前に Build 済みの古い Version しか試せない」ことが欠点となります。「最新の Chromium へのコミット」などを行いたい場合には適さないアプローチでしょう。
しかしながら、「過去の Version の Chromium でも良いから、試しに Build して動かしてみたい」という場合には役立つのではないかと期待しています。
以下、ステップ 0 から順番に作業を進めてみます。
ステップ0. 事前に Chromium の Build 成果物を用意して、GCS へアップロードしておく
Chromium はまともにゼロから Build すると、とてつもなく長い時間がかかってしまいます。そこで、「事前に Chromium を Build して生成した一連の Object File 及び Binary を tar.gz にまとめたもの」を用意しておきます。これをダウンロードして利用することで、「再ビルドの手間」を省くことができるはずです。
対象の File は、chromium-dev-south37
GCS Bucket の中で chromium20201213.tar.gz
という名前で配置しています(suffix は日付で、2020/12/13 時点の Chromium のコードを Build したことを示しています)。
$ gsutil ls -l gs://chromium-dev-south37/chromium20201213.tar.gz 18900879483 2020-12-13T15:56:30Z gs://chromium-dev-south37/chromium20201213.tar.gz TOTAL: 1 objects, 18900879483 bytes (17.6 GiB)
Public にダウンロード可能な形で公開しているので、誰でも試していただくことが可能です。ソースコードも含んでいるので、17.6GiB というかなり巨大なサイズになっています。
この後のステップでは、上記の「ソースコードと Build 成果物を tar.gz でまとめたもの」を利用して作業を進めます。
ステップ1. Linux マシンを用意する
この部分は 前回 と同様です。
GCP の Compute Engine で以下の VM Instance を立ててそこで作業を行うことにします。
以下のコマンドで ssh して、そこで作業を行います。
$ gcloud beta compute ssh --zone "asia-northeast1-b" <instance 名>
ステップ2. 事前に用意しておいた Chromium の一連の Build 成果物をダウンロードする
早速、ステップ0 として事前に用意しておいた「Chromium の一連の Build 成果物」をダウンロードしましょう。以下のように $ gsutil cp
コマンド利用して GCS からダウンロードをします。
$ gsutil -o 'GSUtil:parallel_thread_count=1' \ -o 'GSUtil:sliced_object_download_max_components=8' \ cp gs://chromium-dev-south37/chromium20201213.tar.gz ./chromium20201213.tar.gz
なお、ここでは Cloud Storage のパフォーマンスを最適化する - Google Cloud Platform の推奨に従って、GSUtil:parallel_thread_count
オプションや GSUtil:sliced_object_download_max_components=8
オプションを利用しています。これは、 「1つの巨大なファイルの転送」をしたい場合に推奨されるオプション として紹介されています。
上記のコマンドを実行すると、環境にもよりますが大体 3 分ほどでダウンロードが完了するはずです。
minami@chromium-dev-20210226:~$ gsutil -o 'GSUtil:parallel_thread_count=1' \ > -o 'GSUtil:sliced_object_download_max_components=8' \ > cp gs://chromium-dev-south37/chromium20201213.tar.gz ./chromium20201213.tar.gz Copying gs://chromium-dev-south37/chromium20201213.tar.gz... - [1 files][ 17.6 GiB/ 17.6 GiB] 25.7 MiB/s Operation completed over 1 objects/17.6 GiB.
ダウンロードが終わると、 17.6 GiB の chromium20201213.tar.gz
が作られているはずです。
minami@chromium-dev-20210226:~$ ls -l | grep chromium total 18457900 -rw-rw-r-- 1 minami minami 18900879483 Feb 26 12:34 chromium20201213.tar.gz
今度は、この File を $ tar xvzf chromium20201213.tar.gz
で展開します。これは大体 10-15 分程度で完了するはずです。
minami@chromium-dev-20210226:~$ time tar xvzf chromium20201213.tar.gz chromium/ . . . chromium/src/cloud_print/OWNERS chromium/.gclient chromium/.gclient_entries real 15m45.171s user 5m57.618s sys 2m49.498s
展開が終わると、以下のように chromium
directory が作られているはずです。chromium
directory の中には chromium/src/out/Default
directory が入っています。その中には Build 済みの Object File や chrome
Binary が存在する事も確認できます。
minami@chromium-dev-20210226:~$ ls -la | grep chromium drwxrwxr-x 4 minami minami 4096 Dec 12 12:33 chromium -rw-rw-r-- 1 minami minami 18900879483 Feb 26 12:34 chromium20201213.tar.gz minami@chromium-dev-20210226:~$ ls chromium/src/out/ Default minami@chromium-dev-20210226:~$ ls chromium/src/out/Default/ | grep '\.so$' | wc -l 375 minami@chromium-dev-20210226:~$ ls -la chromium/src/out/Default/chrome -rwxrwxr-x 1 minami minami 1058842464 Dec 13 14:43 chromium/src/out/Default/chrome
ただし、この状態ではまだ chrome
Binary は実行できません。実行しようとすると、以下のようにエラーが出てしまいます。
minami@chromium-dev-20210226:~$ ./chromium/src/out/Default/chrome ./chromium/src/out/Default/chrome: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory
ステップ3. 必要な package を install
chrome
Binary 実行にはいくつか package が必要となります。
まず、python2 が必要になるので、install しておきます。
minami@chromium-dev-20210226:~$ sudo apt update -y minami@chromium-dev-20210226:~$ sudo apt install -y python2 minami@chromium-dev-20210226:~$ which python2 /usr/bin/python2 minami@chromium-dev-20210226:~$ python2 -V Python 2.7.18 minami@chromium-dev-20210226:~$ sudo ln -s /usr/bin/python2 /usr/local/bin/python minami@chromium-dev-20210226:~$ which python /usr/local/bin/python minami@chromium-dev-20210226:~$ python -V Python 2.7.18
次に、./build/install-build-deps.sh
を実行します。これは 6 分程度で完了するはずです。
minami@chromium-dev-20210226:~/chromium/src$ time ./build/install-build-deps.sh . . . 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. real 6m10.812s user 2m35.472s sys 0m58.130s
これで、必要な package の install が完了しました。この状態で、試しに chrome
Binary を実行してみましょう。前回のように、「headless mode での実行」を試してみます。以下のようにちゃんと動作をすることが確認できました 🎉
minami@chromium-dev-20210226:~/chromium/src$ ./out/Default/chrome --headless --disable-gpu --dump-dom https://example.com <!DOCTYPE html> . . .
ここまで、 GCP VM instance への ssh から大体 20-25 分 ほどで「chrome
Binary を動かすこと」が出来ました 。
ステップ4. Build に必要な環境をセットアップ
さて、「ダウンロードした chrome
Binary」を動かせただけでは、あまり嬉しくありません。「コードを書き換えながら、chrome
を Build して実行することができる」という状態を目指します。
まず、ninja
など Build に必要なツールを利用するために、depot_tools
をインストールします。
minami@chromium-dev-20210226:~/chromium/src$ cd $HOME minami@chromium-dev-20210226:~$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git # PATH を通しておく minami@chromium-dev-20210226:~$ export PATH="$PATH:${PWD}/depot_tools"
これで、gn
などの Build に必要なコマンドが使えるようになります。
minami@chromium-dev-20210226:~$ which gn /home/minami/depot_tools/gn
次に、この状態で chrome
Binary の Build をしてみます。autoninja -C out/Default chrome
を実行すると、既に chrome
Binary は存在するため、no work to do
という表示が出て 5 秒程度で終了します。
minami@chromium-dev-20210226:~$ cd chromium/src/ minami@chromium-dev-20210226:~/chromium/src$ autoninja -C out/Default chrome ninja: Entering directory `out/Default' ninja: no work to do.
前回と同様に、chrome/common/channel_info.cc
という File を touch して timestamp を更新してみます。こうすると、更新した File (及びその File に依存した File)だけを対象に Build が行われるので、20 秒程度で chrome
Binary の Build が終了します。
minami@chromium-dev-20210226:~/chromium/src$ touch chrome/common/channel_info.cc minami@chromium-dev-20210226:~/chromium/src$ time autoninja -C out/Default chrome ninja: Entering directory `out/Default' [4/4] LINK ./chrome real 0m21.574s user 0m20.022s sys 0m5.478s
ということで、 「コードを書き換えながら、chrome
をBuild して実行することができる」という状態も実現できました!🎉
まとめ
事前に Build 済みの Object File を GCS からダウンロードすることで、再ビルドの手間を避けるアプローチを試しました。その結果、前回の「ゼロからの Build」ではトータルで 7 時間かかったのに対して、今回は 30 分程度で「Chromium を Build して動かすまでのサイクルを試す」ことが出来るようになりました。
このように、「事前に用意した Build 成果物」をうまく活用することで、再ビルドの時間的・マシン的コストは劇的に下げることができます。この記事が、Chromium を試しに触ってみることへの障壁を下げることに少しでも貢献していれば幸いです。
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 が見つかります。 その中で、「Linux で Chromium を Check out して Build する手順」がまとまっているのが以下の Document です。
今日は、このドキュメントを元に作業を進めてみます。
ステップ1. Linux マシンを用意する
まず始めに、作業を行うための Linux マシンを用意する必要があります。 再現性を持たせるために、今回は GCP の Compute Engine で以下の VM Instance を立ててそこで作業を行うことにします。
以下のコマンドで 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_tools
の fetch
でソースコードを取得します。
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 を行います。Chromium は Ninja をメインの 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 にかかる時間を減らすことが開発生産性に繋がる」という話をしているのを聞いた記憶がありますが、それが実感できる機会となりました。
まとめ
Chromium を Linux 上でゼロから Build して動かしてみました。トータルでかかった時間は6-7時間程度とかなり長いので気軽に試すのは難しいですが、「巨大なソフトウェアであっても Build して動かすことが出来る」ということが確かめられたと思います。
また、一度動くところまで持っていけば、「少し変えて動かして試す」ということが簡単に出来るようになるので、ソフトウェアに対しての理解を深めやすくなります。これをきっかけに Chromium に対して理解を深めたいと思います。