在python中,如何捕获stdout从一个c ++共享库到一个变量 [英] In python, how to capture the stdout from a c++ shared library to a variable

查看:163
本文介绍了在python中,如何捕获stdout从一个c ++共享库到一个变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于其他原因,我使用的c ++共享库将一些文本输出到标准输出。在python中,我想捕获输出和保存到变量。有很多类似的问题关于重定向的stdout,但不工作在我的代码。

For some other reasons, the c++ shared library I used outputs some texts to standard output. In python, I want to capture the output and save to a variable. There are many similar questions about redirect the stdout, but not work in my code.

示例:抑制

Example: Suppressing output of module calling outside library

1 import sys
2 import cStringIO
3 save_stdout = sys.stdout
4 sys.stdout = cStringIO.StringIO()
5 func()
6 sys.stdout = save_stdout

在第5行, func()将调用共享库,共享库生成的文本仍然输出到控制台!如果更改 func()打印hello,它会工作!

In line 5, func() will call the shared library, the texts generated by shared library still output to console! If change func() to print "hello", it works!

我的问题是:


  1. 如何捕获c ++共享库的stdout 变量

  2. 为什么使用StringIO,捕获共享库的输出?


推荐答案

Python的 sys.stdout 对象只是一个Python包装器顶部的通常stdout文件描述符 - 更改它只影响Python进程,而不是底层文件描述符。任何非Python代码,无论是另一个可执行文件 exec 'ed或加载的C共享库,都不会理解,并将继续使用普通文件

Python's sys.stdout object is simply a Python wrapper on top of the usual stdout file descriptor—changing it only affects the Python process, not the underlying file descriptor. Any non-Python code, whether it be another executable which was exec'ed or a C shared library which was loaded, won't understand that and will continue using the ordinary file descriptors for I/O.

因此,为了使共享库输出到不同的位置,您需要通过打开一个新的文件描述符来更改底层文件描述符然后使用 os.dup2() 。您可以使用临时文件作为输出,但最好使用通过 os.pipe() 。但是,如果没有任何东西正在读取管道,则会有死锁的危险,因此为了防止我们可以使用另一个线程来排空管道。

So, in order for the shared library to output to a different location, you need to change the underlying file descriptor by opening a new file descriptor and then replacing stdout using os.dup2(). You could use a temporary file for the output, but it's a better idea to use a pipe created with os.pipe(). However, this has the danger for deadlock, if nothing is reading the pipe, so in order to prevent that we can use another thread to drain the pipe.

下面是

C共享库代码:

// test.c
#include <stdio.h>

void hello(void)
{
  printf("Hello, world!\n");
}

编译为:

$ clang test.c -shared -fPIC -o libtest.dylib


$ b b

Python驱动程式:

Python driver:

import ctypes
import os
import sys
import threading

print 'Start'

liba = ctypes.cdll.LoadLibrary('libtest.dylib')

# Create pipe and dup2() the write end of it on top of stdout, saving a copy
# of the old stdout
stdout_fileno = sys.stdout.fileno()
stdout_save = os.dup(stdout_fileno)
stdout_pipe = os.pipe()
os.dup2(stdout_pipe[1], stdout_fileno)
os.close(stdout_pipe[1])

captured_stdout = ''
def drain_pipe():
    global captured_stdout
    while True:
        data = os.read(stdout_pipe[0], 1024)
        if not data:
            break
        captured_stdout += data

t = threading.Thread(target=drain_pipe)
t.start()

liba.hello()  # Call into the shared library

# Close the write end of the pipe to unblock the reader thread and trigger it
# to exit
os.close(stdout_fileno)
t.join()

# Clean up the pipe and restore the original stdout
os.close(stdout_pipe[0])
os.dup2(stdout_save, stdout_fileno)
os.close(stdout_save)

print 'Captured stdout:\n%s' % captured_stdout

这篇关于在python中,如何捕获stdout从一个c ++共享库到一个变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆