在 Cython 中使用两个独立的库编译文件

Compile file with two separate libraries in Cython

我用 Cython 写了一个库,有两个不同的 "modes":

  1. 如果渲染,我使用 GLFW 编译。
  2. 如果不渲染,我使用EGL编译,速度更快,但我还没有想出如何用它渲染。

处理这种情况的推荐方法是什么?

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

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

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

这工作正常,只是每次我想在模式之间切换时都需要重新编译代码。一定会有更好的办法。

更新

我同意最好的方法是同时编译两个不同的库,然后使用切换键选择要导入的库。我已经在 sim.pyx 中有一个具有共享功能的基础 class。然而,这个基础 class 本身必须用单独的库编译。具体来说,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() 这不是一个非常有用的错误消息,但是似乎是由于尝试在两个不同的扩展程序之间共享源文件。

选项 4 之类的东西应该是可能的。事实上,如果我使用原始 C,我会简单地使用不同的库并排构建两个共享对象。非常欢迎任何关于如何解决此 Cython 限制的建议。

(此回答只是对评论的总结,并有更多解释。)

我最初的建议是创建两个定义通用接口的扩展模块。这样你就可以选择在 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,找不到它,并给出错误。

一个简单的方法是将通用代码放在 "sim.pxi" 中,然后使用 Cython's largely obsolete include mechanism 以文本方式将代码包含在 sim1.pyx 和 sim2.pyx[=19= 中]

include "sim.pxi"

虽然通常不再推荐 include 并且首选 cimport 因为它提供了更多 "Python-like" 行为,include 是解决这个特定问题的简单方法。