CentOS7 源码编译安装 Python 3.8.10,开启 SSL 功能
背景
CentOS7 自带的 Python3,或者通过 yum 安装的 Python3,可能会有无法使用 ssl 的问题:
$ python3
Python 3.8.10 (default, Jun 13 2023, 14:51:15)
[GCC 11.2.1 20220127 (Red Hat 11.2.1-9)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/python3/python3.8.10/lib/python3.8/ssl.py", line 100, in <module>
from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION
ImportError: cannot import name 'OPENSSL_VERSION_NUMBER' from '_ssl' (unknown location)
>>>
而使用 pip3 安装依赖项,需要用到 ssl;所以我们需要源码编译 Python3,并开启 ssl 功能。
源码编译安装 openssl
下载 openssl 源码
登录 https://www.openssl.org/source/ 下载最合适版本的 openssl。
首先尝试使用 https://www.openssl.org/source/openssl-3.1.1.tar.gz,然后源码编译 Python-3.8.10时,报出如下问题:
......
Python build finished successfully!
......
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
......
如上信息提示我们,需要使用 openssl 1.0.2 或 1.1 版本。于是重新安装 https://www.openssl.org/source/openssl-1.1.1u.tar.gz :
$ cd /usr/local/src
$ wget https://www.openssl.org/source/openssl-1.1.1u.tar.gz
$ tar zxvf openssl-1.1.1u.tar.gz
$ cd openssl-1.1.1u
$ ./config --prefix=/usr/local/openssl/openssl1.1.1
$ make
$ sudo make install
至此,openssl就被安装到了 /usr/local/openssl/openssl1.1.1:
$ ll /usr/local/openssl/openssl1.1.1
total 0
drwxr-xr-x 2 root root 37 Jun 13 16:36 bin
drwxr-xr-x 3 root root 21 Jun 13 16:36 include
drwxr-xr-x 4 root root 159 Jun 13 16:36 lib
drwxr-xr-x 4 root root 28 Jun 13 16:37 share
drwxr-xr-x 5 root root 140 Jun 13 16:36 ssl
将 openssl 的 lib 添加到动态链接库
查看动态链接库文件配置
$ cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
$ cd /etc/ld.so.conf.d
$ ls
bind-export-x86_64.conf kernel-3.10.0-1160.el7.x86_64.conf mariadb-x86_64.conf
dyninst-x86_64.conf libiscsi-x86_64.conf qt-x86_64.conf
kernel-3.10.0-1160.88.1.el7.x86_64.conf
$ cat mariadb-x86_64.conf
/usr/lib64/mysql
如上,可以看到,所谓添加动态链接库,就是在 /etc/ld.so.conf.d 目录中创建一个 .conf 文件,其中填写 lib.so 文件所在的目录即可。
上一步将 openssl 安装到了 /usr/local/openssl/openssl1.1.1,可以看到其中的 lib目录包含了相关的 lib*.so 文件:
$ ll /usr/local/openssl/openssl1.1.1/lib/
total 10440
drwxr-xr-x 2 root root 39 Jun 13 16:36 engines-1.1
-rw-r--r-- 1 root root 5603958 Jun 13 16:36 libcrypto.a
lrwxrwxrwx 1 root root 16 Jun 13 16:36 libcrypto.so -> libcrypto.so.1.1
-rwxr-xr-x 1 root root 3362560 Jun 13 16:36 libcrypto.so.1.1
-rw-r--r-- 1 root root 1027122 Jun 13 16:36 libssl.a
lrwxrwxrwx 1 root root 13 Jun 13 16:36 libssl.so -> libssl.so.1.1
-rwxr-xr-x 1 root root 689720 Jun 13 16:36 libssl.so.1.1
drwxr-xr-x 2 root root 61 Jun 13 16:36 pkgconfig
创建动态链接库配置
那么在 /etc/ld.so.conf.d 中创建 openssl-1.1.1.conf 文件,并填写 /usr/local/openssl/openssl1.1.1/lib 即可:
$ cat /etc/ld.so.conf.d/openssl-1.1.1.conf
/usr/local/openssl/openssl1.1.1/lib
重新加载动态链接库
# 需要 root 权限
$ sudo ldconfig
配置 openssl 环境变量
$ sudo vim /etc/bashrc:
# 添加如下内容
OPENSSL_VERSION=1.1.1
OPENSSL_PATH=/usr/local/openssl
OPENSSL_BIN=${OPENSSL_PATH}/openssl${OPENSSL_VERSION}/bin
export PATH=${OPENSSL_BIN}:${PATH}
$ source /etc/bashrc
查看安装结果
$ openssl version
OpenSSL 1.1.1u 30 May 2023
至此,openssl 相关环境就完全配置完毕了。
源码编译安装 python3.8.10
下载 python3.8.10 源码
$ cd /usr/local/src
$ wget https://www.python.org/ftp/python/3.8.10/Python-3.8.10.tgz
$ tar zxvf Python-3.8.10.tgz
$ cd Python-3.8.10
编辑 Modules/Setup
编辑 /usr/local/src/Python-3.8.10/Modules/Setup
,
将 SSL=/usr/local/openssl
处的注释解除,并修改SSL为刚才安装的 openssl 路径
$ vim Modules/Setup
# 编辑后的内容如下:
SSL=/usr/local/openssl/openssl1.1.1
_ssl _ssl.c \
-DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
-L$(SSL)/lib -lssl -lcrypto
配置 Python3.8.10
在 /usr/local/src/Python-3.8.10
目录下执行如下命令进行配置;
--prefix
参数用于指定后续的 make install 命令会将 Python 安装到哪个目录;
--with-openssl
参数用于指定编译出来的 Python 开启 ssl 功能,并指定 openssl 相关库文件的位置。
$ ./configure --prefix=/usr/local/python3/python3.8.10 --with-openssl=/usr/local/openssl/openssl1.1.1
......
checking for openssl/ssl.h in /usr/local/openssl/openssl1.1.1... yes
checking whether compiling and linking against OpenSSL works... yes
checking for X509_VERIFY_PARAM_set1_host in libssl... yes
checking for --with-ssl-default-suites... python
......
编译 Python3.8.10
$ make
......
The following modules found by detect_modules() in setup.py, have been
built by the Makefile instead, as configured by the Setup files:
_abc _ssl atexit
pwd time
running build_scripts
creating build/scripts-3.8
copying and adjusting /usr/local/src/python_src/Python-3.8.10/Tools/scripts/pydoc3 -> build/scripts-3.8
copying and adjusting /usr/local/src/python_src/Python-3.8.10/Tools/scripts/idle3 -> build/scripts-3.8
copying and adjusting /usr/local/src/python_src/Python-3.8.10/Tools/scripts/2to3 -> build/scripts-3.8
changing mode of build/scripts-3.8/pydoc3 from 664 to 775
changing mode of build/scripts-3.8/idle3 from 664 to 775
changing mode of build/scripts-3.8/2to3 from 664 to 775
renaming build/scripts-3.8/pydoc3 to build/scripts-3.8/pydoc3.8
renaming build/scripts-3.8/idle3 to build/scripts-3.8/idle3.8
renaming build/scripts-3.8/2to3 to build/scripts-3.8/2to3-3.8
/usr/bin/install -c -m 644 ./Tools/gdb/libpython.py python-gdb.py
gcc -pthread -c -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -std=c99 -Wextra -Wno-unused-result -Wno-unused-parameter -Wno-missing-field-initializers -Werror=implicit-function-declaration -I./Include/internal -I. -I./Include -DPy_BUILD_CORE -o Programs/_testembed.o ./Programs/_testembed.c
gcc -pthread -Xlinker -export-dynamic -o Programs/_testembed Programs/_testembed.o libpython3.8.a -lcrypt -lpthread -ldl -lutil -lm -L/usr/local/openssl/openssl1.1.1/lib -lssl -lcrypto -lm
sed -e "s,@EXENAME@,/usr/local/python3/python3.8.10/bin/python3.8," < ./Misc/python-config.in >python-config.py
LC_ALL=C sed -e 's,\$(\([A-Za-z0-9_]*\)),\$\{\1\},g' < Misc/python-config.sh >python-config
安装
$ sudo make install
......
(cd /usr/local/python3/python3.8.10/bin; ln -s 2to3-3.8 2to3)
if test "x" != "x" ; then \
rm -f /usr/local/python3/python3.8.10/bin/python3-32; \
(cd /usr/local/python3/python3.8.10/bin; ln -s python3.8-32 python3-32) \
fi
if test "x" != "x" ; then \
rm -f /usr/local/python3/python3.8.10/bin/python3-intel64; \
(cd /usr/local/python3/python3.8.10/bin; ln -s python3.8-intel64 python3-intel64) \
fi
rm -f /usr/local/python3/python3.8.10/share/man/man1/python3.1
(cd /usr/local/python3/python3.8.10/share/man/man1; ln -s python3.8.1 python3.1)
if test "xupgrade" != "xno" ; then \
case upgrade in \
upgrade) ensurepip="--upgrade" ;; \
install|*) ensurepip="" ;; \
esac; \
./python -E -m ensurepip \
$ensurepip --root=/ ; \
fi
Looking in links: /tmp/tmpmsb395gk
Processing /tmp/tmpmsb395gk/setuptools-56.0.0-py3-none-any.whl
Processing /tmp/tmpmsb395gk/pip-21.1.1-py3-none-any.whl
Installing collected packages: setuptools, pip
Successfully installed pip-21.1.1 setuptools-56.0.0
WARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv
配置 Python 环境变量
$ sudo vim /etc/bashrc
PY_VERSION=3.8.10
PY_PATH=/usr/local/python3
PY_BIN=${PY_PATH}/python${PY_VERSION}/bin
export PATH=${PY_BIN}:${PATH}
$ source /etc/bashrc
查看安装结果
$ python3
Python 3.8.10 (default, Jun 13 2023, 19:28:11)
[GCC 11.2.1 20220127 (Red Hat 11.2.1-9)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
>>>
2023.06.14 Wed 14:24