在一台新机器上批量装 Python 包,大部分包顺利装上,偏偏有几个反复失败,报错里全是 C 编译器的身影。第一反应往往是"网络又抽风了"或者"镜像源有问题",但换源、重试、换时段都无济于事——因为根本不是网络的事。
现象
执行安装命令时,一部分包成功,另一部分失败:
$ pip install <一批包>
...
Collecting <某个包>
Building wheel for <某个包> ... error
error: subprocess-exited-with-error
× Building wheel for <某个包> failed
...
error: command 'gcc' failed: No such file or directory
error: command 'make' failed: No such file or directory
或者更直接:
fatal error: Python.h: No such file or directory
gcc: command not found
关键特征:失败的都是同一类包,而常用的 HTTP 客户端、数值计算、Web 框架类包却装得好好的。
根因
这里的核心区别是 wheel 和 sdist:
- 有预编译 wheel 的包:发布者已经把编译好的二进制打包上传(文件名形如
xxx-1.2.3-cp311-cp311-manylinux_x86_64.whl)。pip直接下载、解包、放进site-packages即可,不需要在本机做任何编译。所以哪怕系统里没有任何编译工具,它们也照样装得上。 - 只有源码分发包(sdist,通常是
.tar.gz)的包:pip必须先在本机把它编译成二进制,这一步需要 C 编译器(gcc)、构建工具(make)以及 Python 的开发头文件(Python.h,在python3-devel里)。
你看到的"有的包装得上、有的装不上",恰恰就是这两类的分界线。常用库几乎都提供 wheel,所以不受影响;而那些平台特殊、或版本较老、或发布者懒得预编译的包,就只能从源码编译——这时候系统里没有工具链,自然必挂。
还有一个隐蔽点:报错里写着 command 'gcc' failed: No such file or directory,容易被看成"I/O 错误"或"找不到文件",实际含义是"没有装 gcc 这个命令"。系统里可能只装了运行时库(glibc 之类),而没有编译器本体。
解决
第一步,补装编译工具链。 在基于 RPM 的发行版(如 Fedora / CentOS / RHEL 系)上:
sudo dnf install -y gcc gcc-c++ make python3-devel
在基于 Debian 的系统上对应的是:
sudo apt-get install -y build-essential python3-dev
这几样各司其职:gcc/gcc-c++ 是 C/C++ 编译器,make 是构建工具,python3-devel 提供 Python.h 等在编译 Python 扩展时必须的头文件和链接信息。装齐之后再重试安装:
pip install <那个装不上的包>
第二步,日常优先选用提供 wheel 的版本。 不是每个包都值得为它装一整套编译器。装之前可以先看看有没有现成的 wheel:
pip install --only-binary=:all: <包名>
--only-binary=:all: 表示"只接受预编译包,没 wheel 就直接失败",这样能快速判断某个版本是否提供了 wheel。如果某个包总是要编译,可以退而求其次,选一个发布了 wheel 的版本(比如稍旧一点的稳定版),或者改用功能等价的、提供 wheel 的替代库。
第三步,考虑用带二进制依赖的发行方式。 如果这类编译依赖很多,用 Conda 之类的环境管理工具往往更省心——它们的仓库里预先编好了大量常用科学计算包,直接装二进制,不用本机编译。
延伸与预防
一句话记住这条教训:"有的包装得上、有的装不上"往往不是网络问题,而是本地有没有编译工具链。
排查时按这个顺序走,能少绕很多弯:
- 看报错里有没有
gcc/make/Python.h/command ... failed——有,就是缺工具链,装编译器和-devel包。 - 看是不是只有特定几个包失败——是,就是"没有 wheel、只能源码编译"的那几个。
- 排除了以上,再去怀疑网络、镜像源、代理。
预防上,最实在的一条是把编译环境写进部署脚本:新机器初始化时就把 gcc make python3-devel 一起装上,别等到装包时才发现。另外,给项目锁一个 requirements.txt,并且尽量固定到"有 wheel 的版本",能显著减少在不同机器上重现出"有的装得上有的装不上"这种薛定谔现象的概率。