Skip to content

源码编译安装 ​

源码编译安装是从 CPython 官方源代码构建解释器的过程。它能让你获得最新的小版本、针对 CPU 做优化(如 --enable-optimizations)、自定义安装路径,或在没有预编译包的平台上使用。本节将完整讲解依赖准备、./configure 选项、make 编译、make altinstall 安装与虚拟环境验证。

前置知识

阅读本节前,建议先了解:Linux 安装 Python

基础概念 ​

CPython 官方源码包(Source Distribution)包含 C 语言实现的解释器与标准库。编译过程大致分为四步:

阶段命令作用
配置./configure探测系统环境、生成 Makefile
编译make编译 C 源码,生成 python 可执行文件
优化编译make profile-opt由 --enable-optimizations 触发,含 PGO
安装make install / make altinstall复制文件到系统目录

关键术语:

  • PGO(Profile-Guided Optimization,配置文件引导优化):先运行测试用例收集热点,再据此重新编译,可提升 10%~20% 性能。
  • altinstall:以版本号命名安装,不覆盖系统 python3,是多版本共存的关键。
  • prefix:安装前缀路径,如 /usr/local 或 /opt/python-3.12.7。
  • LTO(Link Time Optimization,链接时优化):跨编译单元优化,配合 PGO 使用。

--enable-optimizations 的影响

该选项会显著延长编译时间(可能从几分钟变为十几分钟到半小时),但生成的解释器性能更好。生产环境建议开启,本地快速验证可省略。

语法与用法 ​

标准编译流程(以 Python 3.12.7 为例):

bash
# 1. 下载源码
wget https://www.python.org/ftp/python/3.12.7/Python-3.12.7.tgz

# 2. 解压
tar -xzf Python-3.12.7.tgz
cd Python-3.12.7

# 3. 配置(开启优化与共享库)
./configure --enable-optimizations --enable-shared --prefix=/usr/local

# 4. 编译(使用多核并行)
make -j$(nproc)

# 5. 安装(避免覆盖系统 python3)
sudo make altinstall

# 6. 验证
python3.12 --version

详细说明 ​

步骤一:安装编译依赖 ​

不同发行版需要不同的开发库。缺少任意一个都可能导致某个标准库模块无法编译。

Debian / Ubuntu:

bash
sudo apt update
sudo apt install -y build-essential \
    zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev \
    libssl-dev libreadline-dev libffi-dev libsqlite3-dev \
    libbz2-dev liblzma-dev tk-dev uuid-dev libdb-dev \
    libexpat1-dev libmpdec-dev

RHEL / Fedora:

bash
sudo dnf install -y gcc gcc-c++ make \
    zlib-devel bzip2-devel openssl-devel ncurses-devel \
    sqlite-devel readline-devel tk-devel gdbm-devel \
    libuuid-devel libffi-devel xz-devel expat-devel

Alpine Linux:

bash
sudo apk add --no-cache \
    build-base zlib-dev bzip2-dev openssl-dev ncurses-dev \
    sqlite-dev readline-dev tk-dev gdbm-dev libffi-dev \
    xz-dev expat-dev linux-headers

macOS:

bash
# 先安装 Xcode 命令行工具
xcode-select --install

# 通过 Homebrew 安装依赖
brew install openssl readline sqlite3 xz zlib tcl-tk

缺失依赖的典型症状

编译日志中出现 The necessary bits to build these optional modules were not found 提示,后面列出 _ssl、_sqlite3、_ctypes、_bz2 等模块名。这表示对应依赖缺失,需补装后重新 ./configure && make。

步骤二:下载与解压源码 ​

bash
# 下载指定版本(推荐使用 wget 或 curl)
cd /tmp
wget https://www.python.org/ftp/python/3.12.7/Python-3.12.7.tgz

# 校验完整性(可选但推荐)
wget https://www.python.org/ftp/python/3.12.7/Python-3.12.7.tgz.sha256
sha256sum -c Python-3.12.7.tgz.sha256

# 解压
tar -xzf Python-3.12.7.tgz
cd Python-3.12.7

步骤三:configure 配置选项 ​

./configure 是编译前的环境探测与参数配置阶段。常用选项如下:

选项说明
--prefix=PATH安装前缀,默认 /usr/local
--enable-optimizations开启 PGO 优化,显著提升性能
--with-lto开启链接时优化(LTO),需较新编译器
--enable-shared生成共享库 libpython3.12.so
--enable-loadable-sqlite-extensions允许加载 SQLite 扩展
--with-openssl=PATH指定 OpenSSL 路径(macOS 常用)
--without-ensurepip不安装 pip(后续手动安装时使用)
--with-ensurepip=install安装 pip(默认 upgrade)
--disable-test-modules不安装测试模块,减小体积

生产环境推荐配置:

bash
./configure \
    --prefix=/usr/local \
    --enable-optimizations \
    --with-lto \
    --enable-shared \
    --enable-loadable-sqlite-extensions \
    LDFLAGS="-Wl,-rpath,/usr/local/lib"

--enable-shared 的注意事项

开启共享库后,安装的 libpython3.12.so 位于 /usr/local/lib,运行时需要该目录在动态链接器搜索路径中。使用 LDFLAGS="-Wl,-rpath,/usr/local/lib" 可在可执行文件中内嵌 rpath,免去配置 LD_LIBRARY_PATH。若不设置,执行 python3.12 可能报 libpython3.12.so.1.0: cannot open shared object file。

步骤四:编译 ​

bash
# 使用全部 CPU 核心并行编译
make -j$(nproc)

# macOS 上使用:
# make -j$(sysctl -n hw.ncpu)

# 只编译不安装,可用于快速验证
# 编译产物为 ./python
./python -c "print('编译成功')"

编译过程中的 PGO 阶段会运行整套测试套件,耗时较长。可观察输出:

text
Running code to generate profile data (this can take a while)...

步骤五:安装 ​

bash
# 方式一:altinstall(推荐,多版本共存,不覆盖系统 python3)
sudo make altinstall

# 方式二:install(会创建 python3 符号链接,可能覆盖系统版本)
sudo make install

两者的区别:

命令生成的可执行文件是否覆盖系统 python3
make installpython3、python3.12是(有风险)
make altinstall仅 python3.12否

为什么推荐 altinstall

make install 会创建 /usr/local/bin/python3 并可能覆盖发行版管理的 python3,导致系统工具异常。altinstall 只安装带完整版本号的可执行文件,安全且便于多版本共存。

编译产物的目录结构 ​

编译完成后,源码目录中会出现若干关键路径:

text
Python-3.12.7/
├── python                    # 编译出的可执行文件,可直接运行
├── libpython3.12.a           # 静态库(未开启 shared 时)
├── libpython3.12.so          # 共享库(开启 --enable-shared 时)
├── build/                    # 中间产物
├── Modules/                  # C 扩展模块源码
├── Lib/                      # 标准库 Python 源码
└── Makefile                  # configure 生成的构建文件

安装后的目录结构(以 /usr/local 为例):

text
/usr/local/
├── bin/
│   ├── python3.12
│   ├── pip3.12
│   ├── idle3.12
│   └── pydoc3.12
├── lib/
│   ├── libpython3.12.so.1.0
│   └── python3.12/
│       ├── site-packages/
│       └── lib-dynload/       # 扩展模块 .so
├── include/
│   └── python3.12/            # 头文件,编译 C 扩展用
└── share/
    └── man/man1/python3.12.1

未安装 pip 时

若配置时使用了 --without-ensurepip,则安装目录中不会出现 pip3.12。此时可下载 get-pip.py 手动安装:

bash
curl -O https://bootstrap.pypa.io/get-pip.py
python3.12 get-pip.py

卸载源码安装的 Python ​

源码安装没有包管理器记录,卸载需要手动删除文件:

bash
# 假设 prefix 为 /usr/local
sudo rm -rf /usr/local/bin/python3.12 \
            /usr/local/bin/pip3.12 \
            /usr/local/bin/idle3.12 \
            /usr/local/bin/pydoc3.12
sudo rm -rf /usr/local/lib/libpython3.12.so*
sudo rm -rf /usr/local/lib/python3.12
sudo rm -rf /usr/local/include/python3.12
sudo rm -rf /usr/local/share/man/man1/python3.12.1
sudo ldconfig

逐一确认再删除

/usr/local 下可能同时存在多个版本的 Python 文件。删除前先用 ls /usr/local/lib | grep python 确认版本号,避免误删其他版本。

验证安装 ​

基本验证命令 ​

bash
# 1. 版本号
python3.12 --version

# 2. 确认 pip 可用
python3.12 -m pip --version

# 3. 解释器路径(应为 /usr/local/bin 或自定义 prefix)
python3.12 -c "import sys; print(sys.executable)"

# 4. 确认关键标准库模块已编译
python3.12 -c "import ssl, sqlite3, ctypes, bz2, lzma, zlib; print('模块完整')"

# 5. 查看是否为 PGO 优化构建
python3.12 -c "import sysconfig; print(sysconfig.get_config_var('CONFIG_ARGS'))"

# 6. 检查共享库依赖
ldd $(which python3.12) | grep libpython

验证清单脚本 ​

python
"""verify_build.py —— 校验源码编译的 Python 是否功能完整。"""

import importlib
import sys
import sysconfig


# 源码编译最容易缺失的标准库模块
REQUIRED_MODULES: list[str] = [
    "ssl",       # 依赖 OpenSSL
    "sqlite3",   # 依赖 SQLite
    "ctypes",    # 依赖 libffi
    "bz2",       # 依赖 libbz2
    "lzma",      # 依赖 liblzma
    "zlib",      # 依赖 zlib
    "readline",  # 依赖 readline
    "hashlib",   # 部分算法依赖 OpenSSL
]


def check_modules() -> bool:
    """逐个导入模块并报告结果,返回是否全部通过。"""
    ok: bool = True
    for name in REQUIRED_MODULES:
        try:
            importlib.import_module(name)
            print(f"  ✅ {name}")
        except ImportError as exc:
            ok = False
            print(f"  ❌ {name} —— {exc}")
    return ok


if __name__ == "__main__":
    print(f"解释器:{sys.executable}")
    print(f"版本:{sys.version.split()[0]}")
    print(f"前缀:{sys.prefix}")
    print(f"编译参数:{sysconfig.get_config_var('CONFIG_ARGS')}")
    print("模块检查:")
    sys.exit(0 if check_modules() else 1)
bash
python3.12 verify_build.py

步骤六:安装后处理 ​

bash
# 若开启了 --enable-shared,刷新动态链接库缓存
sudo ldconfig

# 或写入 /etc/ld.so.conf.d/
echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/python3.12.conf
sudo ldconfig

# 验证共享库可被找到
ldd $(which python3.12) | grep libpython

实战示例 ​

案例一:Ubuntu 上编译安装 Python 3.12.7 ​

bash
#!/bin/bash
# build-python.sh —— 在 Debian/Ubuntu 上编译安装 Python 3.12.7
set -euo pipefail

VERSION="3.12.7"
PREFIX="/usr/local"

# 1. 安装依赖
sudo apt update
sudo apt install -y build-essential zlib1g-dev libncurses5-dev \
    libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev \
    libsqlite3-dev libbz2-dev liblzma-dev tk-dev uuid-dev libexpat1-dev

# 2. 下载并解压
cd /tmp
wget -q "https://www.python.org/ftp/python/${VERSION}/Python-${VERSION}.tgz"
tar -xzf "Python-${VERSION}.tgz"
cd "Python-${VERSION}"

# 3. 配置
./configure \
    --prefix="${PREFIX}" \
    --enable-optimizations \
    --with-lto \
    --enable-shared \
    LDFLAGS="-Wl,-rpath,${PREFIX}/lib"

# 4. 编译并安装
make -j"$(nproc)"
sudo make altinstall

# 5. 刷新共享库
echo "${PREFIX}/lib" | sudo tee /etc/ld.so.conf.d/python3.12.conf
sudo ldconfig

# 6. 验证
python3.12 --version
python3.12 -m pip --version
echo "安装完成!"

案例二:编译到独立前缀并切换 ​

bash
# 安装到 /opt/python-3.12.7,完全隔离
./configure --prefix=/opt/python-3.12.7 --enable-optimizations
make -j$(nproc)
sudo make altinstall

# 验证
/opt/python-3.12.7/bin/python3.12 --version

# 加入 PATH 以便全局调用
echo 'export PATH="/opt/python-3.12.7/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

# 升级 pip
python3.12 -m pip install --upgrade pip

# 创建虚拟环境
python3.12 -m venv ~/venvs/demo
source ~/venvs/demo/bin/activate

案例三:使用 pyenv 自动编译安装 ​

若不想手动处理依赖与选项,pyenv 内部封装了相同的编译流程:

bash
# pyenv 会以 --enable-optimizations 等参数自动编译
pyenv install 3.12.7

# 查看 pyenv 使用的编译配置
cat ~/.pyenv/plugins/python-build/share/python-build/3.12.7

注意事项 ​

  • 编译时间:开启 --enable-optimizations 后通常需 10~30 分钟,make -j 可显著加速。
  • 必须 make altinstall:避免覆盖系统 python3。
  • 共享库路径:--enable-shared 后未配置 rpath 或 ldconfig 会导致启动失败。
  • SSL 模块缺失:OpenSSL 版本过低或头文件缺失,会导致 pip 无法使用(pip is configured with locations that require TLS/SSL)。
  • _ctypes 缺失:缺 libffi-dev,影响大量依赖 C 扩展的库。
  • 内存不足:make -j$(nproc) 在低内存机器上可能 OOM,改用 make -j2。
  • 磁盘空间:编译过程需要 1~2 GB 临时空间。

常见问题排查表:

现象原因解决
缺少 _sslOpenSSL 头文件缺失安装 libssl-dev 后重新编译
缺少 _sqlite3SQLite 开发库缺失安装 libsqlite3-dev
缺少 _ctypeslibffi 缺失安装 libffi-dev
cannot open shared object共享库路径未配置设置 rpath 或 ldconfig
pip is configured with ... TLS/SSLSSL 模块未编译重装 OpenSSL 依赖后重编
make OOM 被杀并行度过高降低 -j 值

最佳实践 ​

  • 生产环境开启 --enable-optimizations 与 --with-lto:性能提升明显。
  • 始终使用 make altinstall:保留系统 Python 完整性。
  • 使用独立 prefix:便于整体卸载与多版本并存。
  • 记录编译参数:将 configure 命令写入构建脚本,保证可复现。
  • 优先考虑 pyenv / uv:除非有特殊定制需求,否则无需手动编译。
  • 容器中编译后清理:多阶段构建,将编译产物复制到精简镜像。
  • 保留源码目录:便于后续打补丁或重新配置。

下一节

继续学习:环境变量配置

参考链接 ​