自己编译一个最新版本的 Python3

最近想看看 Python 3.10 的模式匹配新特性,刚好也了解了一些编译相关的基础知识,于是尝试下在平时使用的测试机上编译一份最新的 Python。

工作环境

测试机的操作系统是 Ubuntu 20.10,已安装有 gccgit 等基础的开发工具。经验证以下步骤同样适用于 macOS 11。

1
2
uname -a
Linux waynerv-woqutech 5.8.0-48-generic #54-Ubuntu SMP Fri Mar 19 14:25:20 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

下载源码

从 CPython 的官方仓库 https://github.com/python/cpython 克隆源码:

1
git clone https://github.com/python/cpython.git

这个仓库的文件体积很大,如果克隆时遇到网络问题,可尝试使用 Gitee 的「同步 GitHub 仓库」功能。

配置

核心的 CPython 编译器只需要一个基本的 C 编译器就可以编译,但一些扩展模块会需要开发头文件来提供一些额外的库(如压缩功能需要的zlib库),这也是为什么我们用操作系统提供的包管理器(如apt)安装 Python 时会需要 python3-dev 等等一大堆依赖。

由于我并不打算将自行编译的 Python 用于开发或生产,因此将跳过安装依赖这一步。

首先进入我们所克隆的仓库目录:

1
cd cpython

然后需要进行配置:

1
./configure --prefix=/root/build-python

默认情况下,后续的 make install 命令会将编译得到的文件安装到 /usr/local/bin/usr/local/lib,这可能会覆盖系统已有的安装文件,为了不和系统已安装的 Python 版本产生冲突,我们通过指定 --prefix 选项将其安装到一个自定义的目录。

编译

配置结束后运行编译:

1
make -s -j 4

执行编译时可通过 -j 选项指定并行的任务数量来加快速度,通常我们将其设置为编译机器的 CPU 数量,可以结合 nproc 命令使用:

1
make -s -j "$(nproc)"

-s 选项意为 silence,即不打印编译的过程日志,也可启用。

编译的过程可能会比较耗时,成功后的输出如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Python build finished successfully!
The necessary bits to build these optional modules were not found:
_bz2                  _curses               _curses_panel      
_dbm                  _gdbm                 _hashlib           
_lzma                 _sqlite3              _ssl               
_tkinter              _uuid                 readline           
To find the necessary bits, look in setup.py in detect_modules() for the module's name.


The following modules found by detect_modules() in setup.py, have been
built by the Makefile instead, as configured by the Setup files:
_abc                  pwd                   time               


Could not build the ssl module!
Python requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().
LibreSSL 2.6.4 and earlier do not provide the necessary APIs, https://github.com/libressl-portable/portable/issues/381

由于我们没有安装依赖,所以提示有部分模块未找到,但不影响使用 Python 的基本功能。

安装

编译成功后其实已经可以运行 Python 了。上述构建过程会在当前目录(非--prefix指定的目录)生成一个名为 python 的二进制文件(macOS 下是 python.exe),运行它即可启动 Python 解释器:

1
./python

它会使用当前目录中编译生成的临时文件作为资源文件,现在我们将其安装到在配置步骤中指定的目录:

1
make install

安装过程会进行大量的资源复制,并调用 Python 解释器将使用 Python 实现的标准库编译为字节码(.pyc),此外默认还会安装 setuptoolspip 这两个 Python 包,因此当我们安装较新版本的 Python 版本时,基本不再需要手动安装 pip

安装完成后切换到 /root/build-python 目录下,并查看其目录结构:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cd /root/build-python
tree -L 2 .
.
├── bin
│   ├── 2to3 -> 2to3-3.10
│   ├── 2to3-3.10
│   ├── idle3 -> idle3.10
│   ├── idle3.10
│   ├── pip3
│   ├── pip3.10
│   ├── pydoc3 -> pydoc3.10
│   ├── pydoc3.10
│   ├── python3 -> python3.10
│   ├── python3.10  # Python 可执行文件
│   ├── python3.10-config
│   └── python3-config -> python3.10-config
├── include
│   └── python3.10  # 头文件目录
├── lib
│   ├── libpython3.10.a  # 静态库文件
│   ├── pkgconfig
│   └── python3.10  # 标准库文件及 site-packages
└── share
    └── man

现在执行 ./bin/python3 即可运行我们自己编译安装好的 Python:

1
2
3
Python 3.10.0a6+ (heads/master:80017752ba, Apr  6 2021, 13:47:23) [GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

大功告成!可以看到运行的 Python 版本是 3.10.0a6+,一个尚未发布的开发中版本。

如果我们需要其他稳定版本的 Python,只需要在源码仓库中 git checkout 到指定的 release 标签,然后再重新运行配置-编译-安装 3 个步骤就可以了。

参考链接

updatedupdated2022-08-032022-08-03