Мне нужно связать мои программы на C ++ с парой общих библиотек, которые генерируют слишком много выходных данных для std :: cout
и std :: cerr
делает их обоих бесполезными для моего использования. У меня есть доступ к исходному коду C ++ этих библиотек, но я не могу их изменить.
Есть ли способ перенаправить их вывод в другой поток или подавить его, если он связан с моим кодом? Я бы предпочел чистый путь в C ++, но, опасаясь, что это будет невозможно, я также буду счастлив грязными хакерскими ссылками. Кроме того, «прокси libstdc ++
» подойдет в качестве крайней меры.
Я работаю с набором инструментов GNU ( g ++
, libtool
, ld
) под Linux.
Ну, кажется, никто до этого не додумался, вот мои предложения компоновщика:
write()
и отфильтруйте вывод по файловым дескрипторам 1
и 2
. write()
, как указано выше. my_write()
, которая обходит write()
с помощью dlsym()
. write
при связывании общих библиотек путем передачи -Wl,--wrap=write
. Затем подавите любой вывод в файловые дескрипторы 1
и 2
в функции с именем __wrap_write
. Другие файловые дескрипторы должны вызывать __real_write
. Обратите внимание, для тех, кто не знает, файловые дескрипторы 1
и 2
соответствуют stdout
и stderr
, которые в конечном итоге записано в механизме cout
/cerr
. Часто это реализуется cout
вызовами fwrite
, который вызывает write
с различными уровнями буферизации и махинациями на разных уровнях.
Лучше всего выбрать вариант 4, недостатком которого является то, что вы должны настроить последнюю ссылку для общих библиотек.
Следующим лучшим вариантом является вариант 2 выше, недостатком которого является то, что ваш окончательный исполняемый файл намного больше, но вам не нужно использовать глупые функции в своем собственном коде.
Вставка
Обертывание
Три идеи (ни одна из которых мне не очень нравится...):
Вы можете изменить буфер cout
/cerr
, в который выполняется запись, используя rdbuf( )
. Вы можете делать это каждый раз непосредственно перед вызовом функции в библиотеке и последующим ее сбросом (возможно, с помощью функций-оболочек).
Вы можете навсегда изменить буфер и использовать разные объекты cout/cerr для своего собственного приложения.
Для компиляции библиотек можно использовать модифицированные стандартные заголовочные файлы. Они могут определять новые объекты глобального потока cout_new
и использовать макросы для переопределения cout
на cout_new
. Вы можете просто указать компилятору использовать новую новую версию файлов заголовков только для компиляции библиотек (так что вам не нужно изменять их исходный код).
Как я уже сказал, ни одно из этих решений не является «чистым», но вы просили об этом :) ...
Если они действительно выводят через std::cout
и std::cerr
, то вы можете заменить буферы потока этих объектов, но у вас будет для перенаправления вывода вашей собственной программы через другие потоки. См. этот вопрос , чтобы узнать, как это сделать.
Однако, если они используют std::printf()
и т. д., это не сработает.
Поскольку stdout (файловый дескриптор 1) и stderr (файловый дескриптор 2) действительны для всего процесса, и вы не можете сделать так, чтобы одна часть программы указывала на другой файл, существует только один способ сделать это: использовать dup(2)
, чтобы продублировать их и использовать эти файловые дескрипторы в своем собственном коде. Закройте fd 1 и 2, open
/dev/null для записи и используйте dup2
, чтобы попытаться установить их в 1 или 2 соответственно, если это еще не сделано. Довольно некрасиво, но это сработает.
Если вам не нужно использовать ни то, ни другое, проще всего будет просто перенаправить стандартный вывод и стандартную ошибку из командной строки при запуске программы.
$ myprog >/dev/null 2>&1
Если вы делаете хотите использовать их самостоятельно, трюк будет состоять в том, чтобы изменить используемый ими streambuf. Здесь есть некоторый код и обсуждение как это сделать. Это действительно слишком долго, чтобы размещать здесь.