只装 build-base 不行,因其仅含 gcc/g++/make/musl-dev/binutils,缺少 python3-dev(提供 python.h)和 libffi-dev(提供 ffi.h),而 musl-dev 才提供 limits.h 等基础头文件。

直接装 build-base 就能解决绝大多数 Python C 扩展编译失败问题,但必须配合 python3-dev 和 libffi-dev,否则仍会报 limits.h: No such file or directory 或 ffi.h: No such file or directory。
为什么只装 gcc 不行?
Alpine 的 gcc 包只是编译器本体,不带标准头文件、Python C API 头、libffi 接口头。pip 构建 cffi、cryptography、pydantic-core 等包时,第一行就卡在 #include <python.h></python.h> 或 #include <ffi.h></ffi.h>。
-
python3-dev提供Python.h、pyconfig.h和静态链接库libpython3.12.a -
libffi-dev提供ffi.h和ffitarget.h,是cffi编译的硬依赖 -
musl-dev(常被忽略)提供limits.h、stdint.h等基础 C 标准头,缺它连setuptools自身都可能编译失败
build-base 是什么,能不能只装它?
build-base 是 Alpine 的元包,等价于 gcc + g++ + make + musl-dev + binutils。它解决了编译工具链问题,但不包含 python3-dev 和 libffi-dev —— 这两个必须显式加装。
正确写法是:
apk add --no-cache build-base python3-dev libffi-dev
不要拆开成 apk add gcc make musl-dev 再补一堆,容易漏;也不要只装 build-base 就以为万事大吉。
装完还要卸载吗?生产镜像要不要保留 build-base?
要卸载,但不能简单 apk del build-base —— 它会把 musl-dev 也删掉,而 musl-dev 提供的头文件已被编译产物静态链接进 .so 文件,运行时不需要,但删它不影响;真正不能删的是 libffi 运行时库(非 -dev 版),否则 cffi 导入就报 libffi.so.8: cannot open shared object file。
- 构建阶段:装
build-base python3-dev libffi-dev - 安装完所有 Python 包后:用
apk del --no-cache build-base python3-dev卸载开发包 - 保留
libffi(不含-dev)—— 它是运行时依赖,apk info libffi可确认已存在
ARM64 架构下 wheel 缺失怎么办?
PyPI 上很多包对 aarch64 的 wheel 更新滞后,尤其是新 Python 版本(如 3.12)刚发布时。即使装了全套编译工具,pip 仍可能因找不到匹配的 manylinux_aarch64 wheel 而 fallback 到源码编译 —— 这正是你遇到的场景。
此时有两个选择:
- 加
--only-binary=:all:强制跳过源码构建(但多数情况下会直接失败,因为没 wheel 可用) - 更可靠的做法:加
--prefer-binary并确保build-base等已就位,让 pip 在找不到 wheel 时自动编译(这才是默认且预期的行为) - 注意:不要设
PIP_NO_BINARY=cffi之类,这反而会禁用已有的 wheel,强迫走编译路径
最终镜像体积增加约 80–120MB(build-base 层大小),但换来的是跨架构构建稳定性 —— 这比反复调试 wheel 兼容性更省时间。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











