Error [No such file or directory: 'gcc']

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 No such file or directory: 'gcc' signature was gone after the fix (exit 0).

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

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

setuptools 84.0.0 以降では、同じ状況が次の文言で出ます。

error: [Errno 2] No such file or directory: 'gcc'
...
ERROR: Failed building wheel for <パッケージ名>

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

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

いずれも、pip が事前ビルド済みのパッケージ(wheel)を使えず、ソースからコンパイルしようとして、その環境に C コンパイラや開発用ヘッダが無いために起きます。

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

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

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

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

なぜ setuptools 84 以降は文言が変わるのか

gcc が無いと分かった行を書いているのは pip ではなく、ビルドバックエンドの setuptools です。ここの文言が setuptools 84.0.0 で変わりました。

setuptools止まるときに出る行
83.0.0 以下error: command 'gcc' failed: No such file or directory
84.0.0 以上error: [Errno 2] No such file or directory: 'gcc'

この 2 つの版の間に別の版はないので、境界はここだけです。症状も直し方も同じで、変わったのは表示だけです。

パッケージの版を固定していても、この行は変わります。 pip install はビルドを隔離環境(build isolation)で行い、そこへ入れる setuptools はそのときの最新を取ってくるからです。requirements.txt やロックファイルが押さえているのはインストールする側の依存で、ビルドする側の道具ではありません。ビルド側も固定するなら、制約ファイルを PIP_CONSTRAINT で渡します。

echo "setuptools==83.0.0" > build-constraints.txt
PIP_CONSTRAINT=build-constraints.txt pip install <パッケー>

古い記事や社内の手順書が command 'gcc' failed を検索語にしていると、84 以降の環境では引っかかりません。No such file or directory: 'gcc' で探し直してください。

なぜ wheel が無い環境で出るのか

手元(デスクトップや、これまで使っていた環境)では、そのパッケージの 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(84 以降は No such file or directory: 'gcc')が出る:この場合は道具不足ではなく、コンパイルそのものの失敗です。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: [Errno 2] No such file or directory: 'gcc' を出して終了コード 1(ビルドバックエンドは pip が隔離環境へ入れる setuptools 84.0.0。83.0.0 以下なら同じ場所で error: command 'gcc' failed: No such file or directory
  • 修正: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 のバージョン固定コンテナ内で再現し、修正後に No such file or directory: 'gcc' のシグネチャが消えることを機械で確認しています。

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

確認したのは上のイメージの中だけです。別の環境で直らなかった、記述が違う、という場合は 報告してください(対象と検証イメージは件名・本文に入ります)。