Ninja
manifest_parser.cc
Go to the documentation of this file.
1 // Copyright 2011 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 "manifest_parser.h"
16 
17 #include <stdio.h>
18 #include <vector>
19 
20 #include "graph.h"
21 #include "metrics.h"
22 #include "state.h"
23 #include "util.h"
24 #include "version.h"
25 
27  : state_(state), file_reader_(file_reader) {
28  env_ = &state->bindings_;
29 }
30 bool ManifestParser::Load(const string& filename, string* err) {
31  string contents;
32  string read_err;
33  if (!file_reader_->ReadFile(filename, &contents, &read_err)) {
34  *err = "loading '" + filename + "': " + read_err;
35  return false;
36  }
37  contents.resize(contents.size() + 10);
38  return Parse(filename, contents, err);
39 }
40 
41 bool ManifestParser::Parse(const string& filename, const string& input,
42  string* err) {
43  METRIC_RECORD(".ninja parse");
44  lexer_.Start(filename, input);
45 
46  for (;;) {
47  Lexer::Token token = lexer_.ReadToken();
48  switch (token) {
49  case Lexer::POOL:
50  if (!ParsePool(err))
51  return false;
52  break;
53  case Lexer::BUILD:
54  if (!ParseEdge(err))
55  return false;
56  break;
57  case Lexer::RULE:
58  if (!ParseRule(err))
59  return false;
60  break;
61  case Lexer::DEFAULT:
62  if (!ParseDefault(err))
63  return false;
64  break;
65  case Lexer::IDENT: {
67  string name;
68  EvalString let_value;
69  if (!ParseLet(&name, &let_value, err))
70  return false;
71  string value = let_value.Evaluate(env_);
72  // Check ninja_required_version immediately so we can exit
73  // before encountering any syntactic surprises.
74  if (name == "ninja_required_version")
75  CheckNinjaVersion(value);
76  env_->AddBinding(name, value);
77  break;
78  }
79  case Lexer::INCLUDE:
80  if (!ParseFileInclude(false, err))
81  return false;
82  break;
83  case Lexer::SUBNINJA:
84  if (!ParseFileInclude(true, err))
85  return false;
86  break;
87  case Lexer::ERROR: {
88  return lexer_.Error(lexer_.DescribeLastError(), err);
89  }
90  case Lexer::TEOF:
91  return true;
92  case Lexer::NEWLINE:
93  break;
94  default:
95  return lexer_.Error(string("unexpected ") + Lexer::TokenName(token),
96  err);
97  }
98  }
99  return false; // not reached
100 }
101 
102 
103 bool ManifestParser::ParsePool(string* err) {
104  string name;
105  if (!lexer_.ReadIdent(&name))
106  return lexer_.Error("expected pool name", err);
107 
108  if (!ExpectToken(Lexer::NEWLINE, err))
109  return false;
110 
111  if (state_->LookupPool(name) != NULL)
112  return lexer_.Error("duplicate pool '" + name + "'", err);
113 
114  int depth = -1;
115 
116  while (lexer_.PeekToken(Lexer::INDENT)) {
117  string key;
118  EvalString value;
119  if (!ParseLet(&key, &value, err))
120  return false;
121 
122  if (key == "depth") {
123  string depth_string = value.Evaluate(env_);
124  depth = atol(depth_string.c_str());
125  if (depth < 0)
126  return lexer_.Error("invalid pool depth", err);
127  } else {
128  return lexer_.Error("unexpected variable '" + key + "'", err);
129  }
130  }
131 
132  if (depth < 0)
133  return lexer_.Error("expected 'depth =' line", err);
134 
135  state_->AddPool(new Pool(name, depth));
136  return true;
137 }
138 
139 
140 bool ManifestParser::ParseRule(string* err) {
141  string name;
142  if (!lexer_.ReadIdent(&name))
143  return lexer_.Error("expected rule name", err);
144 
145  if (!ExpectToken(Lexer::NEWLINE, err))
146  return false;
147 
148  if (state_->LookupRule(name) != NULL) {
149  *err = "duplicate rule '" + name + "'";
150  return false;
151  }
152 
153  Rule* rule = new Rule(name); // XXX scoped_ptr
154 
155  while (lexer_.PeekToken(Lexer::INDENT)) {
156  string key;
157  EvalString value;
158  if (!ParseLet(&key, &value, err))
159  return false;
160 
161  if (Rule::IsReservedBinding(key)) {
162  rule->AddBinding(key, value);
163  } else {
164  // Die on other keyvals for now; revisit if we want to add a
165  // scope here.
166  return lexer_.Error("unexpected variable '" + key + "'", err);
167  }
168  }
169 
170  if (rule->bindings_["rspfile"].empty() !=
171  rule->bindings_["rspfile_content"].empty()) {
172  return lexer_.Error("rspfile and rspfile_content need to be "
173  "both specified", err);
174  }
175 
176  if (rule->bindings_["command"].empty())
177  return lexer_.Error("expected 'command =' line", err);
178 
179  state_->AddRule(rule);
180  return true;
181 }
182 
183 bool ManifestParser::ParseLet(string* key, EvalString* value, string* err) {
184  if (!lexer_.ReadIdent(key))
185  return false;
186  if (!ExpectToken(Lexer::EQUALS, err))
187  return false;
188  if (!lexer_.ReadVarValue(value, err))
189  return false;
190  return true;
191 }
192 
193 bool ManifestParser::ParseDefault(string* err) {
194  EvalString eval;
195  if (!lexer_.ReadPath(&eval, err))
196  return false;
197  if (eval.empty())
198  return lexer_.Error("expected target name", err);
199 
200  do {
201  string path = eval.Evaluate(env_);
202  string path_err;
203  if (!CanonicalizePath(&path, &path_err))
204  return lexer_.Error(path_err, err);
205  if (!state_->AddDefault(path, &path_err))
206  return lexer_.Error(path_err, err);
207 
208  eval.Clear();
209  if (!lexer_.ReadPath(&eval, err))
210  return false;
211  } while (!eval.empty());
212 
213  if (!ExpectToken(Lexer::NEWLINE, err))
214  return false;
215 
216  return true;
217 }
218 
219 bool ManifestParser::ParseEdge(string* err) {
220  vector<EvalString> ins, outs;
221 
222  {
223  EvalString out;
224  if (!lexer_.ReadPath(&out, err))
225  return false;
226  if (out.empty())
227  return lexer_.Error("expected path", err);
228 
229  do {
230  outs.push_back(out);
231 
232  out.Clear();
233  if (!lexer_.ReadPath(&out, err))
234  return false;
235  } while (!out.empty());
236  }
237 
238  if (!ExpectToken(Lexer::COLON, err))
239  return false;
240 
241  string rule_name;
242  if (!lexer_.ReadIdent(&rule_name))
243  return lexer_.Error("expected build command name", err);
244 
245  const Rule* rule = state_->LookupRule(rule_name);
246  if (!rule)
247  return lexer_.Error("unknown build rule '" + rule_name + "'", err);
248 
249  for (;;) {
250  // XXX should we require one path here?
251  EvalString in;
252  if (!lexer_.ReadPath(&in, err))
253  return false;
254  if (in.empty())
255  break;
256  ins.push_back(in);
257  }
258 
259  // Add all implicit deps, counting how many as we go.
260  int implicit = 0;
262  for (;;) {
263  EvalString in;
264  if (!lexer_.ReadPath(&in, err))
265  return err;
266  if (in.empty())
267  break;
268  ins.push_back(in);
269  ++implicit;
270  }
271  }
272 
273  // Add all order-only deps, counting how many as we go.
274  int order_only = 0;
276  for (;;) {
277  EvalString in;
278  if (!lexer_.ReadPath(&in, err))
279  return false;
280  if (in.empty())
281  break;
282  ins.push_back(in);
283  ++order_only;
284  }
285  }
286 
287  if (!ExpectToken(Lexer::NEWLINE, err))
288  return false;
289 
290  // XXX scoped_ptr to handle error case.
291  BindingEnv* env = new BindingEnv(env_);
292 
293  while (lexer_.PeekToken(Lexer::INDENT)) {
294  string key;
295  EvalString val;
296  if (!ParseLet(&key, &val, err))
297  return false;
298 
299  env->AddBinding(key, val.Evaluate(env_));
300  }
301 
302  Edge* edge = state_->AddEdge(rule);
303  edge->env_ = env;
304 
305  string pool_name = edge->GetBinding("pool");
306  if (!pool_name.empty()) {
307  Pool* pool = state_->LookupPool(pool_name);
308  if (pool == NULL)
309  return lexer_.Error("unknown pool name", err);
310  edge->pool_ = pool;
311  }
312 
313  for (vector<EvalString>::iterator i = ins.begin(); i != ins.end(); ++i) {
314  string path = i->Evaluate(env);
315  string path_err;
316  if (!CanonicalizePath(&path, &path_err))
317  return lexer_.Error(path_err, err);
318  state_->AddIn(edge, path);
319  }
320  for (vector<EvalString>::iterator i = outs.begin(); i != outs.end(); ++i) {
321  string path = i->Evaluate(env);
322  string path_err;
323  if (!CanonicalizePath(&path, &path_err))
324  return lexer_.Error(path_err, err);
325  state_->AddOut(edge, path);
326  }
327  edge->implicit_deps_ = implicit;
328  edge->order_only_deps_ = order_only;
329 
330  // Multiple outputs aren't (yet?) supported with depslog.
331  string deps_type = edge->GetBinding("deps");
332  if (!deps_type.empty() && edge->outputs_.size() > 1) {
333  return lexer_.Error("multiple outputs aren't (yet?) supported by depslog; "
334  "bring this up on the mailing list if it affects you",
335  err);
336  }
337 
338  return true;
339 }
340 
341 bool ManifestParser::ParseFileInclude(bool new_scope, string* err) {
342  // XXX this should use ReadPath!
343  EvalString eval;
344  if (!lexer_.ReadPath(&eval, err))
345  return false;
346  string path = eval.Evaluate(env_);
347 
348  string contents;
349  string read_err;
350  if (!file_reader_->ReadFile(path, &contents, &read_err))
351  return lexer_.Error("loading '" + path + "': " + read_err, err);
352 
353  ManifestParser subparser(state_, file_reader_);
354  if (new_scope) {
355  subparser.env_ = new BindingEnv(env_);
356  } else {
357  subparser.env_ = env_;
358  }
359 
360  if (!subparser.Parse(path, contents, err))
361  return false;
362 
363  if (!ExpectToken(Lexer::NEWLINE, err))
364  return false;
365 
366  return true;
367 }
368 
369 bool ManifestParser::ExpectToken(Lexer::Token expected, string* err) {
370  Lexer::Token token = lexer_.ReadToken();
371  if (token != expected) {
372  string message = string("expected ") + Lexer::TokenName(expected);
373  message += string(", got ") + Lexer::TokenName(token);
374  message += Lexer::TokenErrorHint(expected);
375  return lexer_.Error(message, err);
376  }
377  return true;
378 }
void AddIn(Edge *edge, StringPiece path)
Definition: state.cc:146
static bool IsReservedBinding(const string &var)
Definition: graph.cc:48
virtual bool ReadFile(const string &path, string *content, string *err)=0
int order_only_deps_
Definition: graph.h:175
int implicit_deps_
Definition: graph.h:174
BindingEnv * env_
bool ParsePool(string *err)
Parse various statement types.
void Clear()
Definition: eval_env.h:62
Pool * LookupPool(const string &pool_name)
Definition: state.cc:96
void UnreadToken()
Rewind to the last read Token.
Definition: lexer.cc:115
bool Load(const string &filename, string *err)
Load and parse a file.
static const char * TokenErrorHint(Token expected)
Return a human-readable token hint, used in error messages.
Definition: lexer.cc:94
bool PeekToken(Token token)
If the next token is token, read it and return true.
Definition: lexer.cc:420
An edge in the dependency graph; links between Nodes using Rules.
Definition: graph.h:137
bool Error(const string &message, string *err)
Construct an error message with context.
Definition: lexer.cc:23
void CheckNinjaVersion(const string &version)
Check whether version is compatible with the current Ninja version, aborting if not.
Definition: version.cc:34
bool CanonicalizePath(string *path, string *err)
Canonicalize a path like "foo/../bar.h" into just "bar.h".
Definition: util.cc:87
Token ReadToken()
Read a Token from the Token enum.
Definition: lexer.cc:119
bool ReadPath(EvalString *path, string *err)
Read a path (complete with $escapes).
Definition: lexer.h:79
Edge * AddEdge(const Rule *rule)
Definition: state.cc:103
Parses .ninja files.
An Env which contains a mapping of variables to values as well as a pointer to a parent scope...
Definition: eval_env.h:35
void AddOut(Edge *edge, StringPiece path)
Definition: state.cc:152
bool ParseEdge(string *err)
void AddRule(const Rule *rule)
Definition: state.cc:79
BindingEnv * env_
Definition: graph.h:158
An invokable build command and associated metadata (description, etc.).
Definition: graph.h:116
string DescribeLastError()
If the last token read was an ERROR token, provide more info or the empty string. ...
Definition: lexer.cc:103
A pool for delayed edges.
Definition: state.h:39
bool empty() const
Definition: eval_env.h:63
void AddPool(Pool *pool)
Definition: state.cc:91
Token
Definition: lexer.h:32
bool ParseLet(string *key, EvalString *val, string *err)
#define METRIC_RECORD(name)
The primary interface to metrics.
Definition: metrics.h:85
BindingEnv bindings_
Definition: state.h:130
bool ReadIdent(string *out)
Read a simple identifier (a rule or variable name).
Definition: lexer.cc:509
Pool * pool_
Definition: graph.h:155
void AddBinding(const string &key, const EvalString &val)
Definition: graph.cc:36
bool ExpectToken(Lexer::Token expected, string *err)
If the next token is not expected, produce an error string saying "expectd foo, got bar"...
bool ReadVarValue(EvalString *value, string *err)
Read the value side of a var = value line (complete with $escapes).
Definition: lexer.h:85
bool AddDefault(StringPiece path, string *error)
Definition: state.cc:164
string GetBinding(const string &key)
Definition: graph.cc:284
bool ParseRule(string *err)
void AddBinding(const string &key, const string &val)
Definition: eval_env.cc:26
static const char * TokenName(Token t)
Return a human-readable form of a token, used in error messages.
Definition: lexer.cc:73
Global state (file status, loaded rules) for a single run.
Definition: state.h:83
map< string, EvalString > bindings_
Definition: graph.h:133
FileReader * file_reader_
string Evaluate(Env *env) const
Definition: eval_env.cc:46
bool ParseFileInclude(bool new_scope, string *err)
Parse either a 'subninja' or 'include' line.
A tokenized string that contains variable references.
Definition: eval_env.h:59
bool Parse(const string &filename, const string &input, string *err)
Parse a file, given its contents as a string.
bool ParseDefault(string *err)
const Rule * LookupRule(const string &rule_name)
Definition: state.cc:84
void Start(StringPiece filename, StringPiece input)
Start parsing some input.
Definition: lexer.cc:66
ManifestParser(State *state, FileReader *file_reader)
vector< Node * > outputs_
Definition: graph.h:157