Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Commit f8f2937

Browse files
author
Mohamed Bamakhrama
committed
Allow scoping rules through subninja
Ninja didn't support scoping rules through subninja and assumed a unique rule name in the whole namespace. With this change, this behavior is changed to allow scoping rules. Two rules can have the same name if they belong to two different scopes. However, two rules can NOT have the same name in the same scope.
1 parent c406d1c commit f8f2937

10 files changed

+104
-87
lines changed

src/clean.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ int Cleaner::CleanRule(const char* rule) {
220220
assert(rule);
221221

222222
Reset();
223-
const Rule* r = state_->LookupRule(rule);
223+
const Rule* r = state_->bindings_.LookupRule(rule);
224224
if (r) {
225225
CleanRule(r);
226226
} else {
@@ -237,7 +237,7 @@ int Cleaner::CleanRules(int rule_count, char* rules[]) {
237237
PrintHeader();
238238
for (int i = 0; i < rule_count; ++i) {
239239
const char* rule_name = rules[i];
240-
const Rule* rule = state_->LookupRule(rule_name);
240+
const Rule* rule = state_->bindings_.LookupRule(rule_name);
241241
if (rule) {
242242
if (IsVerbose())
243243
printf("Rule %s\n", rule_name);

src/eval_env.cc

+51
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
#include <assert.h>
16+
1517
#include "eval_env.h"
1618

1719
string BindingEnv::LookupVariable(const string& var) {
@@ -27,6 +29,55 @@ void BindingEnv::AddBinding(const string& key, const string& val) {
2729
bindings_[key] = val;
2830
}
2931

32+
void BindingEnv::AddRule(const Rule* rule) {
33+
assert(LookupRule(rule->name()) == NULL);
34+
rules_[rule->name()] = rule;
35+
}
36+
37+
const Rule* BindingEnv::LookupRuleCurrentScope(const string& rule_name) {
38+
map<string, const Rule*>::iterator i = rules_.find(rule_name);
39+
if (i == rules_.end())
40+
return NULL;
41+
return i->second;
42+
}
43+
44+
const Rule* BindingEnv::LookupRule(const string& rule_name) {
45+
map<string, const Rule*>::iterator i = rules_.find(rule_name);
46+
if (i != rules_.end())
47+
return i->second;
48+
if (parent_)
49+
return parent_->LookupRule(rule_name);
50+
return NULL;
51+
}
52+
53+
void Rule::AddBinding(const string& key, const EvalString& val) {
54+
bindings_[key] = val;
55+
}
56+
57+
const EvalString* Rule::GetBinding(const string& key) const {
58+
map<string, EvalString>::const_iterator i = bindings_.find(key);
59+
if (i == bindings_.end())
60+
return NULL;
61+
return &i->second;
62+
}
63+
64+
// static
65+
bool Rule::IsReservedBinding(const string& var) {
66+
return var == "command" ||
67+
var == "depfile" ||
68+
var == "description" ||
69+
var == "deps" ||
70+
var == "generator" ||
71+
var == "pool" ||
72+
var == "restat" ||
73+
var == "rspfile" ||
74+
var == "rspfile_content";
75+
}
76+
77+
const map<string, const Rule*> BindingEnv::GetRules() const {
78+
return rules_;
79+
}
80+
3081
string BindingEnv::LookupWithFallback(const string& var,
3182
const EvalString* eval,
3283
Env* env) {

src/eval_env.h

+28
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,32 @@ using namespace std;
2424

2525
struct EvalString;
2626

27+
/// An invokable build command and associated metadata (description, etc.).
28+
struct Rule {
29+
explicit Rule(const string& name) : name_(name) {}
30+
31+
const string& name() const { return name_; }
32+
33+
typedef map<string, EvalString> Bindings;
34+
void AddBinding(const string& key, const EvalString& val);
35+
36+
static bool IsReservedBinding(const string& var);
37+
38+
const EvalString* GetBinding(const string& key) const;
39+
40+
private:
41+
// Allow the parsers to reach into this object and fill out its fields.
42+
friend struct ManifestParser;
43+
44+
string name_;
45+
map<string, EvalString> bindings_;
46+
};
47+
2748
/// An interface for a scope for variable (e.g. "$foo") lookups.
2849
struct Env {
2950
virtual ~Env() {}
3051
virtual string LookupVariable(const string& var) = 0;
52+
virtual const Rule* LookupRule(const string& rule_name) = 0;
3153
};
3254

3355
/// An Env which contains a mapping of variables to values
@@ -39,6 +61,11 @@ struct BindingEnv : public Env {
3961
virtual ~BindingEnv() {}
4062
virtual string LookupVariable(const string& var);
4163

64+
void AddRule(const Rule* rule);
65+
const Rule* LookupRule(const string& rule_name);
66+
const Rule* LookupRuleCurrentScope(const string& rule_name);
67+
const map<string, const Rule*> GetRules() const;
68+
4269
void AddBinding(const string& key, const string& val);
4370

4471
/// This is tricky. Edges want lookup scope to go in this order:
@@ -51,6 +78,7 @@ struct BindingEnv : public Env {
5178

5279
private:
5380
map<string, string> bindings_;
81+
map<string, const Rule*> rules_;
5482
Env* parent_;
5583
};
5684

src/graph.cc

+5-24
Original file line numberDiff line numberDiff line change
@@ -33,30 +33,6 @@ bool Node::Stat(DiskInterface* disk_interface) {
3333
return mtime_ > 0;
3434
}
3535

36-
void Rule::AddBinding(const string& key, const EvalString& val) {
37-
bindings_[key] = val;
38-
}
39-
40-
const EvalString* Rule::GetBinding(const string& key) const {
41-
map<string, EvalString>::const_iterator i = bindings_.find(key);
42-
if (i == bindings_.end())
43-
return NULL;
44-
return &i->second;
45-
}
46-
47-
// static
48-
bool Rule::IsReservedBinding(const string& var) {
49-
return var == "command" ||
50-
var == "depfile" ||
51-
var == "description" ||
52-
var == "deps" ||
53-
var == "generator" ||
54-
var == "pool" ||
55-
var == "restat" ||
56-
var == "rspfile" ||
57-
var == "rspfile_content";
58-
}
59-
6036
bool DependencyScan::RecomputeDirty(Edge* edge, string* err) {
6137
bool dirty = false;
6238
edge->outputs_ready_ = true;
@@ -231,6 +207,7 @@ struct EdgeEnv : public Env {
231207
EdgeEnv(Edge* edge, EscapeKind escape)
232208
: edge_(edge), escape_in_out_(escape) {}
233209
virtual string LookupVariable(const string& var);
210+
virtual const Rule* LookupRule(const string& rule_name);
234211

235212
/// Given a span of Nodes, construct a list of paths suitable for a command
236213
/// line.
@@ -242,6 +219,10 @@ struct EdgeEnv : public Env {
242219
EscapeKind escape_in_out_;
243220
};
244221

222+
const Rule* EdgeEnv::LookupRule(const string& rule_name) {
223+
return NULL;
224+
}
225+
245226
string EdgeEnv::LookupVariable(const string& var) {
246227
if (var == "in" || var == "in_newline") {
247228
int explicit_deps_count = edge_->inputs_.size() - edge_->implicit_deps_ -

src/graph.h

-21
Original file line numberDiff line numberDiff line change
@@ -121,27 +121,6 @@ struct Node {
121121
int id_;
122122
};
123123

124-
/// An invokable build command and associated metadata (description, etc.).
125-
struct Rule {
126-
explicit Rule(const string& name) : name_(name) {}
127-
128-
const string& name() const { return name_; }
129-
130-
typedef map<string, EvalString> Bindings;
131-
void AddBinding(const string& key, const EvalString& val);
132-
133-
static bool IsReservedBinding(const string& var);
134-
135-
const EvalString* GetBinding(const string& key) const;
136-
137-
private:
138-
// Allow the parsers to reach into this object and fill out its fields.
139-
friend struct ManifestParser;
140-
141-
string name_;
142-
map<string, EvalString> bindings_;
143-
};
144-
145124
/// An edge in the dependency graph; links between Nodes using Rules.
146125
struct Edge {
147126
Edge() : rule_(NULL), env_(NULL), outputs_ready_(false), deps_missing_(false),

src/manifest_parser.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ bool ManifestParser::ParseRule(string* err) {
156156
if (!ExpectToken(Lexer::NEWLINE, err))
157157
return false;
158158

159-
if (state_->LookupRule(name) != NULL)
159+
if (env_->LookupRuleCurrentScope(name) != NULL)
160160
return lexer_.Error("duplicate rule '" + name + "'", err);
161161

162162
Rule* rule = new Rule(name); // XXX scoped_ptr
@@ -185,7 +185,7 @@ bool ManifestParser::ParseRule(string* err) {
185185
if (rule->bindings_["command"].empty())
186186
return lexer_.Error("expected 'command =' line", err);
187187

188-
state_->AddRule(rule);
188+
env_->AddRule(rule);
189189
return true;
190190
}
191191

@@ -252,7 +252,7 @@ bool ManifestParser::ParseEdge(string* err) {
252252
if (!lexer_.ReadIdent(&rule_name))
253253
return lexer_.Error("expected build command name", err);
254254

255-
const Rule* rule = state_->LookupRule(rule_name);
255+
const Rule* rule = env_->LookupRule(rule_name);
256256
if (!rule)
257257
return lexer_.Error("unknown build rule '" + rule_name + "'", err);
258258

src/manifest_parser_test.cc

+12-16
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ TEST_F(ParserTest, Rules) {
6060
"\n"
6161
"build result: cat in_1.cc in-2.O\n"));
6262

63-
ASSERT_EQ(3u, state.rules_.size());
64-
const Rule* rule = state.rules_.begin()->second;
63+
ASSERT_EQ(3u, state.bindings_.GetRules().size());
64+
const Rule* rule = state.bindings_.GetRules().begin()->second;
6565
EXPECT_EQ("cat", rule->name());
6666
EXPECT_EQ("[cat ][$in][ > ][$out]",
6767
rule->GetBinding("command")->Serialize());
@@ -93,8 +93,8 @@ TEST_F(ParserTest, IgnoreIndentedComments) {
9393
"build result: cat in_1.cc in-2.O\n"
9494
" #comment\n"));
9595

96-
ASSERT_EQ(2u, state.rules_.size());
97-
const Rule* rule = state.rules_.begin()->second;
96+
ASSERT_EQ(2u, state.bindings_.GetRules().size());
97+
const Rule* rule = state.bindings_.GetRules().begin()->second;
9898
EXPECT_EQ("cat", rule->name());
9999
Edge* edge = state.GetNode("result", 0)->in_edge();
100100
EXPECT_TRUE(edge->GetBindingBool("restat"));
@@ -126,8 +126,8 @@ TEST_F(ParserTest, ResponseFiles) {
126126
"build out: cat_rsp in\n"
127127
" rspfile=out.rsp\n"));
128128

129-
ASSERT_EQ(2u, state.rules_.size());
130-
const Rule* rule = state.rules_.begin()->second;
129+
ASSERT_EQ(2u, state.bindings_.GetRules().size());
130+
const Rule* rule = state.bindings_.GetRules().begin()->second;
131131
EXPECT_EQ("cat_rsp", rule->name());
132132
EXPECT_EQ("[cat ][$rspfile][ > ][$out]",
133133
rule->GetBinding("command")->Serialize());
@@ -143,8 +143,8 @@ TEST_F(ParserTest, InNewline) {
143143
"build out: cat_rsp in in2\n"
144144
" rspfile=out.rsp\n"));
145145

146-
ASSERT_EQ(2u, state.rules_.size());
147-
const Rule* rule = state.rules_.begin()->second;
146+
ASSERT_EQ(2u, state.bindings_.GetRules().size());
147+
const Rule* rule = state.bindings_.GetRules().begin()->second;
148148
EXPECT_EQ("cat_rsp", rule->name());
149149
EXPECT_EQ("[cat ][$in_newline][ > ][$out]",
150150
rule->GetBinding("command")->Serialize());
@@ -204,8 +204,8 @@ TEST_F(ParserTest, Continuation) {
204204
"build a: link c $\n"
205205
" d e f\n"));
206206

207-
ASSERT_EQ(2u, state.rules_.size());
208-
const Rule* rule = state.rules_.begin()->second;
207+
ASSERT_EQ(2u, state.bindings_.GetRules().size());
208+
const Rule* rule = state.bindings_.GetRules().begin()->second;
209209
EXPECT_EQ("link", rule->name());
210210
EXPECT_EQ("[foo bar baz]", rule->GetBinding("command")->Serialize());
211211
}
@@ -823,18 +823,14 @@ TEST_F(ParserTest, MissingSubNinja) {
823823
}
824824

825825
TEST_F(ParserTest, DuplicateRuleInDifferentSubninjas) {
826-
// Test that rules live in a global namespace and aren't scoped to subninjas.
826+
// Test that rules are scoped to subninjas.
827827
files_["test.ninja"] = "rule cat\n"
828828
" command = cat\n";
829829
ManifestParser parser(&state, this);
830830
string err;
831-
EXPECT_FALSE(parser.ParseTest("rule cat\n"
831+
EXPECT_TRUE(parser.ParseTest("rule cat\n"
832832
" command = cat\n"
833833
"subninja test.ninja\n", &err));
834-
EXPECT_EQ("test.ninja:1: duplicate rule 'cat'\n"
835-
"rule cat\n"
836-
" ^ near here"
837-
, err);
838834
}
839835

840836
TEST_F(ParserTest, Include) {

src/state.cc

+1-13
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,11 @@ Pool State::kConsolePool("console", 1);
7373
const Rule State::kPhonyRule("phony");
7474

7575
State::State() {
76-
AddRule(&kPhonyRule);
76+
bindings_.AddRule(&kPhonyRule);
7777
AddPool(&kDefaultPool);
7878
AddPool(&kConsolePool);
7979
}
8080

81-
void State::AddRule(const Rule* rule) {
82-
assert(LookupRule(rule->name()) == NULL);
83-
rules_[rule->name()] = rule;
84-
}
85-
86-
const Rule* State::LookupRule(const string& rule_name) {
87-
map<string, const Rule*>::iterator i = rules_.find(rule_name);
88-
if (i == rules_.end())
89-
return NULL;
90-
return i->second;
91-
}
92-
9381
void State::AddPool(Pool* pool) {
9482
assert(LookupPool(pool->name()) == NULL);
9583
pools_[pool->name()] = pool;

src/state.h

+1-7
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,14 @@ struct Pool {
7979
DelayedEdges delayed_;
8080
};
8181

82-
/// Global state (file status, loaded rules) for a single run.
82+
/// Global state (file status) for a single run.
8383
struct State {
8484
static Pool kDefaultPool;
8585
static Pool kConsolePool;
8686
static const Rule kPhonyRule;
8787

8888
State();
8989

90-
void AddRule(const Rule* rule);
91-
const Rule* LookupRule(const string& rule_name);
92-
9390
void AddPool(Pool* pool);
9491
Pool* LookupPool(const string& pool_name);
9592

@@ -119,9 +116,6 @@ struct State {
119116
typedef ExternalStringHashMap<Node*>::Type Paths;
120117
Paths paths_;
121118

122-
/// All the rules used in the graph.
123-
map<string, const Rule*> rules_;
124-
125119
/// All the pools used in the graph.
126120
map<string, Pool*> pools_;
127121

src/state_test.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ TEST(State, Basic) {
2929

3030
Rule* rule = new Rule("cat");
3131
rule->AddBinding("command", command);
32-
state.AddRule(rule);
32+
state.bindings_.AddRule(rule);
3333

3434
Edge* edge = state.AddEdge(rule);
3535
state.AddIn(edge, "in1", 0);

0 commit comments

Comments
 (0)