在非标准位置构建支持SSL的Python
我需要在一个没有管理员权限的RHEL系统上安装几个Python模块。其中至少有一个模块需要用到Python.h
这个文件。
在这种情况下,我发现最好的办法是把Python和它的依赖项安装到~/local
目录下。通常这样做是没问题的,但这次Python在构建SSL模块时失败了(具体情况见下文)。下面是我所做的步骤。
我下载了Python 6的源代码,然后开始了:
./configure --prefix=/home/fds/rms/local
make >& make.log
查看日志后发现,ssl模块没有被编译,但没有说明原因(在make或configure中没有其他关于ssl的记录):
Failed to find the necessary bits to build these modules:
_bsddb _curses _curses_panel
_hashlib _sqlite3 _ssl <----------
所以我猜,Python根本找不到任何ssl库(这很奇怪,不过没关系...)。于是我下载了openssl-0.9.8r,然后
./config --prefix=/home/fds/rms/local shared
make
make install
回到Python,我又运行了./configure和make。结果失败了,但这次情况有所不同:
Failed to build these modules:
_hashlib _ssl
仔细查看日志文件后发现了这个:
gcc -pthread -shared build/temp.linux-x86_64-2.6/home/fds/rms/installers/Python-2.6.6/Modules/_ssl.o -L/home/fds/rms/local/lib -L/usr/local/lib -lssl -lcrypto -o build/lib.linux-x86_64-2.6/_ssl.so
*** WARNING: renaming "_ssl" since importing it failed: libssl.so.0.9.8: cannot open shared object file: No such file or directory
现在它找到了库,但似乎没有完全正确(文件在应该在的位置):
$ find /home/fds/rms/local -iname libssl.so.0.9.8
/home/fds/rms/local/lib/libssl.so.0.9.8
接下来我想追踪一下make,看它在找哪个文件:
$ strace -f make 2>&1 | grep libssl.so.0.9.8
[pid 5584] open("/lib/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/usr/lib/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/lib64/tls/x86_64/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/lib64/tls/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/lib64/x86_64/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/lib64/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/usr/lib64/tls/x86_64/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/usr/lib64/tls/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/usr/lib64/x86_64/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/usr/lib64/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] write(1, "*** WARNING: renaming \"_ssl\" sin"..., 131*** WARNING: renaming "_ssl" since importing it failed: libssl.so.0.9.8: cannot open shared object file: No such file or directory
[pid 5584] open("/lib/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/usr/lib/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/lib64/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/usr/lib64/tls/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] open("/usr/lib64/libssl.so.0.9.8", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid 5584] write(1, "*** WARNING: renaming \"_hashlib\""..., 135*** WARNING: renaming "_hashlib" since importing it failed: libssl.so.0.9.8: cannot open shared object file: No such file or directory
嗯,它在找错地方。我试着给它一些提示:
CPPFLAGS="-I/home/fds/rms/local/include -I/home/fds/rms/local/include/openssl" LDFLAGS="-L/home/fds/rms/local/lib" ./configure --prefix=/home/fds/rms/local
但没有任何变化,make
似乎根本没有尝试去/home/fds/rms/local/lib
这个地方。
我已经很多年没做这个了,可能是我忽略了什么。有没有人能帮我解决这个问题?
12 个回答
在Linux Red Hat 7.7 x86_64系统上,我在自己的家目录(/home/unix/vangalen)成功安装了openssl-1.1.1d和Python-3.8.1,下面是具体步骤:
安装OpenSSL
你可以参考这两个链接来获取更多信息:source1 和 source2
cd ~
wget https://www.openssl.org/source/openssl-1.1.1d.tar.gz
tar -xzf openssl-1.1.1d.tar.gz
cd /home/unix/vangalen/openssl-1.1.1d
./config --prefix=/home/unix/vangalen/openssl --openssldir=/home/unix/vangalen/openssl
make
make test
make install
安装Python
同样可以参考这几个链接:source2、source3 和 source4
cd ~
wget https://www.python.org/ftp/python/3.8.1/Python-3.8.1.tgz
tar xf Python-3.8.1.tgz
接下来,你需要用文本编辑器修改Python-3.8.1/Modules/Setup文件。如果这个文件不存在,你可能需要先尝试运行一次,虽然会失败。然后,取消注释(去掉#号)并调整第206到213行中SSL的别名:
_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=/home/unix/vangalen/openssl _ssl _ssl.c \ -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ -L$(SSL)/lib -lssl -lcrypto
cd ~/Python-3.8.1
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/home/unix/vangalen/openssl/lib
./configure --prefix=/home/unix/vangalen/py-381 --with-openssl=/home/unix/vangalen/openssl
make
make test
make install
@PeterVanGalen 有一个不错的方法,在2021年时也很相关,但我对一些细节有不同的看法。
他修改 Modules/Setup
文件的方法会导致 libssl.so 和 libcrypto.so 这两个库变成 python 程序本身的动态依赖。这并不是我们想要的——它们应该是 python 可导入的 .so
文件的依赖,比如 _ssl.cpython-39-x86_64-linux-gnu.so
。
他的做法也没有解决 libssl.so 和 libcrypto.so 在运行时如何被找到的问题,而不是在构建时。这一点很重要,特别是当它们放在一些不寻常的自定义路径下时,否则 python 可能根本无法运行,或者无法 import ssl
。你可以用很多方法来解决这个问题(比如 LD_LIBRARY_PATH
和 ld.so.conf
),但我选择使用 rpath,这样在使用这个 python 时,.so
文件总能在它们的自定义位置被找到,而不会影响其他东西。
这是我对 @PeterValGalen 方法的修改:
# First we need openssl installed in a custom location...
tar zxf openssl-1.1.1j.tar.gz
cd openssl-1.1.1j
./config --prefix=/my/weird/path --openssldir=/my/weird/path/ssl
make
make install # Add `sudo` if needed for permission to /my/weird/path.
cd ..
# Now the python part...
wget https://www.python.org/ftp/python/3.9.2/Python-3.9.2.tgz
tar xf Python-3.9.2.tgz
cd Python-3.9.2
LDFLAGS="${LDFLAGS} -Wl,-rpath=/my/weird/path/lib" ./configure --with-openssl=/my/weird/path
make
make install # Add `sudo` if needed for permissions.
这样做的话,openssl 库就不是 python 程序的依赖,而是 _ssl*.so
的依赖。
$ ldd ./python | grep weird
# [Nothing]
$ ldd build/lib.linux-x86_64-3.9/_ssl.cpython-39-x86_64-linux-gnu.so | grep weird
libssl.so.1.1 => /my/weird/path/lib/libssl.so.1.1 (0x00007f733ee73000)
libcrypto.so.1.1 => /my/weird/path/lib/libcrypto.so.1.1 (0x00007f733e9ab000)
而且它能正常工作:
$ ./python -c "import ssl; print('yay')"
yay
$ ./python Lib/test/test_ssl.py
# ... lots of good stuff...
OK (skipped=10)
如果你的 OpenSSL 没有安装在标准位置,你需要编辑 Modules/Setup.dist
文件来指定它的位置。来自 在 Python 2.5.1 中获取 SSL 支持 的内容:
如果你在 Linux 系统上需要在 Python 中使用 SSL 支持(比如在 httplib.HTTPSConnection 或 imaplib.IMAP4_SSL 中使用客户端),那么我可以帮你节省几个小时的网上搜索时间(当然,如果你找到了这个,那说明你已经做了一些搜索了!)。
你可以通过以下错误信息来判断是否需要在 Python 安装中编译 SSL 支持: AttributeError: 'module' object has no attribute 'ssl'
为了消除这个错误,让你可以继续愉快地写 Python 代码,你需要先确保你已经安装了 OpenSSL。默认情况下,它会安装在这个路径:/usr/local/ssl
如果这个目录不存在,那就去下载源代码包。
接下来,按照标准步骤操作:
tar zxf openssl-0.9.8g.tar.gz cd openssl-0.9.8g ./config make make install
然后下载 Python 2.5.1 的源代码并执行:tar zxf Python-2.5.1.tgz && cd Python-2.5.1
接下来,你需要编辑 Modules/Setup.dist 文件:
204:# Socket module helper for SSL support; you must comment out the other 205:# socket line above, and possibly edit the SSL variable: 206:SSL=/usr/local/ssl 207:_ssl _ssl.c \ 208: -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ 209: -L$(SSL)/lib -lssl -lcrypto
如果你把 OpenSSL 安装在默认位置,只需取消注释第 206 到 209 行,然后:
./configure make make install
最后用以下命令验证你的安装:
python /usr/local/lib/python2.5/test/test_socket_ssl.py test_rude_shutdown ... test_basic ... test_timeout ...
确保对 Modules/Setup.dist
的更改被应用,可以通过清理源代码根目录(例如 make distclean
)来实现,然后再次运行 configure
和 make
。