LLVM の更新
Rust は複数の LLVM バージョンに対するビルドをサポートしています。
- 現在の LLVM 開発ブランチのツリー先端は、通常は数日以内にサポートされます。
そのような修正の PR には
llvm-mainタグが付けられます。 - 最新のリリース済みメジャーバージョンは常にサポートされます。
- 直前の 1 つまたは 2 つのメジャーバージョンは、通常、正常にビルドでき、ほとんどのテストに合格することが期待されるという意味でサポートされます。 ただし、誤コンパイルの修正は過去の LLVM バージョンにバックポートされないことが多いため、古いバージョンの LLVM で rustc を使用すると、健全性バグのリスクが高まります。 最新バージョンの LLVM を使用することを強く推奨します。
デフォルトでは、Rust は rust-lang/llvm-project repository にある独自のフォークを使用します。
このフォークはアップストリームプロジェクトの release/$N.x ブランチに基づいており、ここで $N は最新のリリース済みメジャーバージョン、またはリリース候補段階にある現在のメジャーバージョンのいずれかです。
このフォークが main 開発ブランチに基づくことはありません。
私たちの LLVM フォークでは、次のもののみを受け入れます。
- すでにアップストリームに取り込まれた変更のバックポート。
- 私たちの CI 環境に影響するビルド問題の回避策。
SGX 有効化のために既得権として残されている 1 つのパッチを例外として、先にアップストリーム化されていない機能的なパッチは受け入れません。
LLVM の更新には 3 つの種類があり、それぞれ手順が異なります。
- 現在のメジャー LLVM バージョンがサポートされている間のバックポート。
- 現在のメジャー LLVM バージョンがすでにサポートされていない間のバックポート(または、その変更がアップストリームのバックポート対象ではない場合)。
- 新しいメジャー LLVM バージョンへの更新。
バックポート(アップストリームでサポートされている場合)
現在のメジャー LLVM バージョンがアップストリームでサポートされている間は、修正を先にアップストリームへバックポートし、その後リリースブランチを Rust フォークへマージする必要があります。
- バグ修正がアップストリーム LLVM に入っていることを確認します。
- まだ行われていない場合は、アップストリームのリリースブランチへのバックポートをリクエストします。 LLVM のコミットアクセス権がある場合は、backport process に従ってください。 そうでない場合は、バックポートをリクエストする issue を開いてください。 バックポートが承認され、マージされたら続行します。
- rustc が現在使用しているブランチを特定します。
src/llvm-projectサブモジュールは常に rust-lang/llvm-project repository のブランチに固定されています。 - rust-lang/llvm-project リポジトリをフォークします。
- 適切なブランチをチェックアウトします(通常は
rustc/a.b-yyyy-mm-ddという名前です)。 git remote add upstream https://github.com/llvm/llvm-project.gitを使用してアップストリームリポジトリの remote を追加し、git fetch upstreamを使用して fetch します。upstream/release/$N.xブランチをマージします。- このブランチを自分のフォークに push します。
- rust-lang/llvm-project に対して、以前と同じブランチへの Pull Request を送ります。 PR の説明では、修正している Rust および LLVM の issue の一方または両方を必ず参照してください。
- PR がマージされるまで待ちます。
- バグ修正を含む
src/llvm-projectサブモジュールを更新する PR を rust-lang/rust に送ります。 通常、これはローカルでgit submodule update --remote src/llvm-projectを実行することで行えます。 - PR がマージされるまで待ちます。
PR の例: #59089
バックポート(アップストリームでサポートされていない場合)
アップストリームの LLVM リリースは、GA リリース後 2〜3 か月間のみサポートされます。 アップストリームでのバックポートが受け入れられなくなったら、変更は私たちのフォークに直接 cherry-pick する必要があります。
- バグ修正がアップストリーム LLVM に入っていることを確認します。
- rustc が現在使用しているブランチを特定します。
src/llvm-projectサブモジュールは常に rust-lang/llvm-project repository のブランチに固定されています。 - rust-lang/llvm-project リポジトリをフォークします。
- 適切なブランチをチェックアウトします(通常は
rustc/a.b-yyyy-mm-ddという名前です)。 git remote add upstream https://github.com/llvm/llvm-project.gitを使用してアップストリームリポジトリの remote を追加し、git fetch upstreamを使用して fetch します。git cherry-pick -xを使用して、関連するコミットを cherry-pick します。- このブランチを自分のフォークに push します。
- rust-lang/llvm-project に対して、以前と同じブランチへの Pull Request を送ります。 PR の説明では、修正している Rust および LLVM の issue の一方または両方を必ず参照してください。
- PR がマージされるまで待ちます。
- バグ修正を含む
src/llvm-projectサブモジュールを更新する PR を rust-lang/rust に送ります。 通常、これはローカルでgit submodule update --remote src/llvm-projectを実行することで行えます。 - PR がマージされるまで待ちます。
PR の例: #59089
新しい LLVM リリースへの更新
バグ修正とは異なり、新しい LLVM リリースへの更新には通常、はるかに多くの作業が必要です。 これは、コミットを後方へ cherry-pick するのが現実的ではないため、完全な更新を行う必要がある場合です。 ここで行うべきことはたくさんあるため、それぞれを詳しく見ていきます。
-
LLVM が、最新のリリースバージョンがブランチされたことを発表します。 これは llvm/llvm-project repository にブランチとして現れます。 通常は
release/$N.xという名前で、$Nはリリースされる LLVM のバージョンです。 -
rust-lang/llvm-project repository に、 この
release/$N.xブランチから新しいブランチを作成し、rustc/a.b-yyyy-mm-ddという名前を付けます。 ここで、a.bはブランチ作成時点でツリー内にある LLVM の現在のバージョン番号で、 残りの部分は現在の日付です。 -
Rust 固有のパッチを llvm-project リポジトリに適用します。 すべての機能とバグ修正はアップストリームにありますが、 アップストリームに送るのが適切でない、ビルド関連の少し奇妙なパッチがしばしば存在します。 これらのパッチは通常、 rustc が現在使用している rust-lang/llvm-project ブランチの最新のパッチです。
-
rustリポジトリで新しい LLVM をビルドします。 これを行うには、src/llvm-projectリポジトリを自分のブランチと、 作成したリビジョンに更新します。 また、通常は.gitmodulesを LLVM サブモジュールの新しい ブランチ名で更新することも推奨されます。 サブモジュールの更新が巻き戻されないように、src/llvm-projectへの変更をコミット済みにしておいてください。 実行すべきコマンドには次のものがあります。./x build src/llvm-project- LLVM が引き続きビルドできることをテストします./x build- rustc の残りの部分をビルドします
更新された LLVM バインディングでコンパイルできるように、
llvm-wrapper/*.cppを更新する必要がある可能性が高いです。 なお、古い LLVM バージョンでもバインディングが引き続きコンパイルできるように、#ifdefなどを使用する必要があります。profile = "compiler"や./x setupによって設定されるその他のデフォルトは、 LLVM をソースからビルドするのではなく CI からダウンロードすることに注意してください。 変更が使用されていることを確認するために、これを一時的に無効にする必要があります。 これは、bootstrap.tomlに次の設定を記述することで行います。llvm.download-ci-llvm = false -
他のプラットフォームでリグレッションをテストします。 LLVM には非 Tier 1 アーキテクチャ向けのバグが少なくとも 1 つあることが多いため、 これを bors に送る前にもう少しテストしておくとよいでしょう。 リソースが不足している場合は、そのまま PR を bors に送ってもかまいません。 いずれにせよテストされます。
理想的には、いくつかのプラットフォームで LLVM をビルドしてテストします。
- Linux
- macOS
- Windows
その後、CI でも実行されるいくつかの Docker コンテナを実行します。
./src/ci/docker/run.sh wasm32./src/ci/docker/run.sh arm-android./src/ci/docker/run.sh dist-various-1./src/ci/docker/run.sh dist-various-2./src/ci/docker/run.sh armhf-gnu
-
rust-lang/rustへの PR を準備します。rust-lang/llvm-projectのメンテナーと協力して、 そのリポジトリのブランチにコミットを入れてもらい、 その後rust-lang/rustに PR を送ることができます。 少なくともsrc/llvm-projectを変更し、 おそらくllvm-wrapperも変更することになります。先行事例として、過去の LLVM 更新をいくつか挙げます。
実際に
src/llvm-projectを更新する前に、llvm-wrapperの互換性を PR として取り込むのが最も簡単な場合があることに注意してください。 こうすることで、 LLVM の問題に取り組んでいる間も、 新しい LLVM を試したい他の人が、C++ バインディングを更新するためにあなたが行った作業の恩恵を受けられます。 -
その後数か月にわたって、 LLVM は
release/a.bブランチに継続的にコミットをプッシュします。 多くの場合、これらのバグ修正も取り込みたくなります。 そのためのマージプロセスは、git merge自体を使用して LLVM のrelease/a.bブランチを手順 2 で作成したブランチにマージすることです。 これは通常、LLVM のリリースブランチが安定していく間に、必要に応じて複数回行われます。 -
その後、LLVM がバージョン
a.bのリリースを発表します。 -
LLVM の公式リリース後、 rust-lang/llvm-project リポジトリで再び新しいブランチを作成するプロセスに従います。 今回は新しい日付を使用します。 Rust をそのバージョンを使用するように更新する PR がマージされるのは、その後になってからです。
rust-lang/llvm-projectのコミット履歴は、git rebaseが行われることで、よりずっときれいに見えるはずです。 そこでは、素の LLVM のリリースブランチの上に、少数の Rust 固有のコミットだけが積まれます。
注意点と落とし穴
理想的には上記の手順はかなりスムーズですが、進める際には次の注意点を 念頭に置いてください。
- LLVM のバグは見つけるのが難しいため、遠慮なく助けを求めてください。 ここでは二分探索が間違いなく役に立ちます (はい、LLVM のビルドには非常に時間がかかりますが、それでも二分探索は役に立ちます)。 なお、貢献者に強力なハードウェアへのリモートアクセスを提供する取り組みである Dev Desktops を利用できます。
- 一般的な質問がある場合は、wg-llvm が助けになります。
- ブランチの作成は GitHub 上では権限のある操作なので、 多くの場合、書き込み権限を持つ誰かにブランチを作成してもらう必要があります。