在Cython

时间:2017-12-01 20:30:10

标签: cython setuptools distutils python-extensions

我在Cython中编写了一个具有两种不同“模式”的库:

  1. 如果渲染,我使用GLFW进行编译。
  2. 如果没有渲染,我使用EGL进行编译,速度更快,但我还没弄清楚如何使用它进行渲染。
  3. 处理这种情况的推荐方法是什么?

    现在,我有以下目录结构:

    mujoco
    ├── __init__.py
    ├── simEgl.pyx
    ├── simGlfw.pyx
    ├── sim.pxd
    └── sim.pyx
    

    simEgl.pyx包含EGL代码,simGlfw.pyx包含GLFW代码。 setup.py使用环境变量为构建选择一个或另一个。

    这没关系,除了我每次想要在模式之间切换时都需要重新编译代码。肯定有更好的办法。

    更新

    我同意最好的方法是同时编译两个不同的库并使用切换来选择要导入的库。我已经在sim.pyx中拥有一个具有共享功能的基类。但是,此基类本身必须使用单独的库进行编译。具体来说,sim.pyx取决于libmujoco.so,它取决于GLFW或EGL。

    以下是我对可能方法的详尽搜索:

    1. 如果我没有编译sim.pyx的扩展程序,我会ImportError: No module named 'mujoco.sim'
    2. 如果我为sim.pyx编译扩展程序而不在扩展程序中包含图形库,我会得到ImportError: /home/ethanbro/.mujoco/mjpro150/bin/libmujoco150.so: undefined symbol: __glewBlitFramebuffer
    3. 如果我为sim.pyx编译扩展并选择一组图形库(GLFW),那么当我尝试使用另一组图形库(EGL)时,这并不会令人惊讶: ERROR: GLEW initalization error: Missing GL version
    4. 如果我编译了两个不同版本的sim.pyx库,一个有一组库,一个有另一个库,我得到:TypeError: unorderable types: dict() < dict()这不是一个非常有用的错误消息,但似乎尝试在两个不同的扩展名之间共享源文件。
    5. 应该可以选择类似选项4的东西。事实上,如果我在原始C中工作,我只需使用不同的库并排构建两个共享对象。关于如何解决这个Cython限制的任何建议都是非常受欢迎的。

1 个答案:

答案 0 :(得分:0)

(这个答案只是对评论的总结,并提供了一些解释。)

我最初的建议是创建两个定义公共接口的扩展模块。这样你就可以选择在Python中导入哪些内容,但是一旦导入它们就能以相同的方式使用它们:

if rendering:
   import simGlfw as s
else:
   import simEgl as s
s.do_something() # doesn't matter which you imported

从评论中可以看出,这两个模块还共享了大量的代码,而且它们实际上只是与它们相关联的库,它定义了它们的行为方式。尝试使用

重复使用相同的来源
Extension(name='sim1', sources=["sim.pyx",...)
Extension(name='sim2', sources=["sim.pyx",...)

失败。这是因为Cython假定模块名称与文件名相同,因此创建一个函数PyInit_sim(在Python 3上 - Python 2的命名略有不同,但想法是相同的)。但是,当您导入sim1.so时,它会查找函数PyInit_sim1,找不到它,并给出错误。

简单的方法是将公共代码放入&#34; sim.pxi&#34;并使用Cython's largely obsolete include mechanism以文字方式在sim1.pyx和sim2.pyx

中包含该代码
include "sim.pxi"

虽然通常不再推荐include,但cimport是首选,因为它提供了更多类似Python的&#34;行为,include是解决这一特定问题的简单方法。