ビルドを高速化するsccache の紹介
はじめに
この資料は Rust 製のコマンドラインツール sscache について紹介するものです。
Rust製の環境構築やツールのインストール方法については以下を参照してください
sccache について
sccache は ccache に似たコンパイラ・キャッシングツールです。コンパイラのラッパーとして使用され、可能な限りコンパイルを回避し、ローカルディスクまたはいくつかのクラウドストレージバックエンドにキャッシュされた結果を保存します。
sccacheは、C/C++コード、Rust、およびnvccを使用したNVIDIAのCUDAのコンパイルのキャッシュもサポートしています。
また、sccacheは、Rustを含むサポートされているすべてのコンパイラーに対して、icecreamスタイルの分散コンパイル(ローカルツールチェーンの自動パッケージ化)を提供します。分散コンパイルシステムには、認証、トランスポート層の暗号化、ビルドサーバーでのサンドボックス化されたコンパイラー実行など、icecreamにないいくつかのセキュリティ機能が含まれています。
使用方法
sccacheの実行はccacheの実行と同じで、以下のようにコンパイルコマンドの前にsccacheを付けるだけです。
sccache gcc -o foo.o -c foo.c
Rustビルドのキャッシュにsccacheを使用する場合、cargo設定ファイルに build.rustc-wrapper を定義することができます。例えば、~/.cargo/config.toml に追加することで、グローバルに設定することができます。
[build]
rustc-wrapper = "/path/to/sccache"
この機能を使用するには、cargo 1.40 以降を使用する必要があることに注意してください。
または、環境変数 RUSTC_WRAPPER を使用することもできます。
export RUSTC_WRAPPER=/path/to/sccache
cargo build
sccacheはgcc、clang、MSVC、rustc、NVCC、およびWind Riverのdiabコンパイラーをサポートしています。
特に指定しない場合、sccacheはローカルディスクキャッシュを使用します。
sccacheはクライアント・サーバーモデルを使用して動作し、サーバーはクライアントと同じマシン上でローカルに実行されます。クライアント・サーバ・モデルでは、いくつかの状態をメモリ内に保持することで、 サーバをより効率的に動作させることができます。sccache コマンドは、サーバープロセスがまだ実行されていなければ、それを起動します。また、sccache --start-server を実行すると、コンパイルを行わずにバックグラウンドのサーバープロセスを起動します。
sccache --stop-server を実行すると、サーバーを終了させることができます。また、(デフォルトでは) 10 分間何もしないと終了します。
sccache --show-stats を実行すると、キャッシュの統計情報の概要が表示されます。
sccache を Jenkins で使用する際の注意点はこちらです。
cmakeでsccacheを使うには、cmake 3.4以降で以下のコマンドライン引数を与えてください。
-DCMAKE_C_COMPILER_LAUNCHER=sccache
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache
MSVCでデバッグするためのPDBファイルを生成するために、/Z7 オプションを使用することができます。また、/Zi オプションと /Fd を併用しても、/Fd が作成されるオブジェクトファイルごとに異なるPDBファイル名を付けるのであれば、動作させることができます。なお、CMakeはデフォルトで /Zi を設定しますので、CMakeを使用する場合は、CMakeLists.txtに 以下のようなコードを追加すれば、/Z7 を使用することができます。
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
endif()
デフォルトでは、sccache は関連するサーバーとの通信に失敗した場合、ビルドに失敗します。代わりに sccache が停止せずにローカルのコンパイラーにフェイルオーバーするようにするには、環境変数 SCCACHE_IGNORE_SERVER_IO_ERROR=1 を設定します。
ビルド
sscache を開発目的でビルドしない場合、cargo build --release を使用して最適化されたバイナリを取得するようにしてください。
cargo build --release [--no-default-features --features=s3|redis|gcs|memcached|azure]
デフォルトでは、sccache はすべてのストレージバックエンドをサポートして構築されていますが、機能のリストをリセットし、他のすべてのバックエンドを有効にすることによって、個々のバックエンドを無効にすることができます。Cargo で機能を選択する方法の詳細については、Cargo ドキュメントを参照してください。
ポータブルバイナリのビルド
dist-server 機能でビルドする場合、sccache は OpenSSL に依存します。これは、ポータブルなバイナリを配布したい場合、厄介なことになります。openssl/vendored 機能を使って OpenSSL に対して静的にリンクすることができます。
Linux
cargoでビルドし、lddで結果のバイナリがOpenSSLに依存しなくなったことを確認する。
macOS
cargoでビルドし、otool -Lで生成されるバイナリがOpenSSLに依存しなくなったことを確認します。
Windows
Windowsでは、バイナリは、古いWindowsバージョンでは利用できないいくつかのMSVC CRT DLLに依存する場合があります。
この場合、以下の内容の .cargo/config.toml ファイルを使用して、CRT に対して静的にリンクすることができます。
[target.x86_64-pc-windows-msvc]
rustflags = ["-Ctarget-feature=+crt-static"]
cargo でビルドし、dumpbin /dependents を使って、生成されるバイナリがもう MSVC CRT DLL に依存しないことを確認します。
OpenSSLと静的にリンクする場合、$PATH に Perl が必要です。
起動時のキャッシュの分離
複数の異なるコンパイル起動が互いのキャッシュ結果を再利用しないようにするには、環境変数 SCCACHE_C_CUSTOM_CACHE_BUSTER にハッシュに混ぜられる一意の値を設定します。MACOSX_DEPLOYMENT_TARGET と IPHONEOS_DEPLOYMENT_TARGET はすでにそのような再利用抑制の動作を示しています。現在、Rustをコンパイルするためのこのような変数はありません。
キャッシュの上書き
キャッシュに壊れたビルド成果物が含まれている場合、キャッシュの内容を上書きすることが必要になることがあります。環境変数 SCCACHE_RECACHE を設定することで、これを行うことができます。
デバッグ
環境変数 SCCACHE_ERROR_LOG をパスに設定し、SCCACHE_LOG を設定して、サーバー・プロセスのログをそこにリダイレクトすることができます 。
サーバーは内部で RUST_BACKTRACE=1 を設定するので、処理されないパニックの出力も含まれます。
SCCACHE_ERROR_LOG=/tmp/sccache_log.txt SCCACHE_LOG=debug sccache
また、これらの環境変数は、例えば、ビルド・システム用に設定することもできます。
SCCACHE_ERROR_LOG=/tmp/sccache_log.txt SCCACHE_LOG=debug cmake --build /path/to/cmake/build/directory
また、ローカルでコンパイルする場合は、SCCACHE_START_SERVER=1 SCCACHE_NO_DAEMON=1 sccacheを実行してフォアグラウンドモードでサーバーを手動で実行し、環境変数 SCCACHE_LOG などを設定して標準エラーにログを送信することも可能です。この方法は、別のシェルで同時にコンパイルする必要があるため、CIサービスには不向きです。
SCCACHE_LOG=debug SCCACHE_START_SERVER=1 SCCACHE_NO_DAEMON=1 sccache
GNU make ジョブサーバとの相互作用
sccache は GNU make ジョブサーバをサポートしています。ジョブサーバを提供するプロセスからサーバが起動されると、 sccache はそのジョブサーバを使用し、起動されたプロセスにジョブサーバを提供します。(GNU make レシピから sccache を実行する場合、この挙動を得るためにコマンドの前に + を付ける必要があります)。sccache サーバーがジョブサーバーなしで起動された場合、利用可能な CPU コアの数と等しい数のスロットを持つ独自のサーバーを作成します。
これは、Rustのコンパイルにsccacheを使うときに最も便利です。rustcは並列コード生成にjobserverを使うことをサポートしているので、rustcがコード生成タスクでシステムを圧倒することがないようにします。カーゴは、rustcが使用するために、独自のジョブサーバー(Cargoのドキュメントの NUM_JOBS に関する情報を参照)を実装しているので、RUSTC_WRAPPER を介してカーゴでRustコンパイル用にsccacheを使用すると、自動的に正しい処理が行われるはずです。
既知の注意事項
一般的な注意点
キャッシュをヒットさせるには、ファイルの絶対パスが一致しなければなりません。つまり、共有キャッシュを使用している場合でも、お互いに利益を得るためには、全員が同じ絶対パスで (つまり $HOME 以外に) ビルドする必要があるということです。Rust では、サードパーティのクレートのソースも含まれ、デフォルトでは ~/.cargo/registry/cache に格納されます。
Rustでの注意点
システムリンカーを呼び出すクレートは、キャッシュできません。これには、bin、dylib、cdylib、および proc-macro クレートが含まれます。大きな bin クレートは、薄い bin ラッパーで lib create に変換することで、コンパイル時間を短縮できる場合があります。
インクリメンタル・コンパイルされたクレートはキャッシュできません。デフォルトでは、デバッグ プロファイルでは、Cargo はワークスペース メンバーとパス依存性のためにインクリメンタル コンパイルを使用します。インクリメンタル・コンパイルを無効にすることができます。
シンボリックリンクでの注意点
sccache にシンボリックリンクされているパスでは動作しません。ハードリンクを使用するようにしてください。例: ln sccache /usr/local/bin/cc・
ドキュメント
sccache のヘルプメッセージ
% sccache --help
sccache 0.3.3
USAGE:
sccache [OPTIONS] <--dist-auth|--dist-status|--show-stats|--start-server|--stop-server|--zero-stats|--package-toolchain <EXE> <OUT>|CMD> [--]
ARGS:
<CMD>...
OPTIONS:
--dist-auth
authenticate for distributed compilation
--dist-status
show status of the distributed client
-h, --help
Print help information
--package-toolchain <EXE> <OUT>
package toolchain for distributed compilation
-s, --show-stats
show cache statistics
--start-server
start background server
--stats-format <FMT>
set output format of statistics [default: text] [possible values:
text, json]
--stop-server
stop background server
-V, --version
Print version information
-z, --zero-stats
zero statistics counters
Enabled features:
S3: true
Redis: true
Memcached: true
GCS: true
GHA: true
Azure: true
ライセンス
この記事が気に入ったらサポートをしてみませんか?