我的网站目前使用的 Django 版本是 3.2 LTS,Django 对该版本的支持即将在明年初到期,于是准备将它升级到下一个 LTS 版本——4.2。然而我的服务器上安装的 Python 还是老旧的 3.6,从 Django 4 开始,该版本的 Python 已经不被支持,所以需要先做一个新版本 Python 的安装,特此记录。
我的服务器系统是 CentOS 7,这也是一个早已结束支持的操作系统。系统的 RPM 包管理器 yum 能搜索到的 Python 版本最高是 3.6.8,这也是我现在正在使用的版本,所以要想使用更高版本的 Python,只能自行下载源码编译。
Python 官网 下载页面 显示目前 3.10 版本已经处于 security 维护状态,3.11 和 3.12 还在 bugfix,因此虽然目前最高稳定版是 3.12.1,我还是决定只更新到 3.10 最新的 3.10.13,感觉会比较稳定吧。
遵循 官方文档,先使用 yum 安装一些必要依赖:
sudo yum install yum-utils sudo yum-builddep python3sh
下载 Python 3.10.13 的源码并解压:
wget https://www.python.org/ftp/python/3.10.13/Python-3.10.13.tgz tar xf Python-3.10.13.tgzsh
进入解压后的文件夹,配置:
./configure --enable-optimizationssh
--enable-optimizations 是应用优化,如果不加这个参数,在输出的末尾会提示建议添加,故先加上试试。
编译:
makesh
提示:
Could not build the ssl module!
Python requires a OpenSSL 1.1.1 or newer系统 OpenSSL 版本过低,需要先升级到 1.1.1。事实上在执行 ./configure 的输出的靠后位置已有相关提示,可以仔细看看。
由于 EPEL 里面已经有 OpenSSL 1.1.1 了,事实上是不需要像本站 这篇文章 写的那样自己编译的,直接使用 yum 安装即可:
sudo yum install openssl11-develsh
先清理一下编译产物:
make cleansh
再重新走一遍配置。
What???居然还提示 OpenSSL 版本过低。在网上搜了一通,Stack Overflow 上的 该回答 提到是因为动态链接库被安装在了 /usr/lib64 里,这不是 configure 的默认搜索路径,所以需要在配置的时候自行指定:
./configure --enable-optimizations --with-openssl=/usr --with-openssl-rpath=/usr/lib64sh
居然还是不行,找不到新安装的 OpenSSL。又在上述 Stack Overflow 链接中看到另一个回答,说需要先这样做:
mkdir /usr/local/openssl11 cd /usr/local/openssl11 ln -s /usr/lib64/openssl11 lib ln -s /usr/include/openssl11 includesh
也就是把 OpenSSL 的动态链接库目录 /usr/lib64/openssl11 和头文件目录 /usr/include/openssl11 软链接到 /usr/local/openssl11 中,然后在配置时指定该目录为 OpenSSL 的安装目录:
./configure --enable-optimizations --with-openssl=/usr/local/openssl11sh
很有趣,玩了个 trick 欺骗 configure。
终于,输出中没有提示 OpenSSL 有问题了。然而再次编译却报错:
Could not import runpy module
Traceback (most recent call last):
File "/home/zack/tools/Python-3.10.13/Lib/runpy.py", line 15, in <module>
import importlib.util
File "/home/zack/tools/Python-3.10.13/Lib/importlib/util.py", line 14, in <module>
from contextlib import contextmanager
File "/home/zack/tools/Python-3.10.13/Lib/contextlib.py", line 4, in <module>
import _collections_abc
SystemError: <built-in function compile> returned NULL without setting an exception
generate-posix-vars failedStack Overflow 上的 该回答 提及是 GCC 版本过低(当前是 4.8.5)导致应用优化出错,要么升级 GCC,要么在配置时去掉 --enable-optimizations 参数,yum 检测 GCC 无更新,要升级或许又需要自己编译,不想多折腾,故还是选择了去掉优化参数:
./configure --with-openssl=/usr/local/openssl11sh
再次编译终于成功了。接下来运行一下测试:
make testsh
测试真的好慢,比编译还慢。最终输出:
Tests result: FAILURE then SUCCESS所以这是啥意思……成功还是不成功?注意到测试过程中确实有输出一些报错信息,例如 multiprocessing 模块的,提示 fork 出错,我寻思着也没用 sudo 运行测试,它能 fork 成功吗?所以这些问题或许也不全是编译的问题吧,不想再一个个检查了,不管了到时候运行有问题再说,直接安装吧:
sudo make installsh
一定要用 sudo 运行安装,前面的配置、编译、测试其实都没有动系统文件(所以怎么折腾都没事),而这步操作动了。
安装其实就是把编译的产物复制到系统相关目录中。其中二进制可执行文件 python3 被安装在 /usr/local/bin,并未覆盖以前使用 yum 安装的 /usr/bin/python3,即旧的 3.6。事实上自行编译的软件都是安装在 /usr/local 中,可能这是一个约定吧。而系统环境变量 PATH 中,/usr/local/bin 位于 /usr/bin 之前,所以此后在命令行执行 python3 就是新的 3.10 了。检查下版本:
[zack@vultr Python-3.10.13]$ python3 -V Python 3.10.13sh
完工!此后就可以用它来创建虚拟环境,安装新的 Django 4.2 了。
参考资料: