28 #if defined(__SVR4) && defined(__sun) 29 #include <sys/termios.h> 49 virtual ~DryRunCommandRunner() {}
52 virtual bool CanRunMore()
const;
53 virtual bool StartCommand(
Edge* edge);
54 virtual bool WaitForCommand(Result* result);
57 queue<Edge*> finished_;
60 bool DryRunCommandRunner::CanRunMore()
const {
64 bool DryRunCommandRunner::StartCommand(
Edge* edge) {
69 bool DryRunCommandRunner::WaitForCommand(Result* result) {
70 if (finished_.empty())
74 result->edge = finished_.front();
82 : config_(config), start_time_millis_(
GetTimeMillis()), started_edges_(0),
83 finished_edges_(0), total_edges_(0), progress_status_format_(NULL),
84 current_rate_(config.parallelism) {
113 const string& output,
121 *start_time = i->second;
137 for (vector<Node*>::const_iterator o = edge->
outputs_.begin();
139 outputs += (*o)->path() +
" ";
149 if (!output.empty()) {
165 final_output = output;
169 _setmode(_fileno(stdout), _O_BINARY);
175 _setmode(_fileno(stdout), _O_TEXT);
205 const char* progress_status_format,
EdgeStatus status)
const {
209 for (
const char* s = progress_status_format; *s !=
'\0'; ++s) {
235 snprintf(buf,
sizeof(buf),
"%d", running_edges);
269 snprintf(buf,
sizeof(buf),
"%3i%%", percent);
275 snprintf(buf,
sizeof(buf),
"%.3f", elapsed);
281 Fatal(
"unknown placeholder '%%%c' in $NINJA_STATUS", *s);
298 string to_print = edge->
GetBinding(
"description");
299 if (to_print.empty() || force_full_command)
326 set<Edge*>* dyndep_walk) {
332 referenced =
", needed by '" + dependent->
path() +
"',";
333 *err =
"'" + node->
path() +
"'" + referenced +
" missing " 334 "and no known rule to make it";
344 pair<map<Edge*, Want>::iterator,
bool> want_ins =
346 Want& want = want_ins.first->second;
361 dyndep_walk->insert(edge);
363 if (!want_ins.second)
366 for (vector<Node*>::iterator i = edge->
inputs_.begin();
367 i != edge->
inputs_.end(); ++i) {
368 if (!
AddSubTarget(*i, node, err, dyndep_walk) && !err->empty())
384 set<Edge*>::iterator e =
ready_.begin();
401 Edge* edge = want_e->first;
413 map<Edge*, Want>::iterator e =
want_.find(edge);
414 assert(e !=
want_.end());
432 for (vector<Node*>::iterator o = edge->
outputs_.begin();
443 assert(
builder_ &&
"dyndep requires Plan to have a Builder");
450 for (vector<Edge*>::const_iterator oe = node->
out_edges().begin();
452 map<Edge*, Want>::iterator want_e =
want_.find(*oe);
453 if (want_e ==
want_.end())
464 Edge* edge = want_e->first;
481 for (vector<Edge*>::const_iterator oe = node->
out_edges().begin();
484 map<Edge*, Want>::iterator want_e =
want_.find(*oe);
489 if ((*oe)->deps_missing_)
494 vector<Node*>::iterator
495 begin = (*oe)->inputs_.begin(),
496 end = (*oe)->inputs_.end() - (*oe)->order_only_deps_;
497 #if __cplusplus < 201703L 498 #define MEM_FN mem_fun 500 #define MEM_FN mem_fn // mem_fun was removed in C++17. 504 Node* most_recent_input = NULL;
505 for (vector<Node*>::iterator i = begin; i != end; ++i) {
506 if (!most_recent_input || (*i)->
mtime() > most_recent_input->
mtime())
507 most_recent_input = *i;
513 bool outputs_dirty =
false;
515 &outputs_dirty, err)) {
518 if (!outputs_dirty) {
519 for (vector<Node*>::iterator o = (*oe)->outputs_.begin();
520 o != (*oe)->outputs_.end(); ++o) {
527 if (!(*oe)->is_phony())
548 std::vector<DyndepFile::const_iterator> dyndep_roots;
549 for (DyndepFile::const_iterator oe = ddf.begin(); oe != ddf.end(); ++oe) {
550 Edge* edge = oe->first;
556 map<Edge*, Want>::iterator want_e =
want_.find(edge);
560 if (want_e ==
want_.end())
564 dyndep_roots.push_back(oe);
568 std::set<Edge*> dyndep_walk;
569 for (std::vector<DyndepFile::const_iterator>::iterator
570 oei = dyndep_roots.begin(); oei != dyndep_roots.end(); ++oei) {
571 DyndepFile::const_iterator oe = *oei;
572 for (vector<Node*>::const_iterator i = oe->second.implicit_inputs_.begin();
573 i != oe->second.implicit_inputs_.end(); ++i) {
574 if (!
AddSubTarget(*i, oe->first->outputs_[0], err, &dyndep_walk) &&
582 for (vector<Edge*>::const_iterator oe = node->
out_edges().begin();
584 map<Edge*, Want>::iterator want_e =
want_.find(*oe);
585 if (want_e ==
want_.end())
587 dyndep_walk.insert(want_e->first);
591 for (set<Edge*>::iterator wi = dyndep_walk.begin();
592 wi != dyndep_walk.end(); ++wi) {
593 map<Edge*, Want>::iterator want_e =
want_.find(*wi);
594 if (want_e ==
want_.end())
607 set<Node*> dependents;
612 for (set<Node*>::iterator i = dependents.begin();
613 i != dependents.end(); ++i) {
627 map<Edge*, Want>::iterator want_e =
want_.find(edge);
628 assert(want_e !=
want_.end());
638 for (vector<Edge*>::const_iterator oe = node->
out_edges().begin();
642 map<Edge*, Want>::iterator want_e =
want_.find(edge);
643 if (want_e ==
want_.end())
648 for (vector<Node*>::iterator o = edge->
outputs_.begin();
650 if (dependents->insert(*o).second)
658 printf(
"pending: %d\n", (
int)
want_.size());
659 for (map<Edge*, Want>::const_iterator e =
want_.begin(); e !=
want_.end(); ++e) {
664 printf(
"ready: %d\n", (
int)
ready_.size());
674 virtual void Abort();
685 edges.push_back(e->second);
694 size_t subproc_number =
723 result->
edge = e->second;
733 : state_(state), config_(config),
734 plan_(this), disk_interface_(disk_interface),
735 scan_(state, build_log, deps_log, disk_interface,
736 &config_.depfile_parser_options) {
749 for (vector<Edge*>::iterator e = active_edges.begin();
750 e != active_edges.end(); ++e) {
751 string depfile = (*e)->GetUnescapedDepfile();
752 for (vector<Node*>::iterator o = (*e)->outputs_.begin();
753 o != (*e)->outputs_.end(); ++o) {
764 Error(
"%s", err.c_str());
765 if (!depfile.empty() || (*o)->mtime() != new_mtime)
768 if (!depfile.empty())
777 *err =
"unknown target: '" + name +
"'";
790 if (in_edge->outputs_ready())
808 int pending_commands = 0;
857 if (pending_commands) {
863 *err =
"interrupted by user";
875 if (failures_allowed)
885 if (failures_allowed == 0) {
887 *err =
"subcommands failed";
889 *err =
"subcommand failed";
891 *err =
"cannot make progress due to previous errors";
893 *err =
"stuck [this is a bug]";
911 for (vector<Node*>::iterator o = edge->
outputs_.begin();
920 if (!rspfile.empty()) {
921 string content = edge->
GetBinding(
"rspfile_content");
945 vector<Node*> deps_nodes;
947 const string deps_prefix = edge->
GetBinding(
"msvc_deps_prefix");
948 if (!deps_type.empty()) {
950 if (!
ExtractDeps(result, deps_type, deps_prefix, &deps_nodes,
953 if (!result->
output.empty())
954 result->
output.append(
"\n");
955 result->
output.append(extract_err);
960 int start_time, end_time;
962 &start_time, &end_time);
973 bool node_cleaned =
false;
975 for (vector<Node*>::iterator o = edge->
outputs_.begin();
980 if (new_mtime > output_mtime)
981 output_mtime = new_mtime;
982 if ((*o)->mtime() == new_mtime && restat) {
996 for (vector<Node*>::iterator i = edge->
inputs_.begin();
999 if (input_mtime == -1)
1001 if (input_mtime > restat_mtime)
1002 restat_mtime = input_mtime;
1006 if (restat_mtime != 0 && deps_type.empty() && !depfile.empty()) {
1008 if (depfile_mtime == -1)
1010 if (depfile_mtime > restat_mtime)
1011 restat_mtime = depfile_mtime;
1018 output_mtime = restat_mtime;
1033 *err = string(
"Error writing to build log: ") + strerror(errno);
1039 assert(!edge->
outputs_.empty() &&
"should have been rejected by parser");
1040 for (std::vector<Node*>::const_iterator o = edge->
outputs_.begin();
1043 if (deps_mtime == -1)
1046 *err = std::string(
"Error writing to deps log: ") + strerror(errno);
1055 const string& deps_type,
1056 const string& deps_prefix,
1057 vector<Node*>* deps_nodes,
1059 if (deps_type ==
"msvc") {
1062 if (!parser.
Parse(result->
output, deps_prefix, &output, err))
1065 for (set<string>::iterator i = parser.
includes_.begin();
1073 }
else if (deps_type ==
"gcc") {
1075 if (depfile.empty()) {
1076 *err = string(
"edge with deps=gcc but no depfile makes no sense");
1091 if (content.empty())
1095 if (!deps.
Parse(&content, err))
1099 deps_nodes->reserve(deps.
ins_.size());
1100 for (vector<StringPiece>::iterator i = deps.
ins_.begin();
1101 i != deps.
ins_.end(); ++i) {
1111 *err = string(
"deleting depfile: ") + strerror(errno) + string(
"\n");
1116 Fatal(
"unknown deps type '%s'", deps_type.c_str());
Subprocess * Add(const std::string &command, bool use_console=false)
SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
bool dyndep_pending() const
bool Build(std::string *err)
Run the build.
void RetrieveReadyEdges(std::set< Edge *> *ready_queue)
Pool will add zero or more edges to the ready_queue.
std::queue< Subprocess * > finished_
bool RefreshDyndepDependents(DependencyScan *scan, const Node *node, std::string *err)
bool supports_color() const
CommandRunner is an interface that wraps running the build subcommands.
std::auto_ptr< CommandRunner > command_runner_
bool RecordCommand(Edge *edge, int start_time, int end_time, TimeStamp mtime=0)
We do not want to build the edge, but we might want to build one of its dependents.
BuildStatus(const BuildConfig &config)
virtual ~RealCommandRunner()
void Print(std::string to_print, LineType type)
Overprints the current line.
virtual bool WriteFile(const std::string &path, const std::string &contents)=0
Create a file, with the specified name and contents Returns true on success, false on failure...
Store data loaded from one dyndep file.
Subprocess * NextFinished()
double max_load_average
The maximum load average we must not exceed.
Parser for the dependency information emitted by gcc's -M flags.
bool CanonicalizePath(string *path, uint64_t *slash_bits, string *err)
SlidingRateInfo current_rate_
void EdgeScheduled(const Edge &edge)
informs this Pool that the given edge is committed to be run.
Node * GetNode(StringPiece path, uint64_t slash_bits)
void BuildEdgeFinished(Edge *edge, bool success, const std::string &output, int *start_time, int *end_time)
void UpdateRate(int edges)
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|.
The result of waiting for a command.
std::set< Edge * > ready_
void set_dirty(bool dirty)
virtual int RemoveFile(const std::string &path)=0
Remove the file named path.
std::string FormatProgressStatus(const char *progress_status_format, EdgeStatus status) const
Format the progress status string by replacing the placeholders.
Information about a node in the dependency graph: the file, whether it's dirty, mtime, etc.
virtual bool StartCommand(Edge *edge)
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...
bool Parse(std::string *content, std::string *err)
Parse an input file.
bool RecomputeDirty(Node *node, std::string *err)
Update the |dirty_| state of the given node by inspecting its input edge.
bool outputs_ready() const
Interface for accessing the disk.
const BuildConfig & config_
int64_t GetTimeMillis()
Get the current time as relative to some epoch.
Plan(Builder *builder=NULL)
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...
std::vector< Node * > outputs_
const BuildConfig & config_
bool StartEdge(Edge *edge, std::string *err)
void Dump() const
Dumps the current state of the plan.
int command_edge_count() const
Number of edges with commands to run.
An edge in the dependency graph; links between Nodes using Rules.
void UpdateRate(int update_hint)
Node * LookupNode(StringPiece path) const
Store a log of every command ran for every build.
virtual bool WaitForCommand(Result *result)
Wait for a command to complete, or return false if interrupted.
const BuildConfig & config_
const std::string & path() const
DiskInterface * disk_interface_
std::map< Edge *, Want > want_
Keep track of which edges we want to build in this plan.
ExitStatus Finish()
Returns ExitSuccess on successful process exit, ExitInterrupted if the process was interrupted...
void ScheduleWork(std::map< Edge *, Want >::iterator want_e)
Submits a ready edge as a candidate for execution.
bool AddSubTarget(const Node *node, const Node *dependent, std::string *err, std::set< Edge *> *dyndep_walk)
Want
Enumerate possible steps we want for an edge.
As build commands run they can output extra dependency information (e.g.
signed long long int64_t
A 64-bit integer type.
Builder(State *state, const BuildConfig &config, BuildLog *build_log, DepsLog *deps_log, DiskInterface *disk_interface)
Subprocess wraps a single async subprocess.
bool RecordDeps(Node *node, TimeStamp mtime, const std::vector< Node *> &nodes)
void Reset()
Reset state. Clears want and ready sets.
bool ExtractDeps(CommandRunner::Result *result, const std::string &deps_type, const std::string &deps_prefix, std::vector< Node *> *deps_nodes, std::string *err)
std::set< std::string > includes_
bool AddTarget(const Node *node, std::string *err)
Add a target to our plan (including all its dependencies).
virtual vector< Edge * > GetActiveEdges()
Node * AddTarget(const std::string &name, std::string *err)
int64_t start_time_millis_
Time the build started.
void PrintStatus(const Edge *edge, EdgeStatus status)
std::vector< StringPiece > ins_
std::string GetUnescapedRspfile() const
Like GetBinding("rspfile"), but without shell escaping.
int wanted_edges_
Total remaining number of wanted edges.
map< const Subprocess *, Edge * > subproc_to_edge_
DepsLog * deps_log() const
void set_smart_terminal(bool smart)
BuildLog * build_log() const
void DelayEdge(Edge *edge)
adds the given edge to this Pool to be delayed.
void Cleanup()
Clean up after interrupted commands by deleting output files.
A pool for delayed edges.
bool EdgeMaybeReady(std::map< Edge *, Want >::iterator want_e, std::string *err)
void SetConsoleLocked(bool locked)
Lock or unlock the console.
We want to build the edge, but have not yet scheduled it.
bool ShouldDelayEdge() const
true if the Pool might delay this edge
#define METRIC_RECORD(name)
The primary interface to metrics.
std::vector< Node * > inputs_
std::string GetUnescapedDepfile() const
Like GetBinding("depfile"), but without shell escaping.
Builder wraps the build process: starting commands, updating status.
bool LoadDyndeps(Node *node, std::string *err)
Load the dyndep information provided by the given node.
bool EdgeFinished(Edge *edge, EdgeResult result, std::string *err)
Mark an edge as done building (whether it succeeded or failed).
void PlanHasTotalEdges(int total)
std::string GetBinding(const std::string &key) const
Returns the shell-escaped value of |key|.
bool is_smart_terminal() const
string StripAnsiEscapeCodes(const string &in)
void Fatal(const char *msg,...)
Log a fatal message and exit.
Tracks the status of a build: completion fraction, printing updates.
virtual Status ReadFile(const std::string &path, std::string *contents, std::string *err)=0
Read and store in given string.
void SnprintfRate(double rate, char(&buf)[S], const char *format) const
const char * progress_status_format_
The custom progress status format to use.
bool NodeFinished(Node *node, std::string *err)
Update plan with knowledge that the given node is up to date.
Visual Studio's cl.exe requires some massaging to work with Ninja; for example, it emits include info...
DependencyScan manages the process of scanning the files in a graph and updating the dirty/outputs_re...
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)...
bool MakeDirs(const std::string &path)
Create all the parent directories for path; like mkdir -p basename path.
const std::string & GetOutput() const
std::string EvaluateCommand(bool incl_rsp_file=false) const
Expand all variables in a command and return it as a string.
bool AllInputsReady() const
Return true if all inputs' in-edges are ready.
void EdgeFinished(const Edge &edge)
informs this Pool that the given edge is no longer runnable, and should relinquish its resources back...
const std::vector< Edge * > & out_edges() const
void EdgeWanted(const Edge *edge)
Options (e.g. verbosity, parallelism) passed to a build.
Global state (file status) for a single run.
We want to build the edge, have scheduled it, and are waiting for it to complete. ...
bool CleanNode(DependencyScan *scan, Node *node, std::string *err)
Clean the given node during the build.
unsigned long long uint64_t
virtual bool CanRunMore() const
RunningEdgeMap running_edges_
bool more_to_do() const
Returns true if there's more work to be done.
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.
bool GetBindingBool(const std::string &key) const
DepfileParserOptions depfile_parser_options
void PrintOnNewLine(const std::string &to_print)
Prints a string on a new line, not overprinting previous output.
std::vector< Subprocess * > running_
bool AlreadyUpToDate() const
Returns true if the build targets are already up to date.
LinePrinter printer_
Prints progress output.
int command_edges_
Total number of edges that have commands (not phony).
void UnmarkDependents(const Node *node, std::set< Node *> *dependents)
void Error(const char *msg,...)
Log an error message.
bool FinishCommand(CommandRunner::Result *result, std::string *err)
Update status ninja logs following a command termination.
void BuildEdgeStarted(const Edge *edge)
RealCommandRunner(const BuildConfig &config)