23 #if defined(__SVR4) && defined(__sun)
24 #include <sys/termios.h>
42 virtual ~DryRunCommandRunner() {}
45 virtual bool CanRunMore();
46 virtual bool StartCommand(
Edge* edge);
47 virtual bool WaitForCommand(Result* result);
50 queue<Edge*> finished_;
53 bool DryRunCommandRunner::CanRunMore() {
57 bool DryRunCommandRunner::StartCommand(
Edge* edge) {
62 bool DryRunCommandRunner::WaitForCommand(Result* result) {
63 if (finished_.empty())
67 result->edge = finished_.front();
77 started_edges_(0), finished_edges_(0), total_edges_(0),
78 progress_status_format_(NULL),
79 overall_rate_(), current_rate_(config.parallelism) {
107 const string& output,
114 *start_time = i->second;
131 if (!output.empty()) {
148 final_output = output;
159 const char* progress_status_format)
const {
163 for (
const char* s = progress_status_format; *s !=
'\0'; ++s) {
218 snprintf(buf,
sizeof(buf),
"%3i%%", percent);
224 snprintf(buf,
sizeof(buf),
"%.3f", elapsed);
230 Fatal(
"unknown placeholder '%%%c' in $NINJA_STATUS", *s);
247 string to_print = edge->
GetBinding(
"description");
248 if (to_print.empty() || force_full_command)
274 referenced =
", needed by '" + stack->back()->path() +
"',";
275 *err =
"'" + node->
path() +
"'" + referenced +
" missing "
276 "and no known rule to make it";
289 pair<map<Edge*, bool>::iterator,
bool> want_ins =
290 want_.insert(make_pair(edge,
false));
291 bool& want = want_ins.first->second;
295 if (node->
dirty() && !want) {
304 if (!want_ins.second)
307 stack->push_back(node);
308 for (vector<Node*>::iterator i = edge->
inputs_.begin();
309 i != edge->
inputs_.end(); ++i) {
313 assert(stack->back() == node);
320 vector<Node*>::reverse_iterator ri =
321 find(stack->rbegin(), stack->rend(), node);
322 if (ri == stack->rend())
327 stack->push_back(node);
329 vector<Node*>::iterator start = find(stack->begin(), stack->end(), node);
330 *err =
"dependency cycle: ";
331 for (vector<Node*>::iterator i = start; i != stack->end(); ++i) {
334 err->append((*i)->path());
342 set<Edge*>::iterator i =
ready_.begin();
371 map<Edge*, bool>::iterator i =
want_.find(edge);
372 assert(i !=
want_.end());
382 for (vector<Node*>::iterator i = edge->
outputs_.begin();
390 for (vector<Edge*>::const_iterator i = node->
out_edges().begin();
392 map<Edge*, bool>::iterator want_i =
want_.find(*i);
393 if (want_i ==
want_.end())
397 if ((*i)->AllInputsReady()) {
398 if (want_i->second) {
412 for (vector<Edge*>::const_iterator ei = node->
out_edges().begin();
415 map<Edge*, bool>::iterator want_i =
want_.find(*ei);
416 if (want_i ==
want_.end() || !want_i->second)
420 if ((*ei)->deps_missing_)
425 vector<Node*>::iterator
426 begin = (*ei)->inputs_.begin(),
427 end = (*ei)->inputs_.end() - (*ei)->order_only_deps_;
428 if (find_if(begin, end, mem_fun(&
Node::dirty)) == end) {
430 Node* most_recent_input = NULL;
431 for (vector<Node*>::iterator ni = begin; ni != end; ++ni) {
432 if (!most_recent_input || (*ni)->
mtime() > most_recent_input->
mtime())
433 most_recent_input = *ni;
440 for (vector<Node*>::iterator ni = (*ei)->outputs_.begin();
441 ni != (*ei)->outputs_.end(); ++ni) {
445 want_i->second =
false;
447 if (!(*ei)->is_phony())
455 printf(
"pending: %d\n", (
int)
want_.size());
456 for (map<Edge*, bool>::iterator i =
want_.begin(); i !=
want_.end(); ++i) {
461 printf(
"ready: %d\n", (
int)
ready_.size());
471 virtual void Abort();
482 edges.push_back(i->second);
518 result->
edge = i->second;
528 : state_(state), config_(config), disk_interface_(disk_interface),
529 scan_(state, build_log, deps_log, disk_interface) {
542 for (vector<Edge*>::iterator i = active_edges.begin();
543 i != active_edges.end(); ++i) {
544 string depfile = (*i)->GetUnescapedDepfile();
545 for (vector<Node*>::iterator ni = (*i)->outputs_.begin();
546 ni != (*i)->outputs_.end(); ++ni) {
554 if (!depfile.empty() ||
559 if (!depfile.empty())
568 *err =
"unknown target: '" + name +
"'";
581 if (in_edge->outputs_ready())
599 int pending_commands = 0;
637 if (pending_commands) {
643 *err =
"interrupted by user";
655 if (failures_allowed)
665 if (failures_allowed == 0) {
667 *err =
"subcommands failed";
669 *err =
"subcommand failed";
671 *err =
"cannot make progress due to previous errors";
673 *err =
"stuck [this is a bug]";
691 for (vector<Node*>::iterator i = edge->
outputs_.begin();
700 if (!rspfile.empty()) {
701 string content = edge->
GetBinding(
"rspfile_content");
725 vector<Node*> deps_nodes;
727 const string deps_prefix = edge->
GetBinding(
"msvc_deps_prefix");
728 if (!deps_type.empty()) {
730 if (!
ExtractDeps(result, deps_type, deps_prefix, &deps_nodes,
733 if (!result->
output.empty())
734 result->
output.append(
"\n");
735 result->
output.append(extract_err);
740 int start_time, end_time;
742 &start_time, &end_time);
751 bool node_cleaned =
false;
753 for (vector<Node*>::iterator i = edge->
outputs_.begin();
756 if ((*i)->mtime() == new_mtime) {
768 for (vector<Node*>::iterator i = edge->
inputs_.begin();
771 if (input_mtime > restat_mtime)
772 restat_mtime = input_mtime;
776 if (restat_mtime != 0 && deps_type.empty() && !depfile.empty()) {
778 if (depfile_mtime > restat_mtime)
779 restat_mtime = depfile_mtime;
798 *err = string(
"Error writing to build log: ") + strerror(errno);
804 assert(edge->
outputs_.size() == 1 &&
"should have been rejected by parser");
808 *err = string(
"Error writing to deps log: ") + strerror(errno);
816 const string& deps_type,
817 const string& deps_prefix,
818 vector<Node*>* deps_nodes,
821 if (deps_type ==
"msvc") {
824 for (set<string>::iterator i = parser.
includes_.begin();
830 if (deps_type ==
"gcc") {
832 if (depfile.empty()) {
833 *err = string(
"edge with deps=gcc but no depfile makes no sense");
844 if (!deps.
Parse(&content, err))
848 deps_nodes->reserve(deps.
ins_.size());
849 for (vector<StringPiece>::iterator i = deps.
ins_.begin();
850 i != deps.
ins_.end(); ++i) {
857 *err = string(
"deleting depfile: ") + strerror(errno) + string(
"\n");
861 Fatal(
"unknown deps type '%s'", deps_type.c_str());
SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
virtual string ReadFile(const string &path, string *err)=0
Read a file to a string. Fill in |err| on error.
CommandRunner is an interface that wraps running the build subcommands.
map< Subprocess *, Edge * > subproc_to_edge_
void BuildEdgeFinished(Edge *edge, bool success, const string &output, int *start_time, int *end_time)
BuildStatus(const BuildConfig &config)
virtual ~RealCommandRunner()
Subprocess * NextFinished()
double max_load_average
The maximum load average we must not exceed.
bool more_to_do() const
Returns true if there's more work to be done.
Parser for the dependency information emitted by gcc's -M flags.
SlidingRateInfo current_rate_
void EdgeScheduled(const Edge &edge)
informs this Pool that the given edge is committed to be run.
Node * GetNode(StringPiece path)
void UpdateRate(int edges)
bool RecomputeDirty(Edge *edge, string *err)
Examine inputs, outputs, and command lines to judge whether an edge needs to be re-run, and update outputs_ready_ and each outputs' |dirty_| state accordingly.
bool AddSubTarget(Node *node, vector< Node * > *stack, string *err)
The result of waiting for a command.
string GetUnescapedRspfile()
Like GetBinding("rspfile"), but without shell escaping.
void set_dirty(bool dirty)
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 ResumeDelayedJobs(Edge *edge)
Allows jobs blocking on |edge| to potentially resume.
void ScheduleWork(Edge *edge)
Submits a ready edge as a candidate for execution.
bool Parse(string *content, string *err)
Parse an input file.
bool ShouldDelayEdge() const
true if the Pool might delay this edge
bool StatIfNecessary(DiskInterface *disk_interface)
Return true if we needed to stat.
Interface for accessing the disk.
bool RecomputeOutputsDirty(Edge *edge, Node *most_recent_input)
Recompute whether any output of the edge is dirty.
const BuildConfig & config_
bool is_smart_terminal() const
int64_t GetTimeMillis()
Get the current time as relative to some epoch.
bool GetBindingBool(const string &key)
void PrintOnNewLine(const string &to_print)
Prints a string on a new line, not overprinting previous output.
const BuildConfig & config_
void CleanNode(DependencyScan *scan, Node *node)
Clean the given node during the build.
bool outputs_ready() const
bool ExtractDeps(CommandRunner::Result *result, const string &deps_type, const string &deps_prefix, vector< Node * > *deps_nodes, string *err)
An edge in the dependency graph; links between Nodes using Rules.
void UpdateRate(int update_hint)
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 AlreadyUpToDate() const
Returns true if the build targets are already up to date.
vector< Subprocess * > running_
const BuildConfig & config_
void BuildEdgeStarted(Edge *edge)
DiskInterface * disk_interface_
bool CanonicalizePath(string *path, string *err)
Canonicalize a path like "foo/../bar.h" into just "bar.h".
ExitStatus Finish()
Returns ExitSuccess on successful process exit, ExitInterrupted if the process was interrupted...
int command_edge_count() const
Number of edges with commands to run.
void EdgeFinished(Edge *edge)
Mark an edge as done building.
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.
const string & GetOutput() const
Builder(State *state, const BuildConfig &config, BuildLog *build_log, DepsLog *deps_log, DiskInterface *disk_interface)
Subprocess * Add(const string &command, bool use_console=false)
BuildLog * build_log() const
Subprocess wraps a single async subprocess.
map< Edge *, bool > want_
Keep track of which edges we want to build in this plan.
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.
void set_smart_terminal(bool smart)
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.
vector< StringPiece > ins_
A pool for delayed edges.
void SetConsoleLocked(bool locked)
Lock or unlock the console.
#define METRIC_RECORD(name)
The primary interface to metrics.
auto_ptr< CommandRunner > command_runner_
const string & path() const
void RetrieveReadyEdges(set< Edge * > *ready_queue)
Pool will add zero or more edges to the ready_queue.
void PlanHasTotalEdges(int total)
void NodeFinished(Node *node)
bool CheckDependencyCycle(Node *node, vector< Node * > *stack, string *err)
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.
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...
void PrintStatus(Edge *edge)
string Parse(const string &output, const string &deps_prefix)
Parse the full output of cl, returning the output (if any) that should printed.
bool RecordCommand(Edge *edge, int start_time, int end_time, TimeStamp restat_mtime=0)
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()
Options (e.g. verbosity, parallelism) passed to a build.
Global state (file status, loaded rules) for a single run.
bool StartEdge(Edge *edge, string *err)
bool AllInputsReady() const
Return true if all inputs' in-edges are ready.
void Dump()
Dumps the current state of the plan.
void Print(string to_print, LineType type)
Overprints the current line.
bool RecordDeps(Node *node, TimeStamp mtime, const vector< Node * > &nodes)
string GetUnescapedDepfile()
Like GetBinding("depfile"), but without shell escaping.
RunningEdgeMap running_edges_
virtual TimeStamp Stat(const string &path) const =0
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
bool Build(string *err)
Run the build.
string FormatProgressStatus(const char *progress_status_format) const
Format the progress status string by replacing the placeholders.
LinePrinter printer_
Prints progress output.
Node * AddTarget(const string &name, string *err)
const vector< Edge * > & out_edges() const
int command_edges_
Total number of edges that have commands (not phony).
void snprinfRate(double rate, char(&buf)[S], const char *format) const
DepsLog * deps_log() const
Node * LookupNode(StringPiece path) const
RealCommandRunner(const BuildConfig &config)
vector< Node * > outputs_