【问题标题】:Suppress output to cout from linked library禁止从链接库输出到 cout
【发布时间】:2010-08-26 14:19:29
【问题描述】:

我需要将我的 C++ 程序与几个共享库链接起来,这些共享库会生成太多的输出到 std::coutstd::cerr 使它们对我的使用都毫无用处。我可以访问这些库的 C++ 源代码,但不能修改它们。

有没有办法将它们的输出重定向到不同的流或在链接到我的代码时抑制它?我更喜欢 C++ 中的一种干净的方式,但担心那是不可能的,我也会对肮脏的链接器黑客感到满意。作为最后的手段,“代理libstdc++”也可以。

我正在使用 Linux 下的 GNU 工具链(g++libtoolld)。

【问题讨论】:

  • 这不是真正的cerr/cout,而是STDOUT_FILENOSTDERR_FILENO 的包装。除了拥有用户之外,C++ 没有什么神奇之处。
  • @Matt:我刚刚提到希望当我将 C++ 代码链接在一起时(例如覆盖符号)可以利用这一点。但也许那个语言信息在那个阶段都消失了。
  • IMO 不完全重复,但相关:stackoverflow.com/questions/533038/…
  • @sbi:我希望在链接器阶段有一个侵入性较小的解决方案。

标签: c++ linux linker


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    好吧,似乎没有人注意到它,这是我的链接器建议:

    1. 插入 libc,提供您自己的 write(),并将输出过滤到文件描述符 12
    2. 静态链接您自己的代码与 libc,然后插入共享版本以静噪write() 如上所述。
    3. 插入 libc,提供一个 my_write() 函数,使用 dlsym() 绕过 write()
    4. 通过传递-Wl,--wrap=write 链接共享库时包装write。然后在名为__wrap_write 的函数中将任何输出静噪到文件描述符12。其他文件描述符应调用__real_write

    请注意,对于那些不知道的人,文件描述符12 对应于stdoutstderr,它们最终被写入cout/cerr 机器中。这通常是通过cout 调用fwrite 来实现的,后者又调用write,在不同的级别具有不同级别的缓冲和恶作剧。

    您最好的选择是选项 4,缺点是您必须调整共享库的最终链接。

    其次最好的是上面的选项 2,缺点是您的最终可执行文件要大得多,但不必在自己的代码中使用愚蠢的函数。

    链接

    插入

    包装

    【讨论】:

    • 您是否应该在此处某处提及LD_PRELOAD
    • LD_PRELOAD 是插入技术的一部分
    【解决方案3】:

    由于 stdout(文件描述符 1)和 stderr(文件描述符 2)对整个进程都有效,并且您不能让程序的一部分指向不同的文件,因此只有一种方法可以做到:使用dup(2) 复制它们并在您自己的代码中使用这些文件描述符。关闭 fd 的 1 和 2,open /dev/null 进行写入,如果还没有,则使用 dup2 尝试将它们分别设置为 1 或 2。相当丑陋,但这会起作用。

    【讨论】:

      【解决方案4】:

      如果您不需要自己使用,最简单的做法是在启动程序时从命令行重定向标准输出和标准错误。

      $ myprog >/dev/null 2>&1

      如果您确实想自己使用它们,诀窍就是更改它们使用的streambuf。有一些关于how to do that here 的代码和讨论。实在是太长了,在这里发帖。

      【讨论】:

        【解决方案5】:

        三个想法(没有一个是我真正喜欢的......):

        • 您可以使用rdbuf() 更改cout/cerr 正在写入的缓冲区。您可以在每次调用库中的函数并在之后重置它之前执行此操作(可能使用包装函数)。

        • 您可以永久更改缓冲区并为您自己的应用程序使用不同的 cout/cerr 对象。

        • 您可以使用修改后的标准头文件来编译库。他们可以定义新的全局流对象cout_new 并使用宏将cout 重新定义为cout_new。你可以告诉编译器使用新版本的头文件来编译库(所以你不必修改它们的源代码)。

        正如我所说,这些解决方案都不是“干净的”,但你要求它:) ...

        【讨论】:

          【解决方案6】:

          如果它们真的通过std::coutstd::cerr 输出,那么您可以替换这些对象的流缓冲区,但您必须通过其他流重定向您自己程序的输出。请参阅this question 了解如何执行此操作。

          但是,如果他们使用std::printf() 等,那么这将不起作用。

          【讨论】:

            猜你喜欢
            • 2015-08-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-22
            • 2015-07-22
            • 2011-07-08
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多