将.c文件重命名为.cpp,导入Cython库失败

时间:2018-02-05 23:28:01

标签: python c++ c cython

我有一个工作的Cython程序,它包含了一些C库和自定义C代码。最近,我不得不将项目切换到C ++,因此我将所有C代码重命名为*.cpp。 Cython编译正常并生成.so文件。但是,当我尝试在Python中导入我的库时,出现以下错误。

File "example.py", line 1, in <module>
    from tag36h11_detector import detect
ImportError: dlopen(/Users/ajay/Documents/Code/calibration/apriltag_detector/examples/tag36h11_detector.cpython-36m-darwin.so, 2): Symbol not found: _free_detection_payload
  Referenced from: /Users/ajay/Documents/Code/calibration/apriltag_detector/examples/tag36h11_detector.cpython-36m-darwin.so
  Expected in: flat namespace
 in /Users/ajay/Documents/Code/calibration/apriltag_detector/examples/tag36h11_detector.cpython-36m-darwin.so

因为我不确定错误的来源,所以我不确定要提供哪些相关信息。

这是我的setup.py

from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy

setup(ext_modules=cythonize(Extension(
    name='tag36h11_detector',
    sources=["tag36h11_detector.pyx",
             "tag36h11_detector/tag36h11_detector.cpp"],
    include_dirs=["/usr/local/include/apriltag", numpy.get_include()],
    libraries=["apriltag"])))

我用python setup.py build_ext --inplace

编译它

感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

language=c++添加到您的设置中:

setup(ext_modules=cythonize(Extension(
    name='XXX',
    ....
    language="c++",
 )))

您可能使用gcc。 gcc(和许多其他编译器)的前端决定文件是编译为C(使用cc1)还是C ++(使用cc1plus),具体取决于其扩展名:“。c”是C,“。cpp”是C ++。 / p>

如果在设置中使用extra_compile_args=["-v"],,则可以确切地看到使用了哪个编译器:

  1. Cython创建“tag36h11_detector.c”,由于其扩展名,使用了C编译器(cc1)。
  2. 对于文件“tag36h11_detector / tag36h11_detector.cpp”,使用了C ++编译器(cc1plus)。
  3. C和C ++之间的区别之一是name mangling:C期望目标文件中符号的名称不会被破坏,但C ++会破坏它。

    例如,对于具有签名int test(int)的函数,C告诉链接器搜索名为test的符号,但C ++会创建一个名为_Z4testi的符号,因此它不能找到联动步骤。

    现在,联系期间会发生什么?在Linux上,链接共享对象的默认行为是,我们可以使用未定义的符号。隐含地假设,在加载共享库的运行时,这些符号将是有效的。这意味着只有在加载共享对象并且找不到符号时,即导入模块时,程序才会失败。

    如果存在未定义的符号,则可以添加extra_link_args=["-Wl,--no-undefined"]以确保编译失败,以便在运行时没有任何意外。

    解决问题的一种方法可能是C ++ - 编译器在代码中使用extern "C"发出未编码的名称,如评论中所指出的那样。

    一种较少侵入性的方法是向编译器说明,通过将language="c++"添加到设置来使用C ++ - 约定。

    使用language="c++",Cython从“XXX.pyx”创建“XXX.cpp”(而不是“XXX.c”),因此gcc为cythonized文件选择C ++编译器,该文件知道正确的名字 - 错误。