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-essential が gcc などのコンパイラ一式を提供します。公式の python:*-slim は Python.h などの開発ヘッダをインタプリタに同梱しているため、このイメージで実際に欠けるのは gcc だけです(この記事の検証でも、欠けていたのは gcc でした)。python3-dev が要るのは、ディストリの system Python(Debian の python3 など)を使っていてヘッダが本当に無い構成のときで、公式 python イメージでは併せて入れても使われません(別バージョンの system Python 用ヘッダのため)。Dockerfile なら、pip install の前にこの行を置きます。パッケージによっては、さらに個別の開発ライブラリ(libpq-dev、libssl-dev など)が要ることもあり、その場合はビルドログに出る不足ファイルの名前から必要なパッケージを足します。Alpine なら apk add build-base python3-dev が相当します(build-base に musl-dev などが含まれます)。
ビルドが済んだイメージを軽くしたいなら、ビルド道具を入れるステージと実行するステージを分ける(マルチステージビルド)方法もありますが、まずはこの一手で import まで通してから考えれば十分です。
切り分け(うまくいかないとき)
Python.h: No such file or directoryが出る:コンパイラ(gcc)はあるが、Python の開発ヘッダが無い状態です。python3-dev(Alpine ならpython3-dev)を入れてください。build-essentialだけでは足りないことがあります。command -v gccでgccが見つかるのに、それでもcommand 'gcc' failedが出る:この場合は道具不足ではなく、コンパイルそのものの失敗です。build-essentialを入れ直しても直りません。ビルドログのerror:やfatal error:の実際の行(不足しているヘッダ名や API の非互換)を読んで、そこに従ってください。gccを入れても、別のライブラリが無いと言われる:C 拡張が外部ライブラリに依存していることがあります(データベースドライバならlibpq-dev、暗号系ならlibssl-devなど)。ビルドログのfatal error: xxx.h: No such file or directoryのxxxから、必要な-devパッケージを探します。error: can't find Rust compilerが出る:最近は一部のパッケージ(cryptography・pydanticなど)が 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 ツールチェーンなど、環境ごとに足りない道具は変わります。