Skip to content

Commit 4ace578

Browse files
Add tools: 'outputs' and 'dynouts'
'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]>
1 parent 10335df commit 4ace578

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

doc/manual.asciidoc

+6
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,9 @@ _Available since Ninja 1.2._
292292
`deps`:: show all dependencies stored in the `.ninja_deps` file. When given a
293293
target, show just the target's dependencies. _Available since Ninja 1.4._
294294
295+
`dynouts`:: show all dynamic outputs stored in the `.ninja_deps` file. When
296+
given a target, show just the target's outputs.
297+
295298
`missingdeps`:: given a list of targets, look for targets that depend on
296299
a generated file, but do not have a properly (possibly transitive) dependency
297300
on the generator. Such targets may cause build flakiness on clean builds.
@@ -307,6 +310,9 @@ each of them with a missing include error or equivalent pointing to the
307310
generated file.
308311
_Available since Ninja 1.11._
309312
313+
`outputs`:: list all outputs of the build graph. This includes any dynamic
314+
outputs stored in the deps log.
315+
310316
`recompact`:: recompact the `.ninja_deps` file. _Available since Ninja 1.4._
311317
312318
`restat`:: updates all recorded file modification timestamps in the `.ninja_log`

src/ninja.cc

+87-2
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ struct NinjaMain : public BuildLogUser {
125125
int ToolBrowse(const Options* options, int argc, char* argv[]);
126126
int ToolMSVC(const Options* options, int argc, char* argv[]);
127127
int ToolTargets(const Options* options, int argc, char* argv[]);
128+
int ToolDynOuts(const Options* options, int argc, char* argv[]);
129+
int ToolOutputs(const Options* options, int argc, char* argv[]);
128130
int ToolCommands(const Options* options, int argc, char* argv[]);
129131
int ToolInputs(const Options* options, int argc, char* argv[]);
130132
int ToolClean(const Options* options, int argc, char* argv[]);
@@ -570,10 +572,11 @@ int NinjaMain::ToolDeps(const Options* options, int argc, char** argv) {
570572
TimeStamp mtime = disk_interface.Stat((*it)->path(), &err);
571573
if (mtime == -1)
572574
Error("%s", err.c_str()); // Log and ignore Stat() errors;
575+
int deps_count = deps->node_count - deps->outputs_count;
573576
printf("%s: #deps %d, deps mtime %" PRId64 " (%s)\n",
574-
(*it)->path().c_str(), deps->node_count, deps->mtime,
577+
(*it)->path().c_str(), deps_count, deps->mtime,
575578
(!mtime || mtime > deps->mtime ? "STALE":"VALID"));
576-
for (int i = 0; i < deps->node_count; ++i)
579+
for (int i = 0; i < deps_count; ++i)
577580
printf(" %s\n", deps->nodes[i]->path().c_str());
578581
printf("\n");
579582
}
@@ -601,6 +604,84 @@ int NinjaMain::ToolMissingDeps(const Options* options, int argc, char** argv) {
601604
return 0;
602605
}
603606

607+
int NinjaMain::ToolDynOuts(const Options*, int argc, char** argv) {
608+
vector<Node*> nodes;
609+
if (argc == 0) {
610+
for (vector<Node*>::const_iterator ni = deps_log_.nodes().begin();
611+
ni != deps_log_.nodes().end(); ++ni) {
612+
if (deps_log_.IsDepsEntryLiveFor(*ni))
613+
nodes.push_back(*ni);
614+
}
615+
} else {
616+
string err;
617+
if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
618+
Error("%s", err.c_str());
619+
return 1;
620+
}
621+
}
622+
623+
RealDiskInterface disk_interface;
624+
for (vector<Node*>::iterator it = nodes.begin(), end = nodes.end();
625+
it != end; ++it) {
626+
DepsLog::Deps* deps = deps_log_.GetDeps(*it);
627+
if (!deps) {
628+
printf("%s: deps not found\n", (*it)->path().c_str());
629+
continue;
630+
}
631+
632+
string err;
633+
TimeStamp mtime = disk_interface.Stat((*it)->path(), &err);
634+
if (mtime == -1)
635+
Error("%s", err.c_str()); // Log and ignore Stat() errors;
636+
int deps_count = deps->node_count - deps->outputs_count;
637+
printf("%s: #dynouts %d, deps mtime %" PRId64 " (%s)\n",
638+
(*it)->path().c_str(), deps->outputs_count, deps->mtime,
639+
(!mtime || mtime > deps->mtime ? "STALE":"VALID"));
640+
for (int i = deps_count; i < deps->node_count; ++i)
641+
printf(" %s\n", deps->nodes[i]->path().c_str());
642+
printf("\n");
643+
}
644+
645+
return 0;
646+
}
647+
648+
int NinjaMain::ToolOutputs(const Options*, int, char*[]) {
649+
// Load dyndep files that exist, in order to load dynamic outputs
650+
DyndepLoader dyndep_loader(&state_, &disk_interface_);
651+
for (vector<Edge*>::iterator e = state_.edges_.begin();
652+
e != state_.edges_.end(); ++e) {
653+
if (Node* dyndep = (*e)->dyndep_) {
654+
std::string err;
655+
dyndep_loader.LoadDyndeps(dyndep, &err);
656+
}
657+
}
658+
659+
std::string err;
660+
// Load dynamic outputs which may exist in the deps log
661+
DepfileParserOptions depfileOptions;
662+
ImplicitDepLoader implicit_dep_loader(&state_, &deps_log_, &disk_interface_,
663+
&depfileOptions, nullptr);
664+
for (vector<Edge*>::iterator e = state_.edges_.begin();
665+
e != state_.edges_.end(); ++e) {
666+
string dynout = (*e)->GetUnescapedDynout();
667+
668+
if (!dynout.empty()) {
669+
implicit_dep_loader.LoadImplicitOutputs(*e, &err);
670+
}
671+
}
672+
673+
for (vector<Edge*>::iterator e = state_.edges_.begin();
674+
e != state_.edges_.end(); ++e) {
675+
for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
676+
out_node != (*e)->outputs_.end(); ++out_node) {
677+
printf("%s: %s\n", (*out_node)->path().c_str(),
678+
(*e)->rule_->name().c_str());
679+
}
680+
}
681+
682+
return 0;
683+
}
684+
604685
int NinjaMain::ToolTargets(const Options* options, int argc, char* argv[]) {
605686
int depth = 1;
606687
if (argc >= 1) {
@@ -1118,6 +1199,8 @@ const Tool* ChooseTool(const string& tool_name) {
11181199
Tool::RUN_AFTER_LOAD, &NinjaMain::ToolInputs},
11191200
{ "deps", "show dependencies stored in the deps log",
11201201
Tool::RUN_AFTER_LOGS, &NinjaMain::ToolDeps },
1202+
{ "dynouts", "shows dynamic outputs stored in the deps log",
1203+
Tool::RUN_AFTER_LOGS, &NinjaMain::ToolDynOuts },
11211204
{ "missingdeps", "check deps log dependencies on generated files",
11221205
Tool::RUN_AFTER_LOGS, &NinjaMain::ToolMissingDeps },
11231206
{ "graph", "output graphviz dot file for targets",
@@ -1126,6 +1209,8 @@ const Tool* ChooseTool(const string& tool_name) {
11261209
Tool::RUN_AFTER_LOGS, &NinjaMain::ToolQuery },
11271210
{ "targets", "list targets by their rule or depth in the DAG",
11281211
Tool::RUN_AFTER_LOAD, &NinjaMain::ToolTargets },
1212+
{ "outputs", "list all outputs of the build graph, including dynamic outputs stored in the deps log",
1213+
Tool::RUN_AFTER_LOGS, &NinjaMain::ToolOutputs },
11291214
{ "compdb", "dump JSON compilation database to stdout",
11301215
Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCompilationDatabase },
11311216
{ "recompact", "recompacts ninja-internal data structures",

0 commit comments

Comments
 (0)