我的网站目前使用的 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 python3
下载 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.tgz
tar
命令的参数中,x
表示解压操作,f
表示指定压缩包的文件名。进入解压后的文件夹,配置:
./configure --enable-optimizations
--enable-optimizations
是应用优化,如果不加这个参数,在输出的末尾会提示建议添加,故先加上试试。
编译:
make
提示:
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-devel
openssl version
输出的版本号依然是旧的 1.0.2,因为 /usr/bin
里面的二进制可执行文件 openssl
依然是旧版的,看起来这个软件包并不带二进制可执行文件,就只是一些开发库,猜测是有 -devel
后缀的原因?不过由于本文涉及的内容都不需要它,也无所谓了。先清理一下编译产物:
make clean
再重新走一遍配置。
What???居然还提示 OpenSSL 版本过低。在网上搜了一通,Stack Overflow 上的 该回答 提到是因为动态链接库被安装在了 /usr/lib64
里,这不是 configure
的默认搜索路径,所以需要在配置的时候自行指定:
./configure --enable-optimizations --with-openssl=/usr --with-openssl-rpath=/usr/lib64
居然还是不行,找不到新安装的 OpenSSL。又在上述 Stack Overflow 链接中看到另一个回答,说需要先这样做:
mkdir /usr/local/openssl11
cd /usr/local/openssl11
ln -s /usr/lib64/openssl11 lib
ln -s /usr/include/openssl11 include
也就是把 OpenSSL 的动态链接库目录 /usr/lib64/openssl11
和头文件目录 /usr/include/openssl11
软链接到 /usr/local/openssl11
中,然后在配置时指定该目录为 OpenSSL 的安装目录:
./configure --enable-optimizations --with-openssl=/usr/local/openssl11
很有趣,玩了个 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 failed
Stack Overflow 上的 该回答 提及是 GCC 版本过低(当前是 4.8.5)导致应用优化出错,要么升级 GCC,要么在配置时去掉 --enable-optimizations
参数,yum
检测 GCC 无更新,要升级或许又需要自己编译,不想多折腾,故还是选择了去掉优化参数:
./configure --with-openssl=/usr/local/openssl11
再次编译终于成功了。接下来运行一下测试:
make test
测试真的好慢,比编译还慢。最终输出:
Tests result: FAILURE then SUCCESS
所以这是啥意思……成功还是不成功?注意到测试过程中确实有输出一些报错信息,例如 multiprocessing
模块的,提示 fork
出错,我寻思着也没用 sudo
运行测试,它能 fork
成功吗?所以这些问题或许也不全是编译的问题吧,不想再一个个检查了,不管了到时候运行有问题再说,直接安装吧:
sudo make install
一定要用 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.13
完工!此后就可以用它来创建虚拟环境,安装新的 Django 4.2 了。
参考资料: