在 Cython 中使用两个独立的库编译文件
Compile file with two separate libraries in Cython
我用 Cython 写了一个库,有两个不同的 "modes":
- 如果渲染,我使用 GLFW 编译。
- 如果不渲染,我使用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。
这是我对可能方法的详尽搜索:
- 如果我不编译
sim.pyx
的扩展,我会得到 ImportError: No module named 'mujoco.sim'
- 如果我为
sim.pyx
编译扩展而不在扩展中包含图形库,我会得到 ImportError: /home/ethanbro/.mujoco/mjpro150/bin/libmujoco150.so: undefined symbol: __glewBlitFramebuffer
- 如果我为
sim.pyx
编译扩展并选择一组图形库 (GLFW),那么当我尝试使用另一组图形库 (EGL) 时,这也不起作用,这不足为奇:
ERROR: GLEW initalization error: Missing GL version
- 如果我编译两个不同版本的
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
是解决这个特定问题的简单方法。
我用 Cython 写了一个库,有两个不同的 "modes":
- 如果渲染,我使用 GLFW 编译。
- 如果不渲染,我使用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。
这是我对可能方法的详尽搜索:
- 如果我不编译
sim.pyx
的扩展,我会得到ImportError: No module named 'mujoco.sim'
- 如果我为
sim.pyx
编译扩展而不在扩展中包含图形库,我会得到ImportError: /home/ethanbro/.mujoco/mjpro150/bin/libmujoco150.so: undefined symbol: __glewBlitFramebuffer
- 如果我为
sim.pyx
编译扩展并选择一组图形库 (GLFW),那么当我尝试使用另一组图形库 (EGL) 时,这也不起作用,这不足为奇:ERROR: GLEW initalization error: Missing GL version
- 如果我编译两个不同版本的
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
是解决这个特定问题的简单方法。