用于将cython中的许多c ++类包装到单个共享对象的项目结构

时间:2012-07-28 05:13:56

标签: c++ python design-patterns cython

我在文档,邮件列表和this question here之间找到了部分答案,但我希望得到一个更直接的答案来解决我的具体问题......

我正在学习cython,试图一点一点地包装我已经使用的目前包含在boost :: python中的库。我为这个boost包装器贡献了一点点,并将它用作c ++参考,同时我使用ZeroMQ Python bindings作为cython参考。

我的问题是关于项目结构。此lib的当前boost版本编译为单个.so,这是我的目标。我很快发现你无法直接将多个.pyx模块编译为单个.so。然后我开始沿cppclass文件中定义pxd的路径,以及.pxi中相应的python导出的实现类,并尝试将它们包含在一个pyxpxi 1}}用于编译。虽然它最初起作用,但是一旦我写了更多内容,我就会因为cppclass包括在不同的地方而遇到多个定义冲突的问题。

我很想听到一个适当的组织方法来解决以下问题和目标:

  • 将公共类命名为与pyd相同(我现在通过将cppclass放在另一个名为.so并使用导入的命名空间来处理类似名称来实现此目的,ala {{3 }})
  • pyx作为编译输出(Using cimport to resolve naming conflicts
  • 我是否仅针对pyxpyx使用src多包含方法,或者主setup.py是否应包含除了包含所有内容之外的其他内容?
  • 在哪里集中定义将在python中导出的常量?
  • 是否有首选的文件夹结构?现在,我已将所有内容放在pxi, pxd, pyx下方的pxi目录中。看到这么多__init__.py个文件会让人感到困惑。
  • 现在完全不需要{{1}}吗?如果没有,我是否需要使用cython风格的ifndef防护来处理不同模块之间的多个包含?
  • 我知道ZeroMQ python绑定构建了多个模块,并通过{{1}}包含它们来使用包方法。这真的是cython的正确方法吗?

作为参考,我正在练习重新换行的项目是acceptable approach?(openni)。此boost项目采用的模式是在一个地方收集公共对象,然后使用源定义一对一的头定义,然后有一个巨大的包装器将所有定义收集到单个位置。还有添加的自定义异常处理和实用程序。

2 个答案:

答案 0 :(得分:20)

在等待明确的答案时,我一直在玩组织我的代码。到目前为止,将pyx个文件包含在单个pyx中进行编译一直在进行。

我的setup.py很简单:

ext_modules = [
    Extension(
        "openni", 
        ["src/openni.pyx"], 
        language="c++",
        include_dirs=['src/', '/usr/include/ni'],
        libraries=['OpenNI'],
    )
],

openni.pyx看起来像:

include "constants.pyx"
include "exceptions.pyx"
include "context.pyx"
...

我有一个共同的libopenni.pxd来为其余的模块提供仅声明的外部。

我将cppclass声明命名为与pxd类定义不同的pyx名称,以避免名称冲突:

xncontext.pxd

cdef extern from "XnCppWrapper.h" namespace "xn":
    cdef cppclass Context:
           ...

context.pyx:

from libopenni cimport *
from xncontext cimport Context as c_Context 

cdef class Context:
    cdef c_Context *handle   
        ...

答案 1 :(得分:0)

回答是否有首选的文件夹结构?

是的,Cython的.pyx.pxd文件的首选文件夹结构是完全按照.py文件的方式处理它们:每个模块一个,在一个井中组织的包结构。可以像__init__.pxd文件一样提供__init__.py个文件,以组装一组精选符号,从其子模块/包中收集一组符号用于进行cimporting。

是的,这会为每个模块生成一个.so文件,但这些文件会隐藏在构建目录中。 Python的构建模块也是如此;每个文件都有相应的.so个文件。这是一个问题吗?