【问题标题】:Undefined symbol when importing a cython module making use of another cython module导入使用另一个 cython 模块的 cython 模块时未定义的符号
【发布时间】:2016-01-08 19:56:14
【问题描述】:

我正在使用 Cython 将一组 C 函数包装到一个模块中。我希望能够将第一个模块导入到后续基于 Cython 的项目中,但是在 python 脚本中导入派生模块时遇到了“未定义符号”问题。

考虑以下在不同目录中开发的两个模块的最小工作示例:

# exModA wraps the functions provided in exModAFxn.c
exModA/
    __init__.pxd
    __init__.py
    exModAFxn.c
    exModA.pyx
    setup.py
# exModB attempts to use the cdef functions from exModA
exModB/
   __init__.py
   exModB.pyx
   setup.py
# The test script attempts to make use of exModB
test.py

exModA/__init__.pxd:

cdef extern void myCMessage()

exModA/__init__.py:

from exModA import *

exModA/exModAFxn.c:

#include <stdio.h>
void myCMessage() { printf( "This is a test!\n" ); }

exModA/exModA.pyx:

cdef extern from "exModAFxn.c" :
    void myCMessage()
# Use myCMessage in a python function
def foo() :
    myCMessage()

exModA/setup.py:

from distutils.core import setup, Extension
from Cython.Build import cythonize
setup( 
    name = 'exModA',
    ext_modules = cythonize( ['exModA/exModA.pyx'] ),
)

exModB/__init__.py:

from exModB import *

exModB/exModB.pyx:

cimport exModA
# Use a cdef function from exModA in a python function
def bar() :
    exModA.myCMessage()

exModB/setup.py:

from distutils.core import setup, Extension
from Cython.Build import cythonize
setup( 
    name = 'exModB',
    ext_modules = cythonize( ['exModB/exModB.pyx'] ),
)

两个cython模块编译后调用test.py脚本。

python extModA/setup.py build_ext --inplace
python extModB/setup.py build_ext --inplace

test.py:

import exModA
exModA.foo()    # successfully prints message
import exModB   # raises ImportError: undefined symbol: myCMessage
exModB.bar()    # we never get to this line :(

从 exModA.foo 函数成功打印消息向我表明 myCMessage 实际上是可用的,但是在导入 exModB 时找不到它。我知道如果我将 exModA 和 exModB 合并到一个项目中,这个问题就会消失,但如果可能的话,我想避免这种方法——我试图为 C 库公开一组通用的包装器,以便在几个不同的项目中使用应用程序。

【问题讨论】:

    标签: python python-2.7 cython


    【解决方案1】:

    我能够通过执行以下操作来使其工作:

    首先,在exModB/setup.py 文件中指定用于链接的exModA 库,如下所示:

    from distutils.core import setup, Extension
    from Cython.Build import cythonize
    
    ext = Extension('exModB/exModB',
                    sources=['exModB/exModB.pyx'],
                    libraries=['exModA'],
                    library_dirs=['/home/MyFolder/exModA'],
                    runtime_library_dirs=['/home/MyFolder/exModA']
                    )
    setup(name='exModB', ext_modules = cythonize(ext))
    

    (我建议不要指定运行时库目录,而是将exModA.so 移动到库搜索路径上的文件夹中。)

    我还必须将 exModA.so 重命名为 libexModA.so 以便 gcc 可以找到它。在构建 exModA.so 之后,但在构建 exModB.so 之前执行此操作:

    python exModA/setup.py build_ext --inplace
    cp exModA/exModA.so exModA/libexModA.so
    python exModB/setup.py build_ext --inplace
    

    您可能需要对此进行调整,但它应该可以帮助您入门。

    【讨论】:

    • 谢谢,嘉莉!这正如我提供的示例所宣传的那样。
    • 像魅力一样工作。请注意:我实际上遵循了 O'Reilly 的“Python Cookbook”中的说明。对于我在库中编写和导出的每个函数(然后将其转换为 cython 模块),我都得到了未定义的符号。使用nm -C libsample.so 时,我可以看到所有必需的符号都已正确导出,但是在执行nm -C sample.cython-34m.so 时,我的所有东西都得到了U(未定义的符号)。调用cythonize 解决了这个问题。
    最近更新 更多