Skip to content

Commit

Permalink
Add tools: 'outputs' and 'dynouts'
Browse files Browse the repository at this point in the history
'outputs' lists all the outputs generated by the graph, including dynamic
outputs.

'dynouts' lists all dynamic outputs stored in the deps log.

Co-authored-by: Hampus Adolfsson <[email protected]>
  • Loading branch information
Dragnalith and HampusAdolfsson committed Jun 12, 2024
1 parent 10335df commit 4ace578
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 2 deletions.
6 changes: 6 additions & 0 deletions doc/manual.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ _Available since Ninja 1.2._
`deps`:: show all dependencies stored in the `.ninja_deps` file. When given a
target, show just the target's dependencies. _Available since Ninja 1.4._
`dynouts`:: show all dynamic outputs stored in the `.ninja_deps` file. When
given a target, show just the target's outputs.
`missingdeps`:: given a list of targets, look for targets that depend on
a generated file, but do not have a properly (possibly transitive) dependency
on the generator. Such targets may cause build flakiness on clean builds.
Expand All @@ -307,6 +310,9 @@ each of them with a missing include error or equivalent pointing to the
generated file.
_Available since Ninja 1.11._
`outputs`:: list all outputs of the build graph. This includes any dynamic
outputs stored in the deps log.
`recompact`:: recompact the `.ninja_deps` file. _Available since Ninja 1.4._
`restat`:: updates all recorded file modification timestamps in the `.ninja_log`
Expand Down
89 changes: 87 additions & 2 deletions src/ninja.cc
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ struct NinjaMain : public BuildLogUser {
int ToolBrowse(const Options* options, int argc, char* argv[]);
int ToolMSVC(const Options* options, int argc, char* argv[]);
int ToolTargets(const Options* options, int argc, char* argv[]);
int ToolDynOuts(const Options* options, int argc, char* argv[]);
int ToolOutputs(const Options* options, int argc, char* argv[]);
int ToolCommands(const Options* options, int argc, char* argv[]);
int ToolInputs(const Options* options, int argc, char* argv[]);
int ToolClean(const Options* options, int argc, char* argv[]);
Expand Down Expand Up @@ -570,10 +572,11 @@ int NinjaMain::ToolDeps(const Options* options, int argc, char** argv) {
TimeStamp mtime = disk_interface.Stat((*it)->path(), &err);
if (mtime == -1)
Error("%s", err.c_str()); // Log and ignore Stat() errors;
int deps_count = deps->node_count - deps->outputs_count;
printf("%s: #deps %d, deps mtime %" PRId64 " (%s)\n",
(*it)->path().c_str(), deps->node_count, deps->mtime,
(*it)->path().c_str(), deps_count, deps->mtime,
(!mtime || mtime > deps->mtime ? "STALE":"VALID"));
for (int i = 0; i < deps->node_count; ++i)
for (int i = 0; i < deps_count; ++i)
printf(" %s\n", deps->nodes[i]->path().c_str());
printf("\n");
}
Expand Down Expand Up @@ -601,6 +604,84 @@ int NinjaMain::ToolMissingDeps(const Options* options, int argc, char** argv) {
return 0;
}

int NinjaMain::ToolDynOuts(const Options*, int argc, char** argv) {
vector<Node*> nodes;
if (argc == 0) {
for (vector<Node*>::const_iterator ni = deps_log_.nodes().begin();
ni != deps_log_.nodes().end(); ++ni) {
if (deps_log_.IsDepsEntryLiveFor(*ni))
nodes.push_back(*ni);
}
} else {
string err;
if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
Error("%s", err.c_str());
return 1;
}
}

RealDiskInterface disk_interface;
for (vector<Node*>::iterator it = nodes.begin(), end = nodes.end();
it != end; ++it) {
DepsLog::Deps* deps = deps_log_.GetDeps(*it);
if (!deps) {
printf("%s: deps not found\n", (*it)->path().c_str());
continue;
}

string err;
TimeStamp mtime = disk_interface.Stat((*it)->path(), &err);
if (mtime == -1)
Error("%s", err.c_str()); // Log and ignore Stat() errors;
int deps_count = deps->node_count - deps->outputs_count;
printf("%s: #dynouts %d, deps mtime %" PRId64 " (%s)\n",
(*it)->path().c_str(), deps->outputs_count, deps->mtime,
(!mtime || mtime > deps->mtime ? "STALE":"VALID"));
for (int i = deps_count; i < deps->node_count; ++i)
printf(" %s\n", deps->nodes[i]->path().c_str());
printf("\n");
}

return 0;
}

int NinjaMain::ToolOutputs(const Options*, int, char*[]) {
// Load dyndep files that exist, in order to load dynamic outputs
DyndepLoader dyndep_loader(&state_, &disk_interface_);
for (vector<Edge*>::iterator e = state_.edges_.begin();
e != state_.edges_.end(); ++e) {
if (Node* dyndep = (*e)->dyndep_) {
std::string err;
dyndep_loader.LoadDyndeps(dyndep, &err);
}
}

std::string err;
// Load dynamic outputs which may exist in the deps log
DepfileParserOptions depfileOptions;
ImplicitDepLoader implicit_dep_loader(&state_, &deps_log_, &disk_interface_,
&depfileOptions, nullptr);
for (vector<Edge*>::iterator e = state_.edges_.begin();
e != state_.edges_.end(); ++e) {
string dynout = (*e)->GetUnescapedDynout();

if (!dynout.empty()) {
implicit_dep_loader.LoadImplicitOutputs(*e, &err);
}
}

for (vector<Edge*>::iterator e = state_.edges_.begin();
e != state_.edges_.end(); ++e) {
for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
out_node != (*e)->outputs_.end(); ++out_node) {
printf("%s: %s\n", (*out_node)->path().c_str(),
(*e)->rule_->name().c_str());
}
}

return 0;
}

int NinjaMain::ToolTargets(const Options* options, int argc, char* argv[]) {
int depth = 1;
if (argc >= 1) {
Expand Down Expand Up @@ -1118,6 +1199,8 @@ const Tool* ChooseTool(const string& tool_name) {
Tool::RUN_AFTER_LOAD, &NinjaMain::ToolInputs},
{ "deps", "show dependencies stored in the deps log",
Tool::RUN_AFTER_LOGS, &NinjaMain::ToolDeps },
{ "dynouts", "shows dynamic outputs stored in the deps log",
Tool::RUN_AFTER_LOGS, &NinjaMain::ToolDynOuts },
{ "missingdeps", "check deps log dependencies on generated files",
Tool::RUN_AFTER_LOGS, &NinjaMain::ToolMissingDeps },
{ "graph", "output graphviz dot file for targets",
Expand All @@ -1126,6 +1209,8 @@ const Tool* ChooseTool(const string& tool_name) {
Tool::RUN_AFTER_LOGS, &NinjaMain::ToolQuery },
{ "targets", "list targets by their rule or depth in the DAG",
Tool::RUN_AFTER_LOAD, &NinjaMain::ToolTargets },
{ "outputs", "list all outputs of the build graph, including dynamic outputs stored in the deps log",
Tool::RUN_AFTER_LOGS, &NinjaMain::ToolOutputs },
{ "compdb", "dump JSON compilation database to stdout",
Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCompilationDatabase },
{ "recompact", "recompacts ninja-internal data structures",
Expand Down

0 comments on commit 4ace578

Please sign in to comment.