最近工作中需要用到最新的Python3.7版在本地安装一切顺利,到准备在测试环境安装就发现了问题。装好python虚拟环境后,运行程序,发现报错。好像是与模块缺失相关。
1
2
3
4
>>> import _ssl
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ImportError: No module named _ssl
Round 1
虽然不清楚_ssl对应的是什么模块,但是感觉应该是和openssl有关系。搜索了一番,发现原来Python3.7默认的configuration里面把ssl相关的编译给注销了,需要手工取消注释。那么就重新编译吧。那么就先修改配置文件。 在python源代码目录的 Modules/Setup.dist文件里修改。 注意socket和ssl两部分都要取消注释!
1
2
3
4
5
6
7
8
9
# Socket module helper for socket(2)
_socket socketmodule.c
# Socket module helper for SSL support; you must comment out the other
# socket line above, and possibly edit the SSL variable:
SSL=/usr/local/openssl # 默认路径, 如果手动安装到别的路径, 这里需要改
_ssl _ssl.c \
-DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
-L$(SSL)/lib -lssl -lcrypto
修改后重新编译
1
make clean && ./configurate && make && make install
但是又有新的报错:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
./Modules/_ssl.c:73:6: error: #error "libssl is too old and does not support X509_VERIFY_PARAM_set1_host()"
./Modules/_ssl.c: In function ‘_ssl_configure_hostname’:
./Modules/_ssl.c:853: error: implicit declaration of function ‘SSL_get0_param’
./Modules/_ssl.c:853: warning: initialization makes pointer from integer without a cast
./Modules/_ssl.c:855: error: implicit declaration of function ‘X509_VERIFY_PARAM_set1_host’
./Modules/_ssl.c:861: error: implicit declaration of function ‘X509_VERIFY_PARAM_set1_ip’
./Modules/_ssl.c: In function ‘_ssl__SSLContext_impl’:
./Modules/_ssl.c:2947: error: ‘X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS’ undeclared (first use in this function)
./Modules/_ssl.c:2947: error: (Each undeclared identifier is reported only once
./Modules/_ssl.c:2947: error: for each function it appears in.)
./Modules/_ssl.c:3052: error: implicit declaration of function ‘SSL_CTX_get0_param’
./Modules/_ssl.c:3052: warning: assignment makes pointer from integer without a cast
./Modules/_ssl.c:3058: error: implicit declaration of function ‘X509_VERIFY_PARAM_set_hostflags’
./Modules/_ssl.c: In function ‘get_verify_flags’:
./Modules/_ssl.c:3348: warning: assignment makes pointer from integer without a cast
./Modules/_ssl.c: In function ‘set_verify_flags’:
./Modules/_ssl.c:3361: warning: assignment makes pointer from integer without a cast
./Modules/_ssl.c: In function ‘set_host_flags’:
./Modules/_ssl.c:3524: warning: assignment makes pointer from integer without a cast
make: *** [Modules/_ssl.o] Error 1
Round2
从报错第一行来看,是SSL版本太旧了,于是从官网下载最新的openssl进行默认安装:
1
2
3
4
wget -c http://www.openssl.org/source/openssl-1.0.2r.tar.gz
make
make test
make install
安装完之后重新编译Python3.7,问题还是没有解决,依然是提示”libssl is too old”
Round3
从网上检索相关信息,看来应该还需要将openssl编译成动态连接库,并替换系统默认库,才可以生效。于是继续进行操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 编译安装生成动态库
./config shared zlib-dynamic --prefix=/usr/local/openssl
make && make install
# 备份旧的版本
mv /usr/bin/openssl /usr/bin/openssl.old
mv /usr/include/openssl /usr/include/openssl.old
# 为新的版本建立软链
ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl
ln -s /usr/local/ssl/include/openssl /usr/include/openssl
# 建立软链(因为 /usr/local/lib64/ 读取优先级高于 /usr/lib64/)
ln -s /usr/local/ssl/lib/libssl.so /usr/local/lib64/libssl.so
# 增加依赖的动态库
ln -s /usr/local/openssl/lib/libssl.so.1.1 /usr/lib64/libssl.so.1.1
ln -s /usr/local/openssl/lib/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1
# 备份旧的库
mv /usr/lib64/libssl.so /usr/lib64/libssl.so.old
ln -s /usr/local/ssl/lib/libssl.so /usr/lib64/libssl.so
检查一下新版本是否生效
1
2
openssl version
OpenSSL 1.0.2r 26 Feb 2019
新版本openssl生效之后,再重新编译python前修改Python安装目录的Module/Setup文件:
1
2
3
4
#SSL=/usr/local/ssl
#_ssl _ssl.c \
# -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
# -L$(SSL)/lib -lssl -lcrypto
Round4
再次make编译之后,发现新的提示:
1
2
3
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
大意是说LibreSSL版本也是太老了,二话不说,再次更新。
1
2
3
4
wget -c wget https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.9.1.tar.gz
tar -xvf libressl-2.9.1.tar.gz
cd libressl-2.9.1
./configure && make && make install
再验证LibreSSL,确认已经更新到了目标版本:
1
2
#openssl version
LibreSSL 2.9.1
再次尝试编译,发现问题依然在。而且通过查询,发现LibreSSL只是OpenSSL的一个分支!因此OpenSSL如果装好的话,就不用装LibreSSL。
最终重新网上介绍的方法,配置LD_LIBRARY_PATH
1
2
export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64
sudo ldconfig
按照Round3的步骤,重新配置了环境变量和软链接,确认都替换到了openssl相关的库到最新,再尝试编译,问题解决。
Python 安装前的系统准备
1
2
yum update
yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel libffi-devel gcc make
Python virtualenv pip自定义镜像源
默认的python pip比较慢,可以通过在pip.conf自定义镜像源。默认的pip.conf在
1
~/.pip/pip.conf
但是在virtualenv环境,就可以放在虚拟环境根目录下即可。
1
venv/pip.conf
国内较快的镜像使用阿里就可以了
1
2
3
4
5
[global]
index-url = https://mirrors.aliyun.com/pypi/simple/
[install]
trusted-host=mirrors.aliyun.com
如果还想再快一点,可以将上面的https换成http就会更快一点,但是https会更安全。
1
2
3
4
5
[global]
index-url = http://mirrors.aliyun.com/pypi/simple/
[install]
trusted-host=mirrors.aliyun.com