28 #if defined(__SVR4) && defined(__sun) 29 #include <sys/termios.h> 47 virtual ~DryRunCommandRunner() {}
50 virtual bool CanRunMore();
51 virtual bool StartCommand(
Edge* edge);
52 virtual bool WaitForCommand(Result* result);
55 queue<Edge*> finished_;
58 bool DryRunCommandRunner::CanRunMore() {
62 bool DryRunCommandRunner::StartCommand(
Edge* edge) {
67 bool DryRunCommandRunner::WaitForCommand(Result* result) {
68 if (finished_.empty())
72 result->edge = finished_.front();
82 started_edges_(0), finished_edges_(0), total_edges_(0),
83 progress_status_format_(NULL),
84 overall_rate_(), 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() +
" ";
145 if (!output.empty()) {
161 final_output = output;
165 _setmode(_fileno(stdout), _O_BINARY);
171 _setmode(_fileno(stdout), _O_TEXT);
187 const char* progress_status_format,
EdgeStatus status)
const {
191 for (
const char* s = progress_status_format; *s !=
'\0'; ++s) {
217 snprintf(buf,
sizeof(buf),
"%d", running_edges);
251 snprintf(buf,
sizeof(buf),
"%3i%%", percent);
257 snprintf(buf,
sizeof(buf),
"%.3f", elapsed);
263 Fatal(
"unknown placeholder '%%%c' in $NINJA_STATUS", *s);
280 string to_print = edge->
GetBinding(
"description");
281 if (to_print.empty() || force_full_command)
309 referenced =
", needed by '" + dependent->
path() +
"',";
310 *err =
"'" + node->
path() +
"'" + referenced +
" missing " 311 "and no known rule to make it";
321 pair<map<Edge*, Want>::iterator,
bool> want_ins =
323 Want& want = want_ins.first->second;
336 if (!want_ins.second)
339 for (vector<Node*>::iterator i = edge->
inputs_.begin();
340 i != edge->
inputs_.end(); ++i) {
351 set<Edge*>::iterator e =
ready_.begin();
368 Edge* edge = want_e->first;
380 map<Edge*, Want>::iterator e =
want_.find(edge);
381 assert(e !=
want_.end());
399 for (vector<Node*>::iterator o = edge->
outputs_.begin();
407 for (vector<Edge*>::const_iterator oe = node->
out_edges().begin();
409 map<Edge*, Want>::iterator want_e =
want_.find(*oe);
410 if (want_e ==
want_.end())
414 if ((*oe)->AllInputsReady()) {
429 for (vector<Edge*>::const_iterator oe = node->
out_edges().begin();
432 map<Edge*, Want>::iterator want_e =
want_.find(*oe);
437 if ((*oe)->deps_missing_)
442 vector<Node*>::iterator
443 begin = (*oe)->inputs_.begin(),
444 end = (*oe)->inputs_.end() - (*oe)->order_only_deps_;
445 #if __cplusplus < 201703L 446 #define MEM_FN mem_fun 448 #define MEM_FN mem_fn // mem_fun was removed in C++17. 452 Node* most_recent_input = NULL;
453 for (vector<Node*>::iterator i = begin; i != end; ++i) {
454 if (!most_recent_input || (*i)->
mtime() > most_recent_input->
mtime())
455 most_recent_input = *i;
461 bool outputs_dirty =
false;
463 &outputs_dirty, err)) {
466 if (!outputs_dirty) {
467 for (vector<Node*>::iterator o = (*oe)->outputs_.begin();
468 o != (*oe)->outputs_.end(); ++o) {
475 if (!(*oe)->is_phony())
484 printf(
"pending: %d\n", (
int)
want_.size());
485 for (map<Edge*, Want>::iterator e =
want_.begin(); e !=
want_.end(); ++e) {
490 printf(
"ready: %d\n", (
int)
ready_.size());
500 virtual void Abort();
511 edges.push_back(e->second);
520 size_t subproc_number =
549 result->
edge = e->second;
559 : state_(state), config_(config), disk_interface_(disk_interface),
560 scan_(state, build_log, deps_log, disk_interface,
561 &config_.depfile_parser_options) {
574 for (vector<Edge*>::iterator e = active_edges.begin();
575 e != active_edges.end(); ++e) {
576 string depfile = (*e)->GetUnescapedDepfile();
577 for (vector<Node*>::iterator o = (*e)->outputs_.begin();
578 o != (*e)->outputs_.end(); ++o) {
589 Error(
"%s", err.c_str());
590 if (!depfile.empty() || (*o)->mtime() != new_mtime)
593 if (!depfile.empty())
602 *err =
"unknown target: '" + name +
"'";
615 if (in_edge->outputs_ready())
633 int pending_commands = 0;
674 if (pending_commands) {
680 *err =
"interrupted by user";
692 if (failures_allowed)
702 if (failures_allowed == 0) {
704 *err =
"subcommands failed";
706 *err =
"subcommand failed";
708 *err =
"cannot make progress due to previous errors";
710 *err =
"stuck [this is a bug]";
728 for (vector<Node*>::iterator o = edge->
outputs_.begin();
737 if (!rspfile.empty()) {
738 string content = edge->
GetBinding(
"rspfile_content");
762 vector<Node*> deps_nodes;
764 const string deps_prefix = edge->
GetBinding(
"msvc_deps_prefix");
765 if (!deps_type.empty()) {
767 if (!
ExtractDeps(result, deps_type, deps_prefix, &deps_nodes,
770 if (!result->
output.empty())
771 result->
output.append(
"\n");
772 result->
output.append(extract_err);
777 int start_time, end_time;
779 &start_time, &end_time);
791 bool node_cleaned =
false;
793 for (vector<Node*>::iterator o = edge->
outputs_.begin();
798 if (new_mtime > output_mtime)
799 output_mtime = new_mtime;
800 if ((*o)->mtime() == new_mtime && restat) {
814 for (vector<Node*>::iterator i = edge->
inputs_.begin();
817 if (input_mtime == -1)
819 if (input_mtime > restat_mtime)
820 restat_mtime = input_mtime;
824 if (restat_mtime != 0 && deps_type.empty() && !depfile.empty()) {
826 if (depfile_mtime == -1)
828 if (depfile_mtime > restat_mtime)
829 restat_mtime = depfile_mtime;
836 output_mtime = restat_mtime;
850 *err = string(
"Error writing to build log: ") + strerror(errno);
856 assert(edge->
outputs_.size() == 1 &&
"should have been rejected by parser");
859 if (deps_mtime == -1)
862 *err = string(
"Error writing to deps log: ") + strerror(errno);
870 const string& deps_type,
871 const string& deps_prefix,
872 vector<Node*>* deps_nodes,
874 if (deps_type ==
"msvc") {
877 if (!parser.
Parse(result->
output, deps_prefix, &output, err))
880 for (set<string>::iterator i = parser.
includes_.begin();
889 if (deps_type ==
"gcc") {
891 if (depfile.empty()) {
892 *err = string(
"edge with deps=gcc but no depfile makes no sense");
911 if (!deps.
Parse(&content, err))
915 deps_nodes->reserve(deps.
ins_.size());
916 for (vector<StringPiece>::iterator i = deps.
ins_.begin();
917 i != deps.
ins_.end(); ++i) {
927 *err = string(
"deleting depfile: ") + strerror(errno) + string(
"\n");
932 Fatal(
"unknown deps type '%s'", deps_type.c_str());
SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
bool supports_color() const
CommandRunner is an interface that wraps running the build subcommands.
const vector< Edge * > & out_edges() const
map< Subprocess *, Edge * > subproc_to_edge_
bool RecordCommand(Edge *edge, int start_time, int end_time, TimeStamp mtime=0)
void BuildEdgeFinished(Edge *edge, bool success, const string &output, int *start_time, int *end_time)
We do not want to build the edge, but we might want to build one of its dependents.
BuildStatus(const BuildConfig &config)
virtual ~RealCommandRunner()
const string & path() const
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)
Canonicalize a path like "foo/../bar.h" into just "bar.h".
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 UpdateRate(int edges)
bool ExtractDeps(CommandRunner::Result *result, const string &deps_type, const string &deps_prefix, vector< Node *> *deps_nodes, string *err)
The result of waiting for a command.
string GetUnescapedRspfile()
Like GetBinding("rspfile"), but without shell escaping.
void set_dirty(bool dirty)
string FormatProgressStatus(const char *progress_status_format, EdgeStatus status) const
Format the progress status string by replacing the placeholders.
bool AddTarget(Node *node, string *err)
Add a target to our plan (including all its dependencies).
bool MakeDirs(const string &path)
Create all the parent directories for path; like mkdir -p basename path.
Information about a node in the dependency graph: the file, whether it's dirty, mtime, etc.
virtual bool StartCommand(Edge *edge)
void ScheduleWork(map< Edge *, Want >::iterator want_e)
Submits a ready edge as a candidate for execution.
bool Parse(string *content, string *err)
Parse an input file.
bool AddSubTarget(Node *node, Node *dependent, string *err)
bool outputs_ready() const
Interface for accessing the disk.
const BuildConfig & config_
int64_t GetTimeMillis()
Get the current time as relative to some epoch.
bool GetBindingBool(const string &key)
void PrintStatus(Edge *edge, EdgeStatus status)
void PrintOnNewLine(const string &to_print)
Prints a string on a new line, not overprinting previous output.
const BuildConfig & config_
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.
string EvaluateCommand(bool incl_rsp_file=false)
Expand all variables in a command and return it as a string.
bool RecomputeOutputsDirty(Edge *edge, Node *most_recent_input, bool *dirty, string *err)
Recompute whether any output of the edge is dirty, if so sets |*dirty|.
vector< Subprocess * > running_
const BuildConfig & config_
void BuildEdgeStarted(Edge *edge)
DiskInterface * disk_interface_
ExitStatus Finish()
Returns ExitSuccess on successful process exit, ExitInterrupted if the process was interrupted...
Want
Enumerate possible steps we want for an edge.
virtual bool WriteFile(const string &path, const string &contents)=0
Create a file, with the specified name and contents Returns true on success, false on failure...
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 * Add(const string &command, bool use_console=false)
Subprocess wraps a single async subprocess.
void Reset()
Reset state. Clears want and ready sets.
bool FinishCommand(CommandRunner::Result *result, string *err)
Update status ninja logs following a command termination.
virtual vector< Edge * > GetActiveEdges()
int64_t start_time_millis_
Time the build started.
int wanted_edges_
Total remaining number of wanted edges.
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.
virtual TimeStamp Stat(const string &path, string *err) const =0
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
void Cleanup()
Clean up after interrupted commands by deleting output files.
vector< StringPiece > ins_
A pool for delayed edges.
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
map< Edge *, Want > want_
Keep track of which edges we want to build in this plan.
#define METRIC_RECORD(name)
The primary interface to metrics.
auto_ptr< CommandRunner > command_runner_
virtual Status ReadFile(const string &path, string *contents, string *err)=0
Read and store in given string.
void PlanHasTotalEdges(int total)
void NodeFinished(Node *node)
bool is_smart_terminal() const
string StripAnsiEscapeCodes(const string &in)
Removes all Ansi escape codes (http://www.termsys.demon.co.uk/vtansi.htm).
void Fatal(const char *msg,...)
Log a fatal message and exit.
Tracks the status of a build: completion fraction, printing updates.
void RetrieveReadyEdges(set< Edge *> *ready_queue)
Pool will add zero or more edges to the ready_queue.
void SnprintfRate(double rate, char(&buf)[S], const char *format) const
const char * progress_status_format_
The custom progress status format to use.
string GetBinding(const string &key)
Returns the shell-escaped value of |key|.
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...
const string & GetOutput() const
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...
virtual int RemoveFile(const string &path)=0
Remove the file named path.
virtual bool CanRunMore()
queue< Subprocess * > finished_
Options (e.g. verbosity, parallelism) passed to a build.
Global state (file status) for a single run.
bool StartEdge(Edge *edge, string *err)
We want to build the edge, have scheduled it, and are waiting for it to complete. ...
void Dump()
Dumps the current state of the plan.
unsigned long long uint64_t
void Print(string to_print, LineType type)
Overprints the current line.
string GetUnescapedDepfile()
Like GetBinding("depfile"), but without shell escaping.
RunningEdgeMap running_edges_
bool RecomputeDirty(Node *node, string *err)
Update the |dirty_| state of the given node by inspecting its input edge.
bool Build(string *err)
Run the build.
bool RecordDeps(Node *node, TimeStamp mtime, const vector< Node *> &nodes)
bool more_to_do() const
Returns true if there's more work to be done.
bool CleanNode(DependencyScan *scan, Node *node, string *err)
Clean the given node during the build.
void EdgeFinished(Edge *edge, EdgeResult result)
Mark an edge as done building (whether it succeeded or failed).
DepfileParserOptions depfile_parser_options
bool AlreadyUpToDate() const
Returns true if the build targets are already up to date.
LinePrinter printer_
Prints progress output.
Node * AddTarget(const string &name, string *err)
bool Parse(const string &output, const string &deps_prefix, string *filtered_output, string *err)
Parse the full output of cl, filling filtered_output with the text that should be printed (if any)...
int command_edges_
Total number of edges that have commands (not phony).
void Error(const char *msg,...)
Log an error message.
RealCommandRunner(const BuildConfig &config)
vector< Node * > outputs_