(更新3 包含我想要获得答案的问题。更新2 是指我尝试理解并解决此问题的更正)
我正在尝试使用Python扩展模块来包装C库(在这种情况下,它只是书Python Cookbook(3er edition)中描述的一个例子。问题是我遇到了经典错误
ImportError: dynamic module does not define init function (initsample)
当我尝试导入模块时。
这本书本身有以下评论:
对于后面的所有配方,假设前面的代码在名为的文件中找到 sample.c,这些定义可以在名为sample.h的文件中找到,并且它已经是 堆积到库libsample中,可以链接到其他C代码。确切的细节 编译和链接因系统而异,但这不是主要关注点。 假设您使用C代码,那么您已经想到了这一点。
我认为我错了。这就是我正在做的事情:首先,我有以下文件:
➜ Sample ls
csample.pxd sample.c sample.h sample.pyx setup.py
文件内容符合this github repository,其中包含书中描述的文件。假设一切都正确复制。然后我编译sample.c
➜ Sample gcc -c -fPIC -I/path/to/python2.7 sample.c
这会创建sample.o
,然后我继续创建一个共享库:
➜ Sample gcc -shared sample.o -o libsample.so
创建libsample.so
并最终运行setup.py
文件:
➜ Sample python setup.py build_ext --inplace
running build_ext
skipping 'sample.c' Cython extension (up-to-date)
building 'sample' extension
creating build
creating build/temp.linux-x86_64-2.7
gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/path/to/include/python2.7 -c sample.c -o build/temp.linux-x86_64-2.7/sample.o
gcc -pthread -shared build/temp.linux-x86_64-2.7/sample.o -L. -L/path/to/lib -lsample -lpython2.7 -o /path/to/sample.so
但是,我得到了同样的错误。我错过了什么?
这是我的setup.py
(最终,我复制了一个部分来清理以前的版本):
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import sys
import os
import shutil
# clean previous build
for root, dirs, files in os.walk(".", topdown=False):
for name in files:
if (name.startswith("sample") and not(name.endswith(".pyx") or name.endswith(".pxd") or name.endswith(".h"))):
os.remove(os.path.join(root, name))
for name in dirs:
if (name == "build"):
shutil.rmtree(name)
ext_modules = [
Extension('sample',
['sample.pyx'],
libraries=['sample'],
library_dirs=['.'])]
setup(
name = 'Sample extension module',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
更新2
我想知道运行后是否正常
python setup.py build_ext --inplace
文件sample.c
被替换为cythonized版本。
我假设正在运行setup.py
正在使用cython sample.c
,但我问这是因为昨天我错误地编译了cythonized版本sample.c
(删除libsample.so
后,{{1} },sample.o
在之前的运行中创建的)并且在更新sample.so
之后,我收到了此错误:
sample.pyx
在此之后,我将>>> import sample
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: ./sample.so: undefined symbol: divide
恢复为原始content,删除了之前版本中的所有剩余文件(包括临时文件),而且至关重要的是,我必须以某种方式更改sample.c
(例如,添加一个空行。)
我注意到我必须这样做以避免
sample.pyx
错误。然后我像往常一样继续前进:
ImportError: dynamic module does not define init function (initsample)
这次我在上面的输出中得到➜ Sample gcc -c -fPIC -I/path/to/python2.7 sample.c
➜ Sample gcc -shared sample.o -o libsample.so
➜ Sample python setup.py build_ext --inplace
running build_ext
cythoning sample.pyx to sample.c
warning: sample.pyx:27:42: Use boundscheck(False) for faster access
building 'sample' extension
creating build
creating build/temp.linux-x86_64-2.7
gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/path/to/include/python2.7 -c sample.c -o build/temp.linux-x86_64-2.7/sample.o
gcc -pthread -shared build/temp.linux-x86_64-2.7/sample.o -L. -L/path/to/lib -lsample -lpython2.7 -o /path/to/Sample/sample.so
➜ Sample python
>>> import sample
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: libsample.so: cannot open shared object file: No such file or directory
并出现新错误。但是,cythoning sample.pyx to sample.c
位于libsample.so
目录中。这可能是什么问题?
更新3:
我终于能够成功导入此模块,但最后一个错误
Sample
暗示我需要在环境变量LD_LIBRARY_PATH中设置当前目录。但是,我是以粗暴的方式做到的:
ImportError: libsample.so: cannot open shared object file: No such file or directory
这样做的正确方法是什么?也许在export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/Sample
中使用一些参数?关于我发现的几个问题,我想得到一个答案,为什么所有这一切都发生了:
setup.py
时,sample.c
会被替换。这可以吗?python setup.py build_ext --inplace
?sample.c
才能获得正确的输出(而不是具有误导性输出的sample.pyx
)skipping 'sample.c' Cython extension (up-to-date)
的正确方法是什么? 可能会solution添加ImportError: libsample.so: cannot open shared object file: No such file or directory
:
setup.py
但是,这需要runtime_library_dirs=['./'],
与libsample.so
位于同一目录中。