在非标准位置构建支持SSL的Python

93 投票
12 回答
150497 浏览
提问于 2025-04-16 17:17

我需要在一个没有管理员权限的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 个回答

24

在Linux Red Hat 7.7 x86_64系统上,我在自己的家目录(/home/unix/vangalen)成功安装了openssl-1.1.1dPython-3.8.1,下面是具体步骤:

安装OpenSSL

你可以参考这两个链接来获取更多信息:source1source2

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

同样可以参考这几个链接:source2source3source4

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
32

@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_PATHld.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)
74

如果你的 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)来实现,然后再次运行 configuremake

撰写回答