24#include <unordered_set>
26#if defined(__SVR4) && defined(__sun)
27#include <sys/termios.h>
52 size_t CanRunMore()
const override;
53 bool StartCommand(Edge* edge)
override;
54 bool WaitForCommand(Result* result)
override;
57 queue<Edge*> finished_;
60size_t DryRunCommandRunner::CanRunMore()
const {
64bool DryRunCommandRunner::StartCommand(Edge* edge) {
69bool DryRunCommandRunner::WaitForCommand(Result* result) {
70 if (finished_.empty())
74 result->edge = finished_.front();
100 set<Edge*>* dyndep_walk) {
111 referenced =
", needed by '" + dependent->
path() +
"',";
112 *err =
"'" + node->
path() +
"'" + referenced +
113 " missing and no known rule to make it";
123 pair<map<Edge*, Want>::iterator,
bool> want_ins =
125 Want& want = want_ins.first->second;
138 dyndep_walk->insert(edge);
140 if (!want_ins.second)
143 for (vector<Node*>::iterator i = edge->
inputs_.begin();
144 i != edge->
inputs_.end(); ++i) {
145 if (!
AddSubTarget(*i, node, err, dyndep_walk) && !err->empty())
157 builder_->status_->EdgeAddedToPlan(edge);
190 Edge* edge = want_e->first;
202 map<Edge*, Want>::iterator e =
want_.find(edge);
203 assert(e !=
want_.end());
225 for (vector<Node*>::iterator o = edge->
outputs_.begin();
236 assert(
builder_ &&
"dyndep requires Plan to have a Builder");
239 return builder_->LoadDyndeps(node, err);
243 for (vector<Edge*>::const_iterator oe = node->
out_edges().begin();
245 map<Edge*, Want>::iterator want_e =
want_.find(*oe);
246 if (want_e ==
want_.end())
257 Edge* edge = want_e->first;
274 for (vector<Edge*>::const_iterator oe = node->
out_edges().begin();
277 map<Edge*, Want>::iterator want_e =
want_.find(*oe);
282 if ((*oe)->deps_missing_)
287 vector<Node*>::iterator
288 begin = (*oe)->inputs_.begin(),
289 end = (*oe)->inputs_.end() - (*oe)->order_only_deps_;
290#if __cplusplus < 201703L
291#define MEM_FN mem_fun
297 Node* most_recent_input = NULL;
298 for (vector<Node*>::iterator i = begin; i != end; ++i) {
299 if (!most_recent_input || (*i)->
mtime() > most_recent_input->
mtime())
300 most_recent_input = *i;
306 bool outputs_dirty =
false;
308 &outputs_dirty, err)) {
311 if (!outputs_dirty) {
312 for (vector<Node*>::iterator o = (*oe)->outputs_.begin();
313 o != (*oe)->outputs_.end(); ++o) {
320 if (!(*oe)->is_phony()) {
323 builder_->status_->EdgeRemovedFromPlan(*oe);
344 std::vector<DyndepFile::const_iterator> dyndep_roots;
345 for (DyndepFile::const_iterator oe = ddf.begin(); oe != ddf.end(); ++oe) {
346 Edge* edge = oe->first;
352 map<Edge*, Want>::iterator want_e =
want_.find(edge);
356 if (want_e ==
want_.end())
360 dyndep_roots.push_back(oe);
364 std::set<Edge*> dyndep_walk;
365 for (std::vector<DyndepFile::const_iterator>::iterator
366 oei = dyndep_roots.begin(); oei != dyndep_roots.end(); ++oei) {
367 DyndepFile::const_iterator oe = *oei;
368 for (vector<Node*>::const_iterator i = oe->second.implicit_inputs_.begin();
369 i != oe->second.implicit_inputs_.end(); ++i) {
370 if (!
AddSubTarget(*i, oe->first->outputs_[0], err, &dyndep_walk) &&
378 for (vector<Edge*>::const_iterator oe = node->
out_edges().begin();
380 map<Edge*, Want>::iterator want_e =
want_.find(*oe);
381 if (want_e ==
want_.end())
383 dyndep_walk.insert(want_e->first);
387 for (set<Edge*>::iterator wi = dyndep_walk.begin();
388 wi != dyndep_walk.end(); ++wi) {
389 map<Edge*, Want>::iterator want_e =
want_.find(*wi);
390 if (want_e ==
want_.end())
403 set<Node*> dependents;
408 for (set<Node*>::iterator i = dependents.begin();
409 i != dependents.end(); ++i) {
413 std::vector<Node*> validation_nodes;
419 for (std::vector<Node*>::iterator v = validation_nodes.begin();
420 v != validation_nodes.end(); ++v) {
421 if (
Edge* in_edge = (*v)->in_edge()) {
422 if (!in_edge->outputs_ready() &&
436 map<Edge*, Want>::iterator want_e =
want_.find(edge);
437 assert(want_e !=
want_.end());
447 for (vector<Edge*>::const_iterator oe = node->
out_edges().begin();
451 map<Edge*, Want>::iterator want_e =
want_.find(edge);
452 if (want_e ==
want_.end())
457 for (vector<Node*>::iterator o = edge->
outputs_.begin();
459 if (dependents->insert(*o).second)
492 void VisitTarget(
const Node* target) {
498 const std::vector<Edge*>& result()
const {
return sorted_edges_; }
514 void Visit(
Edge* edge) {
515 auto insertion = visited_set_.emplace(edge);
516 if (!insertion.second)
524 sorted_edges_.push_back(edge);
527 std::unordered_set<Edge*> visited_set_;
528 std::vector<Edge*> sorted_edges_;
533 topo_sort.VisitTarget(target);
536 const auto& sorted_edges = topo_sort.result();
539 for (
Edge* edge : sorted_edges)
545 for (
auto reverse_it = sorted_edges.rbegin();
546 reverse_it != sorted_edges.rend(); ++reverse_it) {
547 Edge* edge = *reverse_it;
556 int64_t candidate_weight = edge_weight + EdgeWeightHeuristic(producer);
557 if (candidate_weight > producer_weight)
566 std::set<Pool*> pools;
568 for (std::map<Edge*, Plan::Want>::iterator it =
want_.begin(),
569 end =
want_.end(); it != end; ++it) {
570 Edge* edge = it->first;
586 for (std::set<Pool*>::iterator it=pools.begin(),
587 end = pools.end(); it != end; ++it) {
588 (*it)->RetrieveReadyEdges(&
ready_);
598 printf(
"pending: %d\n", (
int)
want_.size());
599 for (map<Edge*, Want>::const_iterator e =
want_.begin(); e !=
want_.end(); ++e) {
604 printf(
"ready: %d\n", (
int)
ready_.size());
613 scan_(state, build_log, deps_log, disk_interface,
616 string build_dir =
state_->bindings_.LookupVariable(
"builddir");
617 if (!build_dir.empty())
624 status_->SetExplanations(
nullptr);
632 for (vector<Edge*>::iterator e = active_edges.begin();
633 e != active_edges.end(); ++e) {
634 string depfile = (*e)->GetUnescapedDepfile();
635 for (vector<Node*>::iterator o = (*e)->outputs_.begin();
636 o != (*e)->outputs_.end(); ++o) {
647 status_->Error(
"%s", err.c_str());
648 if (!depfile.empty() || (*o)->mtime() != new_mtime)
651 if (!depfile.empty())
664 *err =
"unknown target: '" + name +
"'";
673 std::vector<Node*> validation_nodes;
674 if (!
scan_.RecomputeDirty(target, &validation_nodes, err))
677 Edge* in_edge = target->
in_edge();
679 if (!
plan_.AddTarget(target, err)) {
686 for (std::vector<Node*>::iterator n = validation_nodes.begin();
687 n != validation_nodes.end(); ++n) {
688 if (Edge* validation_in_edge = (*n)->in_edge()) {
689 if (!validation_in_edge->outputs_ready() &&
690 !
plan_.AddTarget(*n, err)) {
700 return !
plan_.more_to_do();
705 plan_.PrepareQueue();
707 int pending_commands = 0;
708 int failures_allowed =
config_.failures_allowed;
727 while (
plan_.more_to_do()) {
729 if (failures_allowed) {
731 while (capacity > 0) {
737 scan_.build_log()->Close();
759 if (current_capacity < capacity)
760 capacity = current_capacity;
766 if (pending_commands == 0 && !
plan_.more_to_do())
break;
770 if (pending_commands) {
776 *err =
"interrupted by user";
783 if (!command_finished) {
796 if (failures_allowed)
806 if (failures_allowed == 0) {
807 if (
config_.failures_allowed > 1)
808 *err =
"subcommands failed";
810 *err =
"subcommand failed";
811 }
else if (failures_allowed <
config_.failures_allowed)
812 *err =
"cannot make progress due to previous errors";
814 *err =
"stuck [this is a bug]";
831 status_->BuildEdgeStarted(edge, start_time_millis);
838 for (vector<Node*>::iterator o = edge->
outputs_.begin();
842 if (build_start == -1) {
845 if (build_start == -1)
861 if (!rspfile.empty()) {
862 string content = edge->
GetBinding(
"rspfile_content");
886 vector<Node*> deps_nodes;
888 const string deps_prefix = edge->
GetBinding(
"msvc_deps_prefix");
889 if (!deps_type.empty()) {
891 if (!
ExtractDeps(result, deps_type, deps_prefix, &deps_nodes,
894 if (!result->
output.empty())
895 result->
output.append(
"\n");
896 result->
output.append(extract_err);
901 int64_t start_time_millis, end_time_millis;
903 start_time_millis = it->second;
907 status_->BuildEdgeFinished(edge, start_time_millis, end_time_millis,
920 bool node_cleaned =
false;
928 if (record_mtime == 0 || restat || generator) {
929 for (vector<Node*>::iterator o = edge->
outputs_.begin();
934 if (new_mtime > record_mtime)
935 record_mtime = new_mtime;
936 if ((*o)->mtime() == new_mtime && restat) {
959 if (
scan_.build_log()) {
960 if (!
scan_.build_log()->RecordCommand(
961 edge,
static_cast<int>(start_time_millis),
962 static_cast<int>(end_time_millis), record_mtime)) {
963 *err = string(
"Error writing to build log: ") + strerror(errno);
968 if (!deps_type.empty() && !
config_.dry_run) {
969 assert(!edge->
outputs_.empty() &&
"should have been rejected by parser");
970 for (std::vector<Node*>::const_iterator o = edge->
outputs_.begin();
973 if (deps_mtime == -1)
975 if (!
scan_.deps_log()->RecordDeps(*o, deps_mtime, deps_nodes)) {
976 *err = std::string(
"Error writing to deps log: ") + strerror(errno);
985 const string& deps_type,
986 const string& deps_prefix,
987 vector<Node*>* deps_nodes,
989 if (deps_type ==
"msvc") {
992 if (!parser.
Parse(result->
output, deps_prefix, &output, err))
995 for (set<string>::iterator i = parser.
includes_.begin();
1001 deps_nodes->push_back(
state_->GetNode(*i, ~0u));
1003 }
else if (deps_type ==
"gcc") {
1005 if (depfile.empty()) {
1006 *err = string(
"edge with deps=gcc but no depfile makes no sense");
1021 if (content.empty())
1025 if (!deps.
Parse(&content, err))
1029 deps_nodes->reserve(deps.
ins_.size());
1030 for (vector<StringPiece>::iterator i = deps.
ins_.begin();
1031 i != deps.
ins_.end(); ++i) {
1034 deps_nodes->push_back(
state_->GetNode(*i, slash_bits));
1039 *err = string(
"deleting depfile: ") + strerror(errno) + string(
"\n");
1044 Fatal(
"unknown deps type '%s'", deps_type.c_str());
1053 if (!
scan_.LoadDyndeps(node, &ddf, err))
1057 if (!
plan_.DyndepsLoaded(&
scan_, node, ddf, err))
int64_t GetTimeMillis()
Get the current time as relative to some epoch.
#define METRIC_RECORD(name)
The primary interface to metrics.
Options (e.g. verbosity, parallelism) passed to a build.
Store a log of every command ran for every build.
Builder wraps the build process: starting commands, updating status.
std::unique_ptr< Jobserver::Client > jobserver_
std::string lock_file_path_
void SetFailureCode(ExitStatus code)
Builder(State *state, const BuildConfig &config, BuildLog *build_log, DepsLog *deps_log, DiskInterface *disk_interface, Status *status, int64_t start_time_millis)
void Cleanup()
Clean up after interrupted commands by deleting output files.
Node * AddTarget(const std::string &name, std::string *err)
int64_t start_time_millis_
Time the build started.
bool ExtractDeps(CommandRunner::Result *result, const std::string &deps_type, const std::string &deps_prefix, std::vector< Node * > *deps_nodes, std::string *err)
bool FinishCommand(CommandRunner::Result *result, std::string *err)
Update status ninja logs following a command termination.
ExitStatus GetExitCode() const
Returns ExitStatus or the exit code of the last failed job (doesn't need to be an enum value of ExitS...
RunningEdgeMap running_edges_
const BuildConfig & config_
DiskInterface * disk_interface_
bool AlreadyUpToDate() const
Returns true if the build targets are already up to date.
ExitStatus Build(std::string *err)
Run the build.
bool StartEdge(Edge *edge, std::string *err)
std::unique_ptr< CommandRunner > command_runner_
ExitStatus exit_code_
Keep the global exit code for the build.
std::unique_ptr< Explanations > explanations_
bool LoadDyndeps(Node *node, std::string *err)
Load the dyndep information provided by the given node.
Visual Studio's cl.exe requires some massaging to work with Ninja; for example, it emits include info...
std::set< std::string > includes_
bool Parse(const std::string &output, const std::string &deps_prefix, std::string *filtered_output, std::string *err)
Parse the full output of cl, filling filtered_output with the text that should be printed (if any).
The result of waiting for a command.
CommandRunner is an interface that wraps running the build subcommands.
static CommandRunner * factory(const BuildConfig &config, Jobserver::Client *jobserver)
Creates the RealCommandRunner.
DependencyScan manages the process of scanning the files in a graph and updating the dirty/outputs_re...
bool RecomputeOutputsDirty(Edge *edge, Node *most_recent_input, bool *dirty, std::string *err)
Recompute whether any output of the edge is dirty, if so sets |*dirty|.
bool RecomputeDirty(Node *node, std::vector< Node * > *validation_nodes, std::string *err)
Update the |dirty_| state of the given nodes by transitively inspecting their input edges.
Parser for the dependency information emitted by gcc's -M flags.
bool Parse(std::string *content, std::string *err)
Parse an input file.
std::vector< StringPiece > ins_
As build commands run they can output extra dependency information (e.g.
Interface for accessing the disk.
Store data loaded from one dyndep file.
An edge in the dependency graph; links between Nodes using Rules.
std::string GetBinding(const std::string &key) const
Returns the shell-escaped value of |key|.
int64_t critical_path_weight() const
std::vector< Node * > outputs_
Jobserver::Slot job_slot_
A Jobserver slot instance. Invalid by default.
bool outputs_ready() const
void set_critical_path_weight(int64_t critical_path_weight)
bool GetBindingBool(const std::string &key) const
TimeStamp command_start_time_
std::string EvaluateCommand(bool incl_rsp_file=false) const
Expand all variables in a command and return it as a string.
std::vector< Node * > inputs_
std::string GetUnescapedRspfile() const
Like GetBinding("rspfile"), but without shell escaping.
std::string GetUnescapedDepfile() const
Like GetBinding("depfile"), but without shell escaping.
bool AllInputsReady() const
Return true if all inputs' in-edges are ready.
A class used to record a list of explanation strings associated with a given 'item' pointer.
bool IsValid() const
Return true if this instance is valid, i.e.
Information about a node in the dependency graph: the file, whether it's dirty, mtime,...
void set_dirty(bool dirty)
const std::string & path() const
bool generated_by_dep_loader() const
Indicates whether this node was generated from a depfile or dyndep file, instead of being a regular i...
bool dyndep_pending() const
const std::vector< Edge * > & out_edges() const
bool AddSubTarget(const Node *node, const Node *dependent, std::string *err, std::set< Edge * > *dyndep_walk)
int command_edges_
Total number of edges that have commands (not phony).
void Reset()
Reset state. Clears want and ready sets.
bool EdgeMaybeReady(std::map< Edge *, Want >::iterator want_e, std::string *err)
bool DyndepsLoaded(DependencyScan *scan, const Node *node, const DyndepFile &ddf, std::string *err)
Update the build plan to account for modifications made to the graph by information loaded from a dyn...
void ScheduleInitialEdges()
bool AddTarget(const Node *target, std::string *err)
Add a target to our plan (including all its dependencies).
int wanted_edges_
Total remaining number of wanted edges.
void Dump() const
Dumps the current state of the plan.
bool RefreshDyndepDependents(DependencyScan *scan, const Node *node, std::string *err)
Want
Enumerate possible steps we want for an edge.
@ kWantNothing
We do not want to build the edge, but we might want to build one of its dependents.
@ kWantToFinish
We want to build the edge, have scheduled it, and are waiting for it to complete.
@ kWantToStart
We want to build the edge, but have not yet scheduled it.
void ScheduleWork(std::map< Edge *, Want >::iterator want_e)
Submits a ready edge as a candidate for execution.
std::map< Edge *, Want > want_
Keep track of which edges we want to build in this plan.
void ComputeCriticalPath()
void EdgeWanted(const Edge *edge)
std::vector< const Node * > targets_
user provided targets in build order, earlier one have higher priority
void UnmarkDependents(const Node *node, std::set< Node * > *dependents)
bool EdgeFinished(Edge *edge, EdgeResult result, std::string *err)
Mark an edge as done building (whether it succeeded or failed).
Plan(Builder *builder=NULL)
bool CleanNode(DependencyScan *scan, Node *node, std::string *err)
Clean the given node during the build.
bool NodeFinished(Node *node, std::string *err)
Update plan with knowledge that the given node is up to date.
A pool for delayed edges.
bool ShouldDelayEdge() const
true if the Pool might delay this edge
void DelayEdge(Edge *edge)
adds the given edge to this Pool to be delayed.
void RetrieveReadyEdges(EdgePriorityQueue *ready_queue)
Pool will add zero or more edges to the ready_queue.
void EdgeScheduled(const Edge &edge)
informs this Pool that the given edge is committed to be run.
void EdgeFinished(const Edge &edge)
informs this Pool that the given edge is no longer runnable, and should relinquish its resources back...
Global state (file status) for a single run.
Node * LookupNode(StringPiece path) const
Abstract interface to object that tracks the status of a build: completion fraction,...
void CanonicalizePath(string *path, uint64_t *slash_bits)
void Fatal(const char *msg,...)
Log a fatal message and exit.
unsigned long long uint64_t
signed long long int64_t
A 64-bit integer type.