简体   繁体   English

从链接库中抑制输出到cout

[英]Suppress output to cout from linked library

I need to link my C++ programs against a couple shared libraries which generate way too much output to std::cout and std::cerr rendering them both useless for my uses. 我需要将我的C ++程序与几个共享库链接起来,这些共享库会产生太多输出到std::coutstd::cerr使它们对我的用途都无用。 I have access to the C++ source code of these libraries, but cannot modify them. 我可以访问这些库的C ++源代码,但无法修改它们。

Is there a way to redirect their output to a different stream or suppress it when linked against my code? 有没有办法将其输出重定向到不同的流或在链接到我的代码时抑制它? I would prefer a clean way in C++, but fearing that that would be impossible I will also be happy with dirty linker hacks. 我更喜欢C ++中的一种干净的方式,但是担心那是不可能的,我也会对脏的链接器黑客感到高兴。 Also a "proxy libstdc++ " would be fine as a last resort. 另外,“代理libstdc++ ”可以作为最后的手段。

I am working with a GNU toolchain ( g++ , libtool , ld ) under Linux. 我在Linux下使用GNU工具链( g++libtoolld )。

显然, freopen可以做到这一点。

If you don't need to use either yourself, the easiest thing to do would be to just redirect standard output and standard error from the command line when you start your program. 如果您不需要自己使用,最简单的方法是在启动程序时从命令行重定向标准输出和标准错误。

$ myprog >/dev/null 2>&1

If you do want to use them yourself, the trick would be to change the streambuf they use. 如果您确实想自己使用它们,那么诀窍就是更改它们使用的streambuf。 There's some code and discussion about how to do that here . 这里有一些代码和讨论如何做到这一点 Its really too long to post here. 它真的太长了,无法在这里发布。

Since stdout (file descriptor 1) and stderr (file descriptor 2) are valid for the whole process and you can't make one part of the program have it point to a different file, there's only one way to do it: use dup(2) to duplicate them and use those file descriptors in your own code. 由于stdout(文件描述符1)和stderr(文件描述符2)对整个过程有效,并且您不能使程序的一部分指向不同的文件,因此只有一种方法可以执行此操作:使用dup(2)复制它们并在您自己的代码中使用这些文件描述符。 Close the fd's 1 and 2, open /dev/null for writing and use dup2 to try to set them to 1 or 2 respectively if it isn't already. 关闭fd的1和2, open / dev / null进行写入,并使用dup2分别尝试将它们设置为1或2(如果尚未设置)。 Pretty ugly, but that'd work. 很难看,但那很有用。

Three ideas (none of which I really like ...): 三个想法(我都不喜欢......):

  • You can change the buffer cout / cerr are writing to by using rdbuf() . 您可以使用rdbuf()更改缓冲区cout / cerr正在写入的内容。 You could do this everytime just before you're calling a function in the library and resetting it afterwards (maybe using wrapper functions). 您可以在调用库中的函数之前每次执行此操作并在之后重置它(可能使用包装函数)。

  • You could change the buffer permanently and use different cout/cerr objects for your own application. 您可以永久更改缓冲区,并为您自己的应用程序使用不同的cout / cerr对象。

  • You could use modified standard header files for compiling the libraries. 您可以使用修改后的标准头文件来编译库。 They could define new global stream objects cout_new and use macros to redefine cout to cout_new . 他们可以定义新的全局流对象cout_new并使用宏将cout重新定义为cout_new You could just tell the compiler to use new new version of the header files just for compiling the libraries (so you don't have to modify their source code). 你可以告诉编译器使用新版本的头文件只是为了编译库(所以你不必修改它们的源代码)。

As I said, none of these solutions is "clean", but you asked for it :) ... 正如我所说,这些解决方案都不是“干净”,但你要求它:) ...

Well nobody seems to have hit on it, here's my linker suggestions: 好吧没有人似乎对它有所了解,这是我的链接器建议:

  1. Interpose libc, provide your own write() , and filter output to file descriptors 1 and 2 . 插入libc,提供自己的write() ,并将输出过滤到文件描述符12
  2. Statically link your own code against libc, and then interpose the shared version to squelch write() as above. 将您自己的代码静态链接到libc,然后插入共享版本以如上所述压制write()
  3. Interpose libc, providing a my_write() function that bypasses write() using dlsym() . 插入libc,提供一个my_write()函数,使用dlsym()绕过write() dlsym()
  4. Wrap write when linking the shared libraries by passing -Wl,--wrap=write . write通过传递联的共享库时-Wl,--wrap=write Then squelch any output to file descriptors 1 and 2 in a function called __wrap_write . 然后在名为__wrap_write的函数__wrap_write任何输出压缩到文件描述符12 Other file descriptors should call through to __real_write . 其他文件描述符应调用__real_write

Note that for those that aren't aware, file descriptors 1 and 2 correspond to stdout and stderr , which are eventually written to in the cout / cerr machinery. 请注意,对于那些不知道的人,文件描述符12对应于stdoutstderr ,它们最终被写入cout / cerr机器中。 Often this is implemented cout calls fwrite which calls write , with varying levels of buffering and shenanigans at the different levels. 通常这是实现cout调用fwrite调用write ,在不同级别具有不同级别的缓冲和恶作剧。

Your best bet is option 4, the downside is you must tweak the final link for the shared libraries. 您最好的选择是选项4,缺点是您必须调整共享库的最终链接。

Next best is option 2 above, the downside is your final executable is much bigger, but don't have to use silly functions in your own code. 接下来最好的是上面的选项2,缺点是你的最终可执行文件要大得多,但不必在你自己的代码中使用愚蠢的函数。

Links 链接

Interposing 居间

Wrapping 包皮

If they are really outputting through std::cout and std::cerr then you could replace those object's stream buffers, but you would have to redirect your own program's output through other streams. 如果它们真的通过std::coutstd::cerr输出,那么你可以替换那些对象的流缓冲区,但是你必须通过其他流重定向你自己的程序的输出。 See this question for how to do this. 有关如何执行此操作,请参阅此问题

However, if they use std::printf() etc. then this won't work. 但是,如果他们使用std::printf()等,那么这将无效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM