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

Posted

技术标签:

【中文标题】在非标准位置构建具有 SSL 支持的 Python【英文标题】:Building Python with SSL support in non-standard location 【发布时间】:2017-04-20 03:05:53 【问题描述】:

我需要在没有 root 访问权限的 RHEL 上安装几个 Python 模块。至少其中一个模块还需要访问Python.h

在这种情况下,我发现最好的办法是在~/local 中安装 python 及其依赖项。它通常可以正常工作,但这次 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

我已经很多年没有这样做了,所以也许我忽略了一些东西。谁能帮忙解决这个问题?

提前致谢。

【问题讨论】:

相关:***.com/q/36774171/1959808 【参考方案1】:

如果 OpenSSL 不在标准位置,您需要编辑 Modules/Setup.dist 以指定 OpenSSL 的位置。来自Getting SSL Support in Python 2.5.1:

如果你发现自己在一个需要 python 支持 ssl 的 linux 机器上(到 在 httplib.HTTPSConnection 之类的东西中使用客户端或 imaplib.IMAP4_SSL),然后让我为您节省几个小时的狩猎时间 在网络上(当然,如果你发现了这个,那么这意味着 你已经完成了一些级别的狩猎!)。

您会知道是否需要编译到您的 python 中的 ssl 支持 如果您收到以下异常消息,则安装: AttributeError:“模块”对象没有属性“ssl”

为了让它消失,这样你就可以继续快乐地抛锚了 python 代码,你需要首先确保你有 OpenSSL 安装。默认情况下,它是从源安装的:/usr/local/ssl

如果该目录不存在,则获取源包。

做标准:

tar zxf openssl-0.9.8g.tar.gz
cd openssl-0.9.8g
./config
make
make install

然后获取 2.5.1 的 python 源代码和: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 ...

确保通过清理源根目录(例如make distclean)获取对Modules/Setup.dist 的更改,然后再次运行configuremake

【讨论】:

在 RHEL 上,标准位置在哪里?我已经用 yum 安装了 openssl 和 openssl-devel rpm 也适用于 python3.6 ^^ 在标准位置未安装 openssl 时无法在 python3.7 上运行 @Xiao 3.7 中可能引入了一个更改,这可能就是原因。您可能想通过bugs.python.org/issue32694 获取更多信息。 这适用于在 RHEL 上安装 Python 3.7.4。使用默认的 openssl 安装,我必须更改 SSL 行:SSL=/etc/pki/tls,取消注释接下来的三行,我必须运行 sudo yum install openssl-devel【参考方案2】:

在 Linux Red Hat 7.7 x86_64 上,在我的主目录 (/home/unix/) 中安装 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

【讨论】:

【参考方案3】:

在 Bourne shell(/bin/sh 或 /bin/bash)中:

$ LD_LIBRARY_PATH=/usr/local/lib
$ export LD_LIBRARY_PATH
$ make

在 C-shell 中(/bin/csh 或 /bin/tcsh):

% setenv LD_LIBRARY_PATH /usr/local/lib
% make

【讨论】:

这与本地安装的 OpenSSL 相结合,为我解决了问题。 这似乎只在编译时有效,稍后在没有导出的情况下运行 python 时,不再找到该库!【参考方案4】:

@PeterVanGalen has a good method,与 2021 年相关,但我不同意一些细节。

他修改Modules/Setup 文件的方法导致libssl.so 和libcrypto.so 库成为python 二进制文件本身的动态依赖项。这不是预期的——那些应该是python可导入.so的依赖项,比如_ssl.cpython-39-x86_64-linux-gnu.so

他的方法也不包括在运行时而不是构建时如何找到libssl.solibcrypto.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)

【讨论】:

我使用python 3.6.8,它显示configure: WARNING: unrecognized options: --with-openssl 这个configure 命令行选项是在 CPython 3.7 中添加的。【参考方案5】:

对我来说编辑Modules/Setup 是不够的,因为_hashlib 模块最终还是使用了错误的OpenSSL 版本;并且在我的 SLES 系统上运行时未考虑 LD_LIBRARY_PATH

有效的方法是将本地 OpenSSL 静态链接到 _ssl_hashlib,方法是按照 setup.py 编辑 GitHub patch: eddy-geek/ python_custom_openssl.diff,然后编辑 make clean &amp;&amp; make

更多关于我为什么在 Stack Overflow 上使用静态链接的详细信息Coredump when compiling python with a custom openssl version。

【讨论】:

【参考方案6】:

这是我在 Python 2.7.11 中使用的完整过程。


在*** Python2.7.11 源目录中:

    更改Modules/Setup.distModules/Setup :取消注释_ssl 部分,注释掉_socket(如果它已经被注释掉,则无操作),取消注释并适当地设置SSL(新ssl 的路径lib/includes 等。 )

    注意:Modules/Setup 文件最初不存在,但我相信在第一次运行后它会从 Modules/Setup.dist 获取内容。确保每次运行前都会在此处反映更改。

    应用补丁:http://gist.github.com/eddy-geek/9604982 (如果之前运行过 make,则 make distclean)

    ./configure --prefix=/root/.local/aks/py-ssl/python2.7 --enable-shared
    
    # modify: Makefile -> set svnversion to ""
    
    make
    
    make altinstall
    

【讨论】:

确认此方法有效,并且在第一次运行失败后不要忘记更改Modules/Setup 文件。 我取消了 Modules/Setup.dist 中的注释,然后:./configure --prefix='my build dir' --enable-shared make which failed: dyld: Symbol not found: _GENERAL_NAME_free 引用自:my_source_dir/libpython2.7.dylib 预期在:动态查找 /bin/sh:第 1 行:63299 中止陷阱:6 DYLD_LIBRARY_PATH=my_source_dir ./python.exe -E -S -m sysconfig --generate-posix- vars generate-posix-vars failed make 只有在我将 --enable-shared 包含在配置中时才会失败。相反,如果我不取消注释 Setup.dist 中的 ssl 行,则使用 --enable-shared 正确构建。【参考方案7】:

在我回到 openssl 的日志之前,我得到了相同的结果。 在那里我看到在构建 openssl 时需要使用 -fPIC: 构建“_ssl”扩展:

gcc -pthread -fPIC -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/usr/local/ssl/include -I. -IInclude -I./Include -I/usr/local/include -I/home/feramos/Python-2.7.3/Include -I/home/feramos/Python-2.7.3 -c /home/feramos/Python-2.7.3/Modules/_ssl.c -o build/temp.linux-x86_64-2.7/home/feramos/Python-2.7.3/Modules/_ssl.o
gcc -pthread -shared build/temp.linux-x86_64-2.7/home/feramos/Python-2.7.3/Modules/_ssl.o -L/usr/local/ssl/lib -L/usr/local/lib -lssl -lcrypto -o build/lib.linux-x86_64-2.7/_ssl.so
/usr/bin/ld: /usr/local/ssl/lib/libcrypto.a(x86_64cpuid.o): relocation R_X86_64_PC32 against `OPENSSL_cpuid_setup' can not be used when making a shared object; recompile with -fPIC

openssl-0.9.8g]# .config -fPIC

然后,为 openssl 制作、制作安装,然后再次构建 Python。

【讨论】:

【参考方案8】:

我为下面的 2 和 3 提供了一组静态 openssl 和静态 libintl 补丁。

对于 openssl(第一个补丁),您必须设置环境变量 OPENSSL_ROOT。

这是基于来自http://gist.github.com/eddy-geek/9604982 的补丁。

对于 Python 2.7.14:

https://gist.github.com/rkitover/2d9e5baff1f1cc4f2618dee53083bd35

https://gist.github.com/rkitover/afab7ed3ac7ce1860c43a258571c8ae1

对于 Python 3.6.3:

https://gist.github.com/rkitover/93d89a679705875c59275fb0a8f22b45

https://gist.github.com/rkitover/b18f19eafda3775a9652cc9cdf3ec914

【讨论】:

是否需要分别针对 2.7 和 3.6 的第二个补丁进行 iconv 检查? 我使用的第二个补丁,因为我使用的是静态gettext,你可能不需要这个。【参考方案9】:

我正在构建 Python2.7.13,我看到了同样的问题。对于 2.7.13,您必须使用“openssl1.0.0e”或更高版本才能使其工作。我尝试了openssl-0.9.8g,但它不起作用。 不知何故,我不能仅仅修改 Modules/Setup.dist 就让它工作,所以我必须手动编译那个 _ssl.o。 我猜这是因为我提供的 openssl-0.9.8g 不起作用,它搜索了系统默认的 libssl.so.10 也不起作用。

【讨论】:

只是添加一件事,编辑 Modules/Setup.dist 对我不起作用。我必须编辑模块/设置以使其工作【参考方案10】:

对于 MAC OS HIGH Sierra, 和 Python-3.5.6 在上面的答案中,openssl 安装是使用源代码完成的,但是如果你使用 brew 安装它会告诉你安装的包在哪里,所以如果你使用 brew 安装 openssl

brew install openssl

这将在 /usr/local/Cellar/openssl/1.0.2o_2/ 安装 openssl,此路径需要在 Modules/Setup.dist 中更新

Follow this answer which is mentioned above where the location of openssl installation is not mentioned to update the Modules/Setup.dist

在上述行中将 SSL 值更新为

SSL=/usr/local/Cellar/openssl/1.0.2o_2/

并取消注释行, 做一个 CMM,你的 python 会用 openssl 编译。

【讨论】:

这与***.com/a/5939170/1797006 的区别不足以使其成为单独的答案。 @KarlRichter... 我试图通过使用 brew 使其更简单,因为 brew 告诉安装位置,这是我单独编写它的唯一原因。我已经更新了答案,因为它与提到的答案重叠。【参考方案11】:

尝试将-Wl,-rpath,/home/fds/rms/local/lib 添加到LDPATH

【讨论】:

感谢 par,但 make 会忽略所有内容,只在“标准”位置寻找库。 -Wl,, 之后的所有内容传递给编译器驱动程序调用的链接器可执行文件,以指定链接器正在创建的二进制文件静态应该在哪里查找运行时库。运行时选项不会帮助解决构建时问题。见gcc.gnu.org/onlinedocs/gcc-3.4.2/gcc/Link-Options.html

以上是关于在非标准位置构建具有 SSL 支持的 Python的主要内容,如果未能解决你的问题,请参考以下文章

如何在非标准位置构建 Armadillo C++ lib 以静态链接到 OpenBLAS

构建 TensorFlow:bazel 在非标准目录中找不到 libstdc++

用于构建具有 SSL 支持的 uWSGI 的 Dockerfile

在具有 OpenSSL 支持的 Windows 上构建 PyQt5?

如何使用自定义 OpenSSL 编译 Python 3.4?

如何在非阻塞套接字上处理 OpenSSL SSL_ERROR_WANT_READ / WANT_WRITE