使用另一个 cython 模块导入 cython 模块时未定义的符号
Undefined symbol when importing a cython module making use of another cython module
我正在使用 Cython 将一组 C 函数包装到一个模块中。我希望能够将第一个模块导入到后续的基于 Cython 的项目中,但是在 python 脚本中导入衍生模块时,我 运行 遇到了 'undefined symbol' 问题。
考虑以下在不同目录中开发的两个模块的最小工作示例:
# 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 库公开一组通用包装器,以用于多个不同的项目应用程序。
我可以通过执行以下操作来实现它:
首先,在您的 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
您可能想要对此进行调整,但它应该可以帮助您入门。
我正在使用 Cython 将一组 C 函数包装到一个模块中。我希望能够将第一个模块导入到后续的基于 Cython 的项目中,但是在 python 脚本中导入衍生模块时,我 运行 遇到了 'undefined symbol' 问题。
考虑以下在不同目录中开发的两个模块的最小工作示例:
# 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 库公开一组通用包装器,以用于多个不同的项目应用程序。
我可以通过执行以下操作来实现它:
首先,在您的 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
您可能想要对此进行调整,但它应该可以帮助您入门。