Error [command 'gcc' failed]

error: command 'gcc' failed の直し方(wheel が無く pip がソースビルドに落ちるとき)

FIX SUMMARY verified
Applies when
python:3.12-slimany C-extension package without a matching wheel (psutil in verification)pip falls back to source build (no wheel) on a slim image lacking gcc/python3-dev

Verified: reproduced in python:3.12-slim, then the command 'gcc' failed signature was gone after the fix (exit 0).

pip install の途中で、パッケージのビルドに入り、次のエラーで止まることがあります。

error: command 'gcc' failed: No such file or directory
...
ERROR: Failed building wheel for <パッケージ名>

ヘッダが足りない環境では、代わりに次の形でも出ます。

fatal error: Python.h: No such file or directory

どちらも、pip が事前ビルド済みのパッケージ(wheel)を使えず、ソースからコンパイルしようとして、その環境に C コンパイラや開発用ヘッダが無いために起きます。Python やパッケージのコードの誤りではなく、OS 側にビルド道具が無いという環境の問題です。

サーバや Docker で使うなら、直し方は C コンパイラと開発ヘッダを入れるか、そもそもビルドせずに済む wheel を取りに行くかのどちらかです。

なぜソースビルドに入るのか

多くのパッケージは、あらかじめコンパイル済みの wheel を配っています。wheel があれば、pip install はそれをダウンロードして展開するだけで、コンパイルは起きません。ところが、環境に合う wheel が無いと、pip は sdist(ソース配布物)を落としてその場でビルドしようとします。C 拡張を含むパッケージのビルドには、C コンパイラ(gcc)と Python の開発ヘッダ(Python.h)が要ります。

python:3.12-slim のような軽量イメージには、これらのビルド道具が入っていません。だからソースビルドに入った瞬間、gcc が見つからず command 'gcc' failed で止まります。コンパイラはあってもヘッダが無ければ、今度は Python.h: No such file or directory になります。

なぜ手元では出なかったのか

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

  • 新しい Python に、ライブラリがまだ対応した wheel を出していない(例:出たばかりの Python の版に、依存ライブラリの wheel が追いついていない)。
  • Alpine(musl)ベースのイメージ:一般的な Linux 向け wheel(manylinux)は使えず、Alpine 用の wheel(musllinux)が要ります。それが無いとソースビルドに入り、musl-dev などの道具も要ります。
  • 珍しい CPU アーキテクチャで wheel が配られていない。

「手元では入るのに、slim イメージや新しい Python、Alpine の CI でだけビルドに落ちる」という形です。まず、本当にソースからビルドする必要があるのかを疑ってください。

まず考える:ビルドせずに済ませられないか

ソースビルドは避けられることが多いです。wheel を取りに行く方向を先に検討します。

  • pip を新しくするpip install --upgrade pip。古い pip は、新しい形式の wheel を認識できずにソースビルドへ落ちることがあります。
  • wheel のあるプラットフォームを使う:Alpine で詰まっているなら、python:3.12-slim(Debian ベース)に替えると manylinux wheel が使えて、ビルドが要らなくなることがあります。軽さより、wheel が揃う環境を優先します。
  • --no-binary を付けていないか確認する--no-binary はソースビルドを強制する指定です。意図せず付いていると、wheel があってもビルドに入ります。
  • wheel があるかを先に確かめるpip install --only-binary=:all: <パッケージ> を打つと、wheel が無ければ即座に失敗します。道具を入れる前に「本当に wheel が無いのか」を切り分けられます(切り分け専用で、通常のインストールに付ける指定ではありません)。

これらで wheel が入るなら、コンパイラを入れる必要はありません。

直し方:ビルド道具を入れる

wheel がどうしても無く、ソースからビルドするしかない場合は、C コンパイラと開発ヘッダを入れます。Debian / Ubuntu 系なら次のとおりです(Dockerfile の root ユーザーならそのまま、ホストで直接入れるなら sudo を付けます)。

apt-get update && apt-get install -y build-essential python3-dev

build-essentialgcc などのコンパイラ一式を提供します。公式の python:*-slimPython.h などの開発ヘッダをインタプリタに同梱しているため、このイメージで実際に欠けるのは gcc だけです(この記事の検証でも、欠けていたのは gcc でした)。python3-dev が要るのは、ディストリの system Python(Debian の python3 など)を使っていてヘッダが本当に無い構成のときで、公式 python イメージでは併せて入れても使われません(別バージョンの system Python 用ヘッダのため)。Dockerfile なら、pip install前にこの行を置きます。パッケージによっては、さらに個別の開発ライブラリ(libpq-devlibssl-dev など)が要ることもあり、その場合はビルドログに出る不足ファイルの名前から必要なパッケージを足します。Alpine なら apk add build-base python3-dev が相当します(build-basemusl-dev などが含まれます)。

ビルドが済んだイメージを軽くしたいなら、ビルド道具を入れるステージと実行するステージを分ける(マルチステージビルド)方法もありますが、まずはこの一手で import まで通してから考えれば十分です。

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

  • Python.h: No such file or directory が出る:コンパイラ(gcc)はあるが、Python の開発ヘッダが無い状態です。python3-dev(Alpine なら python3-dev)を入れてください。build-essential だけでは足りないことがあります。
  • command -v gccgcc が見つかるのに、それでも command 'gcc' failed が出る:この場合は道具不足ではなく、コンパイルそのものの失敗です。build-essential を入れ直しても直りません。ビルドログの error:fatal error: の実際の行(不足しているヘッダ名や API の非互換)を読んで、そこに従ってください。
  • gcc を入れても、別のライブラリが無いと言われる:C 拡張が外部ライブラリに依存していることがあります(データベースドライバなら libpq-dev、暗号系なら libssl-dev など)。ビルドログの fatal error: xxx.h: No such file or directoryxxx から、必要な -dev パッケージを探します。
  • error: can't find Rust compiler が出る:最近は一部のパッケージ(cryptographypydantic など)が Rust でビルドされます。これも「コンパイラが無い」同型で、足りないのが Rust 側です。対処は error: can’t find Rust compiler(pip が wheel を使えずソースビルドに落ちる) を参照してください。
  • ビルドは通るのに、次に入れ直すとまた失敗するpip はビルド済みの wheel をキャッシュするので、一度成功すると次回はキャッシュから入ります。逆に、キャッシュを消したり別環境に移ると、また同じビルドに入ります。恒久的には、ビルド道具を入れておくか、wheel が配られている環境にそろえます。

検証環境

  • python:3.12-slim、ネットワーク有り
  • 再現:pip install --no-cache-dir --no-binary :all: "psutil==5.9.8" が、gcc の無い環境で error: command 'gcc' failed: No such file or directory を出して終了コード 1
  • 修正:apt-get install -y build-essential python3-dev の後、同じ install が終了コード 0

再現から修正までは errfix の検証ハーネスが機械的に確認しています。ここでは --no-binary :all: でソースビルドを強制し(実環境では wheel が無いと自動でこの経路に入ります)、--no-cache-dir でビルド済みのキャッシュを使わせずに、コンパイラの有無で結果が変わることを、再現→修正→シグネチャ消滅として通しました。python:3.12-slim では Python.h は同梱されており、欠けていたのは gcc でした。Python.h 不足や Alpine の musl-dev、Rust ツールチェーンなど、環境ごとに足りない道具は変わります。

検証(machine-verified)

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

verify — run-case.mjs
$ node run-case.mjs python/pip-gcc-failed-source-build
● reproduce command 'gcc' failed present ✓
● apply fix exit 0
● re-run command 'gcc' failed gone ✓
PASS verified · python:3.12-slim · signature gone