}
break;
+ case FileType::stdout_output:
case FileType::stderr_output:
- // Stderr data: Don't open a destination file. Instead accumulate it in
- // m_dest_data and write it in on_entry_end.
+ // Stdout/stderr data: Don't open a destination file. Instead accumulate it
+ // in m_dest_data and write it in on_entry_end.
m_dest_data.reserve(file_len);
break;
break;
}
- if (file_type == FileType::stderr_output) {
+ if (file_type == FileType::stdout_output
+ || file_type == FileType::stderr_output) {
// Written in on_entry_end.
} else if (dest_path.empty()) {
LOG_RAW("Not writing");
void
ResultRetriever::on_entry_data(const uint8_t* data, size_t size)
{
- ASSERT(!(m_dest_file_type == FileType::stderr_output && m_dest_fd));
+ ASSERT(!((m_dest_file_type == FileType::stdout_output
+ || m_dest_file_type == FileType::stderr_output)
+ && m_dest_fd));
- if (m_dest_file_type == FileType::stderr_output
+ if (m_dest_file_type == FileType::stdout_output
+ || m_dest_file_type == FileType::stderr_output
|| (m_dest_file_type == FileType::dependency && !m_dest_path.empty())) {
m_dest_data.append(reinterpret_cast<const char*>(data), size);
} else if (m_dest_fd) {
void
ResultRetriever::on_entry_end()
{
- if (m_dest_file_type == FileType::stderr_output) {
+ if (m_dest_file_type == FileType::stdout_output) {
+ LOG("Writing to file descriptor {}", STDOUT_FILENO);
+ Util::send_to_fd(m_ctx, m_dest_data, STDOUT_FILENO);
+ } else if (m_dest_file_type == FileType::stderr_output) {
LOG("Writing to file descriptor {}", STDERR_FILENO);
Util::send_to_fd(m_ctx, m_dest_data, STDERR_FILENO);
} else if (m_dest_file_type == FileType::dependency && !m_dest_path.empty()) {
write_result(Context& ctx,
const std::string& result_path,
const Stat& obj_stat,
+ const std::string& stdout_path,
const std::string& stderr_path)
{
Result::Writer result_writer(ctx, result_path);
+ const auto stdout_stat = Stat::stat(stdout_path, Stat::OnError::log);
const auto stderr_stat = Stat::stat(stderr_path, Stat::OnError::log);
- if (!stderr_stat) {
+ if (!stdout_stat || !stderr_stat) {
return false;
}
if (stderr_stat.size() > 0) {
result_writer.write(Result::FileType::stderr_output, stderr_path);
}
+ // Write stdout only after stderr (better with MSVC), as ResultRetriever
+ // will later print process them in the order they are read.
+ if (stdout_stat.size() > 0) {
+ result_writer.write(Result::FileType::stdout_output, stdout_path);
+ }
if (obj_stat) {
result_writer.write(Result::FileType::object, ctx.args_info.output_obj);
}
return nonstd::make_unexpected(Statistic::missing_cache_file);
}
- // MSVC compiler always print the input file name to stdout,
- // plus parts of the warnings/error messages.
- // So we have to fusion that into stderr...
- // Transform \r\n into \n. This way ninja won't produce empty newlines
- // for the /showIncludes argument.
- if (ctx.config.compiler_type() == CompilerType::cl) {
- const std::string merged_output =
- Util::read_file(tmp_stdout_path) + Util::read_file(tmp_stderr_path);
- const std::string merged_output_with_unix_line_endings =
- util::replace_all(merged_output, "\r\n", "\n");
- try {
- Util::write_file(tmp_stderr_path, merged_output_with_unix_line_endings);
- } catch (const core::Error& e) {
- LOG("Failed writing to {}: {}", tmp_stderr_path, e.what());
- return nonstd::make_unexpected(Statistic::internal_error);
- }
- }
-
// distcc-pump outputs lines like this:
// __________Using # distcc servers in pump mode
if (st.size() != 0 && ctx.config.compiler_type() != CompilerType::pump
return nonstd::make_unexpected(Statistic::compiler_produced_stdout);
}
- // Merge stderr from the preprocessor (if any) and stderr from the real
- // compiler into tmp_stderr.
+ // Merge stderr from the preprocessor (if any) and stderr from
+ // the real compiler into tmp_stderr.
if (!ctx.cpp_stderr.empty()) {
std::string combined_stderr =
Util::read_file(ctx.cpp_stderr) + Util::read_file(tmp_stderr_path);
// We can output stderr immediately instead of rerunning the compiler.
Util::send_to_fd(ctx, Util::read_file(tmp_stderr_path), STDERR_FILENO);
+ Util::send_to_fd(ctx, Util::read_file(tmp_stdout_path), STDOUT_FILENO);
auto failure = Failure(Statistic::compile_failed);
failure.set_exit_code(*status);
MTR_BEGIN("result", "result_put");
const bool added = ctx.storage.put(
*result_key, core::CacheEntryType::result, [&](const auto& path) {
- return write_result(ctx, path, obj_stat, tmp_stderr_path);
+ return write_result(
+ ctx, path, obj_stat, tmp_stdout_path, tmp_stderr_path);
});
MTR_END("result", "result_put");
if (!added) {
// Everything OK.
Util::send_to_fd(ctx, Util::read_file(tmp_stderr_path), STDERR_FILENO);
+ // Send stdout after stderr, it makes the output clearer with MSVC.
+ Util::send_to_fd(ctx, Util::read_file(tmp_stdout_path), STDOUT_FILENO);
return *result_key;
}
expect_equal_content reference.stderr test.stderr
expect_equal_content reference.d test.d
+ # -------------------------------------------------------------------------
+ TEST "No stdout"
+
+ cat <<EOF >test.c
+// just something random
+int test() { return 1; }
+EOF
+
+ stderr=$($CCACHE_COMPILE -c test.c >stdout 2>stderr)
+ expect_stat preprocessed_cache_hit 0
+ expect_stat cache_miss 1
+ expect_content stdout ""
+ expect_content stderr ""
+
+ stderr=$($CCACHE_COMPILE -c test.c >stdout 2>stderr)
+ expect_stat preprocessed_cache_hit 1
+ expect_stat cache_miss 1
+ expect_content stdout ""
+ expect_content stderr ""
+
# -------------------------------------------------------------------------
TEST "--zero-stats"