【问题标题】:Compile file with two separate libraries in Cython在 Cython 中使用两个单独的库编译文件
【发布时间】:2017-12-01 20:30:09
【问题描述】:

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

  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 中有一个具有共享功能的基类。然而,这个基类本身必须使用单独的库进行编译。具体来说,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 限制的建议。

【问题讨论】:

  • 您可能只想将两者构建为单独的扩展模块?例如以stackoverflow.com/a/21826294/3657742为例
  • 我在很大程度上同意@chrisb。您编写两个具有相同接口的扩展模块并使用if rendering: import simGlfw as s; else: import simEgl as s。如果您想使用 Cython(即编译时)功能,这可能会改变,但如果是这种情况,您需要提供更多细节(尽管通用基类可能是一个很好的解决方案)
  • 我同意这是要走的路。但是,它确实需要将sim.pyx 文件编译成两个不同的.so 文件。我尝试使用Extension(name='sim1', ...)Extension(name='sim2', ...) 执行此操作,但这会导致导入错误。或许您可以提出一个更好的方法?
  • @chrisb,我的情况与您引用的帖子之间的关键区别在于,该帖子不需要在两个单独的扩展中使用相同的来源。
  • @ethanabrooks(不是 100% 肯定,但是......) Cython/Python 模块的名称来自源文件名,我认为这是导致您出现问题的原因。您可以尝试使用正确的名称创建两个几乎为空的 .pyx 文件,并使用 Cython's little used include mechanism 在每个文件中加载共享代码。

标签: cython setuptools distutils python-extensions


【解决方案1】:

(这个答案只是对cmets的一个总结,还有一点解释。)

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

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

从 cmets 看来,这两个模块还共享大量代码,并且实际上只是它们链接的库定义了它们的行为方式。尝试重复使用相同的来源

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 中

include "sim.pxi"

尽管include 通常不再被推荐,而cimport 是首选,因为它提供了更多“类似Python”的行为,但include 是解决这个特殊问题的简单方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-20
    • 2017-01-22
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    相关资源
    最近更新 更多