无法从 Cython 重定向错误流

Can't redirect error stream from Cython

我尝试使用 cythonize 的 SFML 库在下面定义了这个函数,它允许更改打印错误的位置(默认情况下,SFML 在未调用此函数时将错误消息写入控制台):

namespace sf {
    std::ostream& err() {
        static DefaultErrStreamBuf buffer;
        static std::ostream stream(&buffer);
        return stream;
    }
}

我为上述功能简化的 .pxd 文件:

cdef extern from 'SFML/System.hpp' namespace 'sf':
    ostream& cerr 'sf::err' ()

还有我的 .pyx 模块,它可以正常编译和运行,但不会重定向错误消息(它们仍会打印到控制台)。

cdef void set_error_handler():
    cerr().rdbuf(NULL)  # This call should prevent errors appearing in the console but it silently fails

set_error_handler()

我正在使用 MSVC 并静态链接到 C++ 代码。

编辑

下面是 SFML 库如何在自己的代码中记录错误的示例 (full source):

...
// Error, failed to load the image
err() << "Failed to load image \"" << filename << "\". Reason: " << stbi_failure_reason() << std::endl;
...

我的目标是抑制类似上述的错误消息出现在控制台中,并最终将它们重定向到自己的缓冲区中。

您的问题有两种成分,它们都在您的设置文件中。

第一个要素是你有两个扩展:

ext_modules = [
    Extension('nebula.sfml.system', ['nebula/sfml/system.pyx'],
              language='c++', ...),
    Extension('nebula.sfml.graphics', ['nebula/sfml/graphics.pyx'],
              language='c++', ...),
] 

这意味着 cython 将创建两个不同的共享库:system.dllgraphics.dll 稍后将由 python.

动态加载

第二个要素:sfml-库是静态链接的,但包含一个单例(有问题的错误流),这是灾难的根源:有了你的设置,它不再是一个单例,但有两种不同的错误流:一种来自 system.dll,另一种来自 graphics.dll。因此,您要从 system.dll 中消除错误流(因为您的调用 set_error_handler() 存在于此),但是从 graphics.dll 写入错误流(此处 image_load_test生命)。

那么可以做什么呢?有两种选择:

  1. 使用共享 sfml-库(至少 sfml-system-s),因此单例将保持单例。
  2. 将两个 pyx 文件的内容放在同一个 pyx-file/Extension/shared 库中。至少现在 system.pyx 的内容只需要 graphics.pyx.