Error [can't find Rust compiler]

error: can't find Rust compiler の直し方(pip が wheel を使えずソースビルドに落ちるとき)

FIX SUMMARY verified
Applies when
python:3.12-slimcryptography 42.0.5 (Rust extension; no wheel -> source build)pip source-builds a Rust-based package (--no-binary / no matching wheel) without rustc

Verified: reproduced in python:3.12-slim, then the can't find Rust compiler signature was gone after the fix (exit 0).

pip installcryptographypydanticorjson など)の途中で、ビルドに入り、次のエラーで止まることがあります。

error: can't find Rust compiler

続けて、pip はヒントも出します。

If you are using an outdated pip version, it is possible a prebuilt wheel is available for this package but pip is not able to install from it. Installing from the wheel would avoid the need for a Rust compiler.

これは、そのパッケージが Rust で書かれた拡張を含んでいて、pip が事前ビルド済みのパッケージ(wheel)を使えずにソースからビルドしようとし、その環境に Rust ツールチェーン(rustc / cargo)が無いために起きます。Python やパッケージのコードの誤りではなく、gcc が無いときの error: command 'gcc' failed と同じ「ビルド道具が無い」系で、要求されるのが Rust に変わったものです。

ヒントが言うとおり、多くの場合の正解は Rust を入れることではなく、wheel を使えるようにすることです。

なぜ Rust を要求されるのか

cryptography(3.4 で Rust ビルドを導入し、35.0 以降は Rust が必須)、pydantic(v2 の pydantic-core)、orjson などは、速度や安全性のために内部の一部を Rust で書いています。これらを入れるとき、pip はまず環境に合う wheel(コンパイル済みの配布物)を探します。wheel があれば、ダウンロードして展開するだけで、コンパイルは起きません。

ところが、環境に合う wheel が無いと、pip は sdist(ソース配布物)を落としてその場でビルドしようとします。Rust 拡張のビルドには rustc(Rust コンパイラ)が要ります。それが PATH に無いと、ビルドが build_rust の段階で error: can't find Rust compiler で止まります。

なぜ手元では出ないのか

手元(デスクトップや、これまで使っていた環境)では、そのパッケージの wheel がそのまま入っていました。ソースビルドに落ちるのは、環境に合う wheel が無いか、pip がその wheel を使えていないときです。

看板の cryptography は、Linux 向けに manylinux と musllinux(Alpine 用)の両方を配り、しかも abi3 wheel(1つの wheel が新しい Python でもそのまま使える形)を出しています。だから Alpine でも新しい Python でも、たいていは wheel が当たります。それでもソースビルドに落ちるのは、次のようなときです。

  • --no-binary を付けている--no-binary はソースビルドを強制する指定です。意図せず付いていると、wheel があってもビルドに入り、Rust を要求されます。
  • pip が古くて wheel のタグを読めないmusllinuxabi3 のタグに対応していない古い pip は、wheel があってもソースへ落ちることがあります。
  • wheel の無いプラットフォームppc64les390x のような、そのパッケージが wheel を配っていない CPU アーキテクチャ。

つまり cryptography では、「Alpine だから wheel が無い」はたいてい当てはまりません(musllinux wheel があります)。パッケージによっては musllinux wheel を出しておらず「Alpine だから」が本当に効くこともありますが、まずは決めつけずに、本当にソースからビルドする必要があるのかを疑ってください。

直し方1:wheel を使えるようにする(基本)

Rust を入れる前に、wheel を取りに行く方向を先に検討します。エラーメッセージが最初に案内するのもこちらです。まず、wheel が存在するのに使えていないのか、そもそも無いのかを切り分けます。

pip install --only-binary=:all: <パッケー>

これが成功すれば wheel は存在します(=直し方1で解けます)。失敗すれば、その Python・プラットフォーム向けの wheel がそもそも無いので、直し方2(Rust を入れる)かプラットフォーム変更に進みます。切り分け専用の指定で、通常のインストールに付けるものではありません。

wheel が存在するのに使えていない場合の直し方:

  • pip を新しくするpip install --upgrade pip。古い pip は musllinuxabi3 などの wheel タグを読めず、wheel があってもソースビルドへ落ちることがあります。Alpine で cryptography が落ちたときも、多くはこれで musllinux wheel が取れます。
  • --no-binary を外す--no-binary を意図せず付けていないか確認します。付いていれば、wheel があってもソースビルドに入ります。
  • wheel のあるプラットフォームに替える:使っているアーキやディストリ向けの wheel が無いなら、wheel の揃う環境に寄せると、ビルドが要らなくなります。

これらで wheel が入るなら、Rust は要りません。

直し方2:どうしても Rust が要るとき(source build を続ける)

--only-binary=:all: でも失敗する(対応 wheel がそもそも無い)場合は、ソースからビルドするしかありません。Rust ツールチェーンを入れます。恒久的に管理された環境なら rustup が推奨です。CI やコンテナでは OS のパッケージからも入りますが、OS パッケージの Rust は古いことがあり(たとえば Debian 11 の cargo は 1.48)、パッケージが要求する版(This package requires Rust >=1.63.0 のように出ます)に届かず再び止まることがあります。その場合は rustup で新しい Rust を入れてください。

さらに、Rust だけでは足りないパッケージが多い点に注意してください。cryptography をソースからビルドするには、Rust に加えて C コンパイラ(build-essential)・OpenSSL の開発ヘッダ(libssl-dev)・libffi の開発ヘッダ・Python の開発ヘッダ・pkg-config が要ります(OpenSSL などとリンクするためです)。orjson のような Rust 中心のパッケージでも、ソースからのビルドには C コンパイラなどが併せて要ります。必要な一式は対象パッケージの版で変わるので、その版の公式ビルド手順cryptography なら インストールドキュメント)で必要な依存を確認するのが確実です。

この道は、コンパイラと多くの依存をイメージに積むことになります。だから、対応 wheel が存在するなら直し方1(wheel を使う)を先に選ぶほうが、イメージも軽く、ビルド時間も要りません。

切り分け(うまくいかないとき)

  • error: command 'gcc' failed も一緒に、あるいは代わりに出る:同じ「ビルド道具が無い」系で、足りないのが C コンパイラ側です。対処は error: command ‘gcc’ failed(pip がソースビルドに落ちて gcc が無い) を参照してください。cryptography は Rust と C の両方を使うので、Rust を入れた次に gcc 側で止まることがあります。
  • Rust を入れたのに、まだ can't find Rust compiler と出るrustcPATH に通っているかを確認してください。rustup で入れた場合、source "$HOME/.cargo/env" を実行するか、シェルを開き直さないと PATH に載らないことがあります。rustc --version が通るかを先に見ます。
  • This package requires Rust >=X で止まる:Rust は入っているが版が古いケースです。rustup update か、新しい Rust を入れ直します。OS パッケージの cargorustc が古いこともあります。
  • pip install は通ったのに、実行時に別のエラーが出る:それはビルドと別の問題です。まずは今回の import が通るかを確認してから切り分けます。

検証環境

  • python:3.12-slim、ネットワーク有り
  • 再現:pip install --no-cache-dir --no-binary cryptography "cryptography==42.0.5" が、Rust の無い環境で error: can't find Rust compiler を出して終了コード 1
  • 修正:pip install --no-cache-dir "cryptography==42.0.5"(wheel を使う)の後、終了コード 0

再現から修正までは errfix の検証ハーネスが機械的に確認しています。ここでは --no-binary cryptography でソースビルドを強制し(実環境では wheel が無いと自動でこの経路に入ります)、--no-cache-dir でキャッシュを使わせずに、can't find Rust compiler が出ること、--no-binary を外して wheel を使うと同じインストールが通ることを、再現→修正→シグネチャ消滅として通しました。エラー文言と「wheel を使えば Rust は要らない」というヒントは実機出力から引用しています。Rust を入れる方向(直し方2)は環境ごとに要求が変わるため、本記事では機械検証の対象は wheel を使う経路に限っています。

検証(machine-verified)

この修正は python:3.12-slim のバージョン固定コンテナ内で再現し、修正後に can't find Rust compiler のシグネチャが消えることを機械で確認しています。

verify — run-case.mjs
$ node run-case.mjs python/cant-find-rust-compiler
● reproduce can't find Rust compiler present ✓
● apply fix exit 0
● re-run can't find Rust compiler gone ✓
PASS verified · python:3.12-slim · signature gone