Ninja
status.cc
Go to the documentation of this file.
1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "status.h"
16 
17 #include <stdarg.h>
18 #include <stdlib.h>
19 
20 #ifdef _WIN32
21 #include <fcntl.h>
22 #include <io.h>
23 #endif
24 
25 #include "debug_flags.h"
26 
27 using namespace std;
28 
30  : config_(config),
31  started_edges_(0), finished_edges_(0), total_edges_(0), running_edges_(0),
32  time_millis_(0), progress_status_format_(NULL),
33  current_rate_(config.parallelism) {
34 
35  // Don't do anything fancy in verbose mode.
38 
39  progress_status_format_ = getenv("NINJA_STATUS");
41  progress_status_format_ = "[%f/%t] ";
42 }
43 
45  total_edges_ = total;
46 }
47 
49  int64_t start_time_millis) {
52  time_millis_ = start_time_millis;
53 
54  if (edge->use_console() || printer_.is_smart_terminal())
55  PrintStatus(edge, start_time_millis);
56 
57  if (edge->use_console())
59 }
60 
61 void StatusPrinter::BuildEdgeFinished(Edge* edge, int64_t end_time_millis,
62  bool success, const string& output) {
63  time_millis_ = end_time_millis;
65 
66  if (edge->use_console())
68 
70  return;
71 
72  if (!edge->use_console())
73  PrintStatus(edge, end_time_millis);
74 
76 
77  // Print the command that is spewing before printing its output.
78  if (!success) {
79  string outputs;
80  for (vector<Node*>::const_iterator o = edge->outputs_.begin();
81  o != edge->outputs_.end(); ++o)
82  outputs += (*o)->path() + " ";
83 
84  if (printer_.supports_color()) {
85  printer_.PrintOnNewLine("\x1B[31m" "FAILED: " "\x1B[0m" + outputs + "\n");
86  } else {
87  printer_.PrintOnNewLine("FAILED: " + outputs + "\n");
88  }
89  printer_.PrintOnNewLine(edge->EvaluateCommand() + "\n");
90  }
91 
92  if (!output.empty()) {
93  // ninja sets stdout and stderr of subprocesses to a pipe, to be able to
94  // check if the output is empty. Some compilers, e.g. clang, check
95  // isatty(stderr) to decide if they should print colored output.
96  // To make it possible to use colored output with ninja, subprocesses should
97  // be run with a flag that forces them to always print color escape codes.
98  // To make sure these escape codes don't show up in a file if ninja's output
99  // is piped to a file, ninja strips ansi escape codes again if it's not
100  // writing to a |smart_terminal_|.
101  // (Launching subprocesses in pseudo ttys doesn't work because there are
102  // only a few hundred available on some systems, and ninja can launch
103  // thousands of parallel compile commands.)
104  string final_output;
105  if (!printer_.supports_color())
106  final_output = StripAnsiEscapeCodes(output);
107  else
108  final_output = output;
109 
110 #ifdef _WIN32
111  // Fix extra CR being added on Windows, writing out CR CR LF (#773)
112  _setmode(_fileno(stdout), _O_BINARY); // Begin Windows extra CR fix
113 #endif
114 
115  printer_.PrintOnNewLine(final_output);
116 
117 #ifdef _WIN32
118  _setmode(_fileno(stdout), _O_TEXT); // End Windows extra CR fix
119 #endif
120  }
121 }
122 
124  // The DependencyScan calls EXPLAIN() to print lines explaining why
125  // it considers a portion of the graph to be out of date. Normally
126  // this is done before the build starts, but our caller is about to
127  // load a dyndep file during the build. Doing so may generate more
128  // explanation lines (via fprintf directly to stderr), but in an
129  // interactive console the cursor is currently at the end of a status
130  // line. Start a new line so that the first explanation does not
131  // append to the status line. After the explanations are done a
132  // new build status line will appear.
133  if (g_explaining)
135 }
136 
138  started_edges_ = 0;
139  finished_edges_ = 0;
140  running_edges_ = 0;
141 }
142 
144  printer_.SetConsoleLocked(false);
146 }
147 
148 string StatusPrinter::FormatProgressStatus(const char* progress_status_format,
149  int64_t time_millis) const {
150  string out;
151  char buf[32];
152  for (const char* s = progress_status_format; *s != '\0'; ++s) {
153  if (*s == '%') {
154  ++s;
155  switch (*s) {
156  case '%':
157  out.push_back('%');
158  break;
159 
160  // Started edges.
161  case 's':
162  snprintf(buf, sizeof(buf), "%d", started_edges_);
163  out += buf;
164  break;
165 
166  // Total edges.
167  case 't':
168  snprintf(buf, sizeof(buf), "%d", total_edges_);
169  out += buf;
170  break;
171 
172  // Running edges.
173  case 'r': {
174  snprintf(buf, sizeof(buf), "%d", running_edges_);
175  out += buf;
176  break;
177  }
178 
179  // Unstarted edges.
180  case 'u':
181  snprintf(buf, sizeof(buf), "%d", total_edges_ - started_edges_);
182  out += buf;
183  break;
184 
185  // Finished edges.
186  case 'f':
187  snprintf(buf, sizeof(buf), "%d", finished_edges_);
188  out += buf;
189  break;
190 
191  // Overall finished edges per second.
192  case 'o':
193  SnprintfRate(finished_edges_ / (time_millis_ / 1e3), buf, "%.1f");
194  out += buf;
195  break;
196 
197  // Current rate, average over the last '-j' jobs.
198  case 'c':
200  SnprintfRate(current_rate_.rate(), buf, "%.1f");
201  out += buf;
202  break;
203 
204  // Percentage
205  case 'p': {
206  int percent = (100 * finished_edges_) / total_edges_;
207  snprintf(buf, sizeof(buf), "%3i%%", percent);
208  out += buf;
209  break;
210  }
211 
212  case 'e': {
213  snprintf(buf, sizeof(buf), "%.3f", time_millis_ / 1e3);
214  out += buf;
215  break;
216  }
217 
218  default:
219  Fatal("unknown placeholder '%%%c' in $NINJA_STATUS", *s);
220  return "";
221  }
222  } else {
223  out.push_back(*s);
224  }
225  }
226 
227  return out;
228 }
229 
230 void StatusPrinter::PrintStatus(const Edge* edge, int64_t time_millis) {
233  return;
234 
235  bool force_full_command = config_.verbosity == BuildConfig::VERBOSE;
236 
237  string to_print = edge->GetBinding("description");
238  if (to_print.empty() || force_full_command)
239  to_print = edge->GetBinding("command");
240 
241  to_print = FormatProgressStatus(progress_status_format_, time_millis)
242  + to_print;
243 
244  printer_.Print(to_print,
245  force_full_command ? LinePrinter::FULL : LinePrinter::ELIDE);
246 }
247 
248 void StatusPrinter::Warning(const char* msg, ...) {
249  va_list ap;
250  va_start(ap, msg);
251  ::Warning(msg, ap);
252  va_end(ap);
253 }
254 
255 void StatusPrinter::Error(const char* msg, ...) {
256  va_list ap;
257  va_start(ap, msg);
258  ::Error(msg, ap);
259  va_end(ap);
260 }
261 
262 void StatusPrinter::Info(const char* msg, ...) {
263  va_list ap;
264  va_start(ap, msg);
265  ::Info(msg, ap);
266  va_end(ap);
267 }
void SnprintfRate(double rate, char(&buf)[S], const char *format) const
Definition: status.h:83
bool supports_color() const
Definition: line_printer.h:29
Verbosity verbosity
Definition: build.h:167
virtual void Warning(const char *msg,...)
Definition: status.cc:248
void Print(std::string to_print, LineType type)
Overprints the current line.
Definition: line_printer.cc:66
virtual void Info(const char *msg,...)
Definition: status.cc:262
int finished_edges_
Definition: status.h:73
int64_t time_millis_
Definition: status.h:74
virtual void BuildFinished()
Definition: status.cc:143
std::vector< Node * > outputs_
Definition: graph.h:204
An edge in the dependency graph; links between Nodes using Rules.
Definition: graph.h:164
bool g_explaining
Definition: debug_flags.cc:15
signed long long int64_t
A 64-bit integer type.
Definition: win32port.h:28
const BuildConfig & config_
Definition: status.h:71
virtual void BuildStarted()
Definition: status.cc:137
StatusPrinter(const BuildConfig &config)
Definition: status.cc:29
virtual void BuildEdgeFinished(Edge *edge, int64_t end_time_millis, bool success, const std::string &output)
Definition: status.cc:61
std::string FormatProgressStatus(const char *progress_status_format, int64_t time_millis) const
Format the progress status string by replacing the placeholders.
Definition: status.cc:148
const char * progress_status_format_
The custom progress status format to use.
Definition: status.h:80
void set_smart_terminal(bool smart)
Definition: line_printer.h:27
int total_edges_
Definition: status.h:73
int running_edges_
Definition: status.h:73
void SetConsoleLocked(bool locked)
Lock or unlock the console.
int started_edges_
Definition: status.h:73
SlidingRateInfo current_rate_
Definition: status.h:114
std::string GetBinding(const std::string &key) const
Returns the shell-escaped value of |key|.
Definition: graph.cc:491
bool is_smart_terminal() const
Definition: line_printer.h:26
string StripAnsiEscapeCodes(const string &in)
Definition: util.cc:482
void Fatal(const char *msg,...)
Log a fatal message and exit.
Definition: util.cc:65
LinePrinter printer_
Prints progress output.
Definition: status.h:77
std::string EvaluateCommand(bool incl_rsp_file=false) const
Expand all variables in a command and return it as a string.
Definition: graph.cc:481
virtual void Error(const char *msg,...)
Definition: status.cc:255
void UpdateRate(int update_hint, int64_t time_millis_)
Definition: status.h:95
Options (e.g. verbosity, parallelism) passed to a build.
Definition: build.h:157
virtual void BuildEdgeStarted(const Edge *edge, int64_t start_time_millis)
Definition: status.cc:48
bool use_console() const
Definition: graph.cc:547
virtual void PlanHasTotalEdges(int total)
Definition: status.cc:44
void PrintOnNewLine(const std::string &to_print)
Prints a string on a new line, not overprinting previous output.
virtual void BuildLoadDyndeps()
Definition: status.cc:123
void PrintStatus(const Edge *edge, int64_t time_millis)
Definition: status.cc:230