Подавить вывод в cout из связанной библиотеки - PullRequest
7 голосов
/ 26 августа 2010

Мне нужно связать мои программы на C ++ с парой общих библиотек, которые генерируют слишком много выходных данных, к std::cout и std::cerr, что делает их обе бесполезными для моего использования.У меня есть доступ к исходному коду этих библиотек на C ++, но я не могу их изменить.

Есть ли способ перенаправить их вывод в другой поток или подавить его, если он связан с моим кодом?Я бы предпочел чистый путь в C ++, но, опасаясь, что это будет невозможно, я также буду счастлив грязными хакерскими ссылками.Кроме того, «прокси libstdc++» было бы неплохо в крайнем случае.

Я работаю с набором инструментов GNU (g++, libtool, ld) под Linux.

Ответы [ 6 ]

4 голосов
/ 26 августа 2010

Очевидно, freopen может сделать это.

2 голосов
/ 26 августа 2010

Поскольку stdout (дескриптор файла 1) и stderr (дескриптор файла 2) действительны для всего процесса, и вы не можете заставить одну часть программы указывать на другой файл, есть только один способ сделать это:используйте dup(2), чтобы дублировать их, и используйте эти файловые дескрипторы в своем собственном коде.Закройте fd's 1 и 2, open / dev / null для записи и используйте dup2, чтобы попытаться установить их в 1 или 2 соответственно, если это еще не сделано.Довольно некрасиво, но это бы сработало.

2 голосов
/ 26 августа 2010

Если вам не нужно использовать их самостоятельно, проще всего будет просто перенаправить стандартный вывод и стандартную ошибку из командной строки при запуске вашей программы.

$ myprog >/dev/null 2>&1

Если вы действительно хотите использовать их самостоятельно, хитрость заключается в изменении потокового буфера, который они используют. Здесь есть некоторый код и обсуждение , как это сделать . Это действительно слишком долго, чтобы публиковать здесь.

1 голос
/ 27 августа 2010

Ну, кажется, никто не ударил, вот мои предложения компоновщика:

  1. Вставьте libc, предоставьте свой write() и отфильтруйте выходные данные в файловых дескрипторах 1 и 2.
  2. Статически свяжите свой собственный код с libc, а затем вставьте совместно используемую версию для подавления write(), как указано выше.
  3. Вставьте libc, предоставив my_write() функцию, которая обходит write(), используя dlsym().
  4. Обтекание write при связывании общих библиотек путем передачи -Wl,--wrap=write. Затем подавите любой вывод в файловые дескрипторы 1 и 2 в функции с именем __wrap_write. Другие файловые дескрипторы должны вызывать __real_write.

Обратите внимание, что для тех, кто не знает, файловые дескрипторы 1 и 2 соответствуют stdout и stderr, которые в конечном итоге записываются в механизм cout / cerr. Часто это реализуется cout вызывает fwrite, что вызывает write, с различными уровнями буферизации и махинаций на разных уровнях.

Ваша лучшая ставка - вариант 4. Недостатком является то, что вы должны настроить окончательную ссылку для общих библиотек.

Следующий лучший вариант - вариант 2 выше, недостатком является то, что ваш конечный исполняемый файл намного больше, но вам не нужно использовать глупые функции в вашем собственном коде.

Ссылки

1043 * Реле *

Обертывание

1 голос
/ 26 августа 2010

Три идеи (ни одна из которых мне не очень нравится ...):

  • Вы можете изменить буфер cout / cerr для записи с помощью rdbuf(). Вы можете делать это каждый раз перед вызовом функции в библиотеке и последующим ее сбросом (возможно, с использованием функций-оболочек).

  • Вы можете навсегда изменить буфер и использовать различные объекты cout / cerr для своего собственного приложения.

  • Вы можете использовать измененные стандартные заголовочные файлы для компиляции библиотек. Они могут определять новые объекты глобального потока cout_new и использовать макросы для переопределения cout в cout_new. Вы можете просто указать компилятору использовать новую новую версию файлов заголовков только для компиляции библиотек (чтобы вам не приходилось изменять их исходный код).

Как я уже сказал, ни одно из этих решений не является "чистым", но вы просили об этом :) ...

0 голосов
/ 26 августа 2010

Если они действительно выводятся через std::cout и std::cerr, вы можете заменить потоковые буферы этих объектов, но вам придется перенаправить вывод своей программы через другие потоки. См. этот вопрос , чтобы узнать, как это сделать.

Однако, если они используют std::printf() и т. Д., Это не сработает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...