Можно ли получить точные показания из stderr/stdout, используя boost::process?C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Можно ли получить точные показания из stderr/stdout, используя boost::process?

Сообщение Anonymous »

Вот пример вывода компилятора MS:
Изображение

Первые три строки всегда выводятся на стандартный вывод, за ними следует строка использования, выводимая на стандартный вывод. cmd.exe — это оболочка-интерпретатор, которая запускает процесс cl.exe, считывает из него stderr/stdout и выводит текст на вывод консоли. Он всегда выводит его в этом порядке, никогда не появляясь перед stderr (возможно, они выполняют fflush(stderr) перед печатью строки использования).
Если я использую boost: :process что бы я ни пробовал, порядок вывода почти всегда не соответствовал тому, что показывал cmd.exe.
Я использую этот пример программы для вывода вывода:
/// test-exe.exe
#include
#include

int main()
{
int lineLen = 1024;
int stdoutCount = 5;
int stderrCount = 5;
int repeatCount = 10;

std::string s;
s.resize(lineLen);
for (int i = 0; i < lineLen; ++i)
s = '0' + (i / 10) % 10;

int n = 0;

for (int i = 0; i < repeatCount; ++i)
{
for (int i = 0; i < stdoutCount; ++i)
fprintf(stdout, "stdout %d %s\n", n++, s.c_str());
for (int i = 0; i < stderrCount; ++i)
fprintf(stderr, "stderr %d %s\n", n++, s.c_str());
}
}

Как правильно это сделать с помощью boost::process::child, чтобы объединенный вывод соответствовал тому, что отображается в обычном приглашении cmd?
Один из способов — использовать boost:: process::system и перенаправить stderr на stdout (например, system("test.exe 2>&1")), но это обходной путь, поскольку потоки обрабатываются с помощью cmd.exe под капотом, и я объединяюсь stdout без какого-либо различия, является ли что-то стандартным выводом или stderr.
Я использовал этот код в качестве отправной точки и пытался изменить его по-разному, но у меня это не сработало. Он не получает тупиковые строки чтения из stdout/stderr, но порядок вывода не сохраняется так, как его получает cmd.exe.
#include
#include
#include
#include

struct OutputLine
{
std::string data; // with trailing /r/n stripped if any
bool isStderr; // if the line is stderr
};

static int getCmdOutput(const char* cmd, std::vector& out)
{
namespace bp = boost::process;

out.clear();

std::vector ret;
bp::ipstream s_out, s_err;
std::error_code ec;

bp::child c(cmd, bp::std_err > s_err, bp::std_out > s_out, ec);
if (ec)
return -1;
std::mutex mx, mx2;
bool readingStdout = false;
auto readFunc = [&]() {
for (std::string line;;)
{
bool doStdout = false;
{
std::scoped_lock lock(mx2);
if (!readingStdout)
doStdout = readingStdout = true;
}
bool res = !!std::getline(doStdout ? s_err : s_out, line);
{
std::scoped_lock lock(mx2);
if (doStdout)
readingStdout = false;
}
if (!res)
break;
while (!line.empty() && (line.back() == '\r' || line.back() == '\n'))
line.pop_back();

std::scoped_lock lock(mx);
out.emplace_back();
out.back().data.swap(line);
out.back().isStderr = doStdout;
}
};
std::thread th(readFunc); // read stdout/stderr from async thread
readFunc(); // read stdout/stderr
c.wait();
th.join();
return c.exit_code();
}

int main(int argc, const char* argv[])
{
std::vector out;
int ret = getCmdOutput("test-exe.exe", out);

for (const auto& s : out)
printf("%s\n", s.data.c_str());

printf("test-exe.exe return: %d", ret);
}


Подробнее здесь: https://stackoverflow.com/questions/793 ... ostprocess
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»