Python 多版本共存导致动态库混乱的问题

在已经存在 Python 的环境中再源码安装其他版本的 Python 时,或源码安装 mod_python 或 mod_wsgi 等模块时,经常会出现动态库混乱的问题。常见的错误信息如下:

/usr/bin/ld: .../lib/libpython2.7.a(abstract.o): relocation R_X86_64_32 against 'a local symbol' can not be used when making a shared object; recompile with -fPIC
.../lib/libpython2.7.a: could not read symbols: Bad value
collect2: ld returned 1 exit status

乍一看,错误信息非常明白,就是无法生成动态库,需要使用 -fPIC 参数来重新编译 Python。其实,就是把 Python 编译成动态库。有这么几种方法:

  • 直接修改Makefile:使用原来的 ./configure 参数生成 Makefile 后,打开并在 gcc 命令后面添加 -fPIC 参数。
  • ./configure 参数中设置 CFLAGS 变量:在原来的 ./configure 参数后面追加 CFLAGS=-fPIC
  • ./configure 参数中使用 --enable-shared在原来的 ./configure 参数后面追加 --enable-shared

其中,最后一种方法是网上最推荐的。

但令人沮丧的是,在 make 的时候问题依在。我们明明看到每条 gcc 命令后面都跟了 -fPIC 参数。继续在网络上搜索会找到如下几个原因:

  • 系统不支持位置相关代码(position-dependent code)(参见)。
  • 在64位系统上使用了32位的Python库。也就是你的Python被编译成了32位的。(参见)
  • 你的Python库没有被放置到正确的位置,或者系统找不到你的Python库。(参见)
  • 系统使用了错误的Python库。这就是多版本Python共存的典型问题。(参见)

对上面的第一种情况我们不做讨论。

对第二种情况,你可以使用file命令查看一下你的Python到底被编译成了64位还是32位,如下:

$ file python
python: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), for GNU/Linux 2.6.8, dynamically linked (uses shared libs), not stripped

对于第三种情况,你可以通过在 ./configure 参数中设置 LDFLAGS 变量,或在 make 前设置 LD_LIBRARY_PATH 环境变量来指明你要使用的 Python 库的路径。如下:

$ ./configure --prefix=/bla/bla LDFLAGS=-L/path/to/your/python/lib

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

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

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

% setenv LD_LIBRARY_PATH /usr/local/lib
% make

下面是我遇到的第四种情况。上面给出的参见链接中,有人通过对比是否使用 --enable-shared 参数,以及是否使用 --prefix 参数,./configure 的输出和 make 的输出,对该问题进行了仔细的研究。他发现,在使用 --prefix 参数后,编译命令中依然添加了系统中已经存在的 python 的 include 和 lib 路径。从而导致编译 Python 的附带模块时,链接的不是新生成的 Python 库,而是原来的系统中已经存在的 Python 库,而它恰巧并没有使用 --enable-shared-fPIC 进行编译。

解决的办法就是,把系统原有的 Python 库的路径从编译参数中除去,或者把新的 Python 库所在的路径放到前面,让链接器先搜索该路径。对于 Python 自带的那些模块,这个路径应该就是当前路径 . 。可以通过设置 LDFLAGS 解决,如下:

$ ./configure --prefix=/bla/bla LDFLAGS=-L.

对于 mod_python 或 mod_wsgi 等模块可以使用 --with-python 解决,如下:

$ ./configure --prefix=/bla/bla --with-python=/path/to/your/python
Creative Commons License Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 4.0 International license .