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_;
60 size_t DryRunCommandRunner::CanRunMore()
const {
64 bool DryRunCommandRunner::StartCommand(
Edge* edge) {
69 bool 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())
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");
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
293 #define MEM_FN mem_fn
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()) {
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());
610 : state_(state), config_(config), plan_(this), status_(status),
611 start_time_millis_(start_time_millis), disk_interface_(disk_interface),
613 scan_(state, build_log, deps_log, disk_interface,
614 &config_.depfile_parser_options, explanations_.get()) {
617 if (!build_dir.empty())
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) {
648 if (!depfile.empty() || (*o)->mtime() != new_mtime)
651 if (!depfile.empty())
664 *err =
"unknown target: '" + name +
"'";
673 std::vector<Node*> validation_nodes;
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() &&
707 int pending_commands = 0;
729 if (failures_allowed) {
731 while (capacity > 0) {
759 if (current_capacity < capacity)
760 capacity = current_capacity;
770 if (pending_commands) {
776 *err =
"interrupted by user";
783 if (!command_finished) {
796 if (failures_allowed)
806 if (failures_allowed == 0) {
808 *err =
"subcommands failed";
810 *err =
"subcommand failed";
812 *err =
"cannot make progress due to previous errors";
814 *err =
"stuck [this is a bug]";
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;
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) {
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);
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)
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();
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) {
1039 *err = string(
"deleting depfile: ") + strerror(errno) + string(
"\n");
1044 Fatal(
"unknown deps type '%s'", deps_type.c_str());
int64_t GetTimeMillis()
Get the current time as relative to some epoch.
#define METRIC_RECORD(name)
The primary interface to metrics.
virtual std::string LookupVariable(const std::string &var)
Options (e.g. verbosity, parallelism) passed to a build.
DepfileParserOptions depfile_parser_options
Store a log of every command ran for every build.
bool RecordCommand(Edge *edge, int start_time, int end_time, TimeStamp mtime=0)
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.
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.
Node * AddTarget(const std::string &name, std::string *err)
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...
BuildLog * build_log() const
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|.
DepsLog * deps_log() const
bool LoadDyndeps(Node *node, std::string *err) const
Load a dyndep file from the given node's path and update the build graph with the new information.
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.
bool RecordDeps(Node *node, TimeStamp mtime, const std::vector< Node * > &nodes)
Interface for accessing the disk.
virtual bool WriteFile(const std::string &path, const std::string &contents, bool crlf_on_windows)=0
Create a file, with the specified name and contents If crlf_on_windows is true, will be converted t...
bool MakeDirs(const std::string &path)
Create all the parent directories for path; like mkdir -p basename path.
virtual int RemoveFile(const std::string &path)=0
Remove the file named path.
virtual TimeStamp Stat(const std::string &path, std::string *err) const =0
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
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.
virtual Status ReadFile(const std::string &path, std::string *contents, std::string *err)=0
Read and store in given string.
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)
bool generated_by_dep_loader() const
Indicates whether this node was generated from a depfile or dyndep file, instead of being a regular i...
const std::string & path() const
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).
bool more_to_do() const
Returns true if there's more work to be done.
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 * GetNode(StringPiece path, uint64_t slash_bits)
Node * LookupNode(StringPiece path) const
Abstract interface to object that tracks the status of a build: completion fraction,...
virtual void BuildEdgeStarted(const Edge *edge, int64_t start_time_millis)=0
virtual void BuildStarted()=0
virtual void EdgeRemovedFromPlan(const Edge *edge)=0
virtual void SetExplanations(Explanations *)=0
Set the Explanations instance to use to report explanations, argument can be nullptr if no explanatio...
virtual void BuildEdgeFinished(Edge *edge, int64_t start_time_millis, int64_t end_time_millis, ExitStatus exit_code, const std::string &output)=0
virtual void EdgeAddedToPlan(const Edge *edge)=0
virtual void Error(const char *msg,...)=0
virtual void BuildFinished()=0
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.