Migrate explanation printing from StatusPrinter to Explanations

It makes more sense to live in the latter.

Suggested-by: David 'Digit' Turner <digit+github@google.com>
This commit is contained in:
Brad King
2026-03-26 14:48:52 -04:00
parent 2dc18d33d7
commit 1ad778bff7
6 changed files with 57 additions and 14 deletions

View File

@@ -604,7 +604,7 @@ Builder::Builder(State* state, const BuildConfig& config, BuildLog* build_log,
Status* status, int64_t start_time_millis)
: state_(state), config_(config), plan_(this), status_(status),
start_time_millis_(start_time_millis), disk_interface_(disk_interface),
explanations_(g_explaining ? new Explanations() : nullptr),
explanations_(g_explaining ? new Explanations(status) : nullptr),
scan_(state, build_log, deps_log, disk_interface,
&config_.depfile_parser_options, explanations_.get()) {
lock_file_path_ = ".ninja_lock";

View File

@@ -21,6 +21,26 @@
#include <unordered_map>
#include <vector>
#include "graph.h"
#include "status_printer.h"
namespace {
void Explain(const char* msg, va_list ap) {
fputs("ninja explain: ", stderr);
vfprintf(stderr, msg, ap);
fputs("\n", stderr);
}
void Explain(const char* msg, ...) {
va_list ap;
va_start(ap, msg);
Explain(msg, ap);
va_end(ap);
}
} // anonymous namespace
Explanations::Explanations(Status* status) : status_(status) {}
void Explanations::Record(const void* item, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
@@ -34,6 +54,24 @@ void Explanations::RecordArgs(const void* item, const char* fmt, va_list args) {
map_[item].emplace_back(buffer);
}
void Explanations::ExplainEdge(const Edge* edge) {
// Collect all explanations for the current edge's outputs.
std::vector<std::string> explanations;
for (Node* output : edge->outputs_) {
this->LookupAndAppend(output, &explanations);
}
if (!explanations.empty()) {
if (status_) {
// Start a new line so that the first explanation
// does not append to the status line.
status_->NewLine();
}
for (const auto& exp : explanations) {
Explain("%s", exp.c_str());
}
}
}
void Explanations::LookupAndAppend(const void* item,
std::vector<std::string>* out) {
auto it = map_.find(item);

View File

@@ -20,23 +20,32 @@
#include <unordered_map>
#include <vector>
struct Edge;
struct Status;
/// A class used to record a list of explanation strings associated
/// with a given 'item' pointer. This is used to implement the
/// `-d explain` feature.
struct Explanations {
public:
Explanations(Status* status = nullptr);
/// Record an explanation for |item| if this instance is enabled.
void Record(const void* item, const char* fmt, ...);
/// Same as Record(), but uses a va_list to pass formatting arguments.
void RecordArgs(const void* item, const char* fmt, va_list args);
/// Print recorded explanations for an edge.
void ExplainEdge(const Edge* edge);
/// Lookup the explanations recorded for |item|, and append them
/// to |*out|, if any.
void LookupAndAppend(const void* item, std::vector<std::string>* out);
private:
std::unordered_map<const void*, std::vector<std::string>> map_;
Status* status_;
};
/// Convenience wrapper for an Explanations pointer, which can be null

View File

@@ -40,6 +40,9 @@ struct Status {
/// (which is the default).
virtual void SetExplanations(Explanations*) = 0;
/// Start a new line so that new output does not append to the status line.
virtual void NewLine() = 0;
virtual void Info(const char* msg, ...) = 0;
virtual void Warning(const char* msg, ...) = 0;
virtual void Error(const char* msg, ...) = 0;

View File

@@ -407,19 +407,7 @@ string StatusPrinter::FormatProgressStatus(const char* progress_status_format,
void StatusPrinter::PrintStatus(const Edge* edge, int64_t time_millis) {
if (explanations_) {
// Collect all explanations for the current edge's outputs.
std::vector<std::string> explanations;
for (Node* output : edge->outputs_) {
explanations_->LookupAndAppend(output, &explanations);
}
if (!explanations.empty()) {
// Start a new line so that the first explanation does not append to the
// status line.
printer_.PrintOnNewLine("");
for (const auto& exp : explanations) {
fprintf(stderr, "ninja explain: %s\n", exp.c_str());
}
}
explanations_->ExplainEdge(edge);
}
if (config_.verbosity == BuildConfig::QUIET
@@ -441,6 +429,10 @@ void StatusPrinter::PrintStatus(const Edge* edge, int64_t time_millis) {
force_full_command ? LinePrinter::FULL : LinePrinter::ELIDE);
}
void StatusPrinter::NewLine() {
printer_.PrintOnNewLine("");
}
void StatusPrinter::Warning(const char* msg, ...) {
va_list ap;
va_start(ap, msg);

View File

@@ -37,6 +37,7 @@ struct StatusPrinter : Status {
void BuildStarted() override;
void BuildFinished() override;
void NewLine() override;
void Info(const char* msg, ...) override;
void Warning(const char* msg, ...) override;
void Error(const char* msg, ...) override;