2017-07-27 44 views
1

我想要cythonize的SFML库定义了下面的这个函数,它允许更改错误的打印位置(默认情况下,SFML在未调用此函数时将错误消息写入控制台):无法重定向来自Cython的错误流

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; 
... 

我的目标是出现在抑制像上面这样一个错误信息控制台,并最终将它们重定向到自己的缓冲区中。

+0

你能提供一个最小的pyx文件,你实际上使用日志? – ead

+0

@ead当然,我已经更新了这个问题。我不会将任何内容记录到'sf:err()'中,SFML库会执行此操作,我想要禁止该操作或重定向。 – HankMoody

+0

如果在C++中编写'set_error_handler()'并从cython调用它,会发生什么情况。那它有用吗?只是试图排除,这是一个不是一个问题。 – ead

回答

1

有两种成分可以解决您的问题,两种成分都在您的设置文件中。

第一成分是您有两个扩展名:

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由蟒这将在两个装载以后动态。

第二个组成部分:sfml -library静态链接,但包含一个singleton(问题中的错误流),这是一个灾难的秘诀:使用您的设置,它不再是单身人士,但有两个不同的错误流:来自system.dll的错误流和来自graphics.dll的错误流。因此,您正在沉默来自system.dll的错误流(因为您的电话set_error_handler()居住在那里),但是写入来自graphics.dll(此处为image_load_test住)的错误流。

那么可以做些什么?有两个选项:

  1. 使用共享sfml -libraries(至少sfml-system-s),因此单会留一个单例。
  2. 将两个pyx文件的内容放在同一个pyx-file/Extension /共享库中。至少现在,system.pyx的内容仅适用于graphics.pyx
+0

不幸的是,它不起作用,Cython抱怨“C++引用无法声明;改用指针”。所以我使用了像'cdef ostream * ref_to_err =&cerr()'这样的指针代替引用,它显然已经被编译了,但它也没有工作。 – HankMoody

+0

@PythonFanboy请你提供一个你的设置的最简单的例子吗?所以我可以重现这个问题? – ead

+0

好的,我已经在这里上传了:https://www.dropbox.com/s/svf8o5o9o5mkt9m/sfml_error.zip?dl=0 – HankMoody