链接错误 疯狂 Python lua.require('socket') -> 未定义符号: lua_getmetatable
我有一个用Python写的项目,它需要一些Lua文件,其中一个文件需要用到'socket'。当我尝试从Python 2.7加载这个Lua文件时,出现了一个错误,提示“加载socket.core时出现未定义的符号:lua_getmetatable”。
简单的重现步骤:
$ python
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:13:53)
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import lua
>>> lua.require('socket')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: error: error loading module 'socket.core' from file
'/usr/lib/lua/5.1/socket/core.so':
/usr/lib/lua/5.1/socket/core.so: undefined symbol: lua_getmetatable
我使用的是一个最近的Lunatic Python分支,在这个版本中我清理了Py_ssize_t的警告,并且在Ubuntu 11.04上使用liblua5.1-socket2。
如果我使用主版本的lunatic-python源代码,或者升级到luasocket 2.0.2,我也会遇到同样的错误。
编辑:是什么导致了这个错误,我该如何修复它?
编辑 #2:这是构建luasocket-2.0.2的输出。默认的make没有构建unix.so,我修改了它以便也构建这个文件,这样我就不会把2.0.0和2.0.2混在一起了:
$ make
cd src; make all
make[1]: Entering directory `/sandbox/luasocket/luasocket-2.0.2/src'
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o luasocket.o luasocket.c
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o timeout.o timeout.c
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o buffer.o buffer.c
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o io.o io.c
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o auxiliar.o auxiliar.c
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o options.o options.c
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o inet.o inet.c
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o tcp.o tcp.c
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o udp.o udp.c
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o except.o except.c
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o select.o select.c
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o usocket.o usocket.c
gcc -O -shared -fpic -o socket.so.2.0.2 luasocket.o timeout.o buffer.o io.o auxiliar.o options.o inet.o tcp.o udp.o except.o select.o usocket.o
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o mime.o mime.c
gcc -O -shared -fpic -o mime.so.1.0.2 mime.o
gcc -I/usr/include/lua5.1 -DLUASOCKET_DEBUG -pedantic -Wall -O2 -fpic -llua -c -o unix.o unix.c
gcc -O -shared -fpic -o unix.so buffer.o auxiliar.o options.o timeout.o io.o usocket.o unix.o
make[1]: Leaving directory `/sandbox/luasocket/luasocket-2.0.2/src'
1 个回答
问题不在于 luasocket
,而是在共享库中符号的处理方式。
具体来说,问题在于虽然 lua.so
(Python模块)链接了 liblua5.1.so
,但是通过 require
加载的共享模块却无法访问 liblua5.1.so
中的符号。在 Mac OS X 上,这个问题不存在,因为 dlopen
加载的符号默认是以 RTLD_GLOBAL
的方式加载的。
我尝试修改 Lua 的源代码(lua-5.1.4/src/loadlib.c:69
),但这并没有帮助,因为在从 lua.so
调用 require
时,liblua5.1.so
中的符号已经被本地加载到 lua.so
里了。这就是为什么 luasocket
不能看到这些符号的原因。
幸运的是,Python 允许你通过 sys
模块来改变 dlopen
的行为。这让你可以强制以 RTLD_GLOBAL
的方式加载模块,这正是我们需要的。试试运行以下代码,看看是否能解决你的问题:
$ python
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:13:53)
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys, DLFCN
>>> sys.setdlopenflags(DLFCN.RTLD_NOW | DLFCN.RTLD_GLOBAL)
>>> import lua
>>> lua.require("socket")
<Lua table at 0x22ccef0>