Python 多版本共存导致动态库混乱的问题
On 2011-11-21 00:48:00 By SoliPython 多版本共存导致动态库混乱的问题
在已经存在 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