1 // Copyright 2015 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 // +build ignore
16
17 #include "rule.h"
18
19 #include "expr.h"
20 #include "log.h"
21 #include "parser.h"
22 #include "stringprintf.h"
23 #include "strutil.h"
24 #include "symtab.h"
25
Rule()26 Rule::Rule() : is_double_colon(false), is_suffix_rule(false), cmd_lineno(0) {}
27
ParseInputs(const StringPiece & inputs_str)28 void Rule::ParseInputs(const StringPiece& inputs_str) {
29 bool is_order_only = false;
30 for (auto const& input : WordScanner(inputs_str)) {
31 if (input == "|") {
32 is_order_only = true;
33 continue;
34 }
35 Symbol input_sym = Intern(TrimLeadingCurdir(input));
36 (is_order_only ? order_only_inputs : inputs).push_back(input_sym);
37 }
38 }
39
ParsePrerequisites(const StringPiece & line,size_t separator_pos,const RuleStmt * rule_stmt)40 void Rule::ParsePrerequisites(const StringPiece& line,
41 size_t separator_pos,
42 const RuleStmt* rule_stmt) {
43 // line is either
44 // prerequisites [ ; command ]
45 // or
46 // target-prerequisites : prereq-patterns [ ; command ]
47 // First, separate command. At this point separator_pos should point to ';'
48 // unless null.
49 StringPiece prereq_string = line;
50 if (separator_pos != string::npos &&
51 rule_stmt->sep != RuleStmt::SEP_SEMICOLON) {
52 CHECK(line[separator_pos] == ';');
53 // TODO: Maybe better to avoid Intern here?
54 cmds.push_back(Value::NewLiteral(
55 Intern(TrimLeftSpace(line.substr(separator_pos + 1))).str()));
56 prereq_string = line.substr(0, separator_pos);
57 }
58
59 if ((separator_pos = prereq_string.find(':')) == string::npos) {
60 // Simple prerequisites
61 ParseInputs(prereq_string);
62 return;
63 }
64
65 // Static pattern rule.
66 if (!output_patterns.empty()) {
67 ERROR_LOC(loc, "*** mixed implicit and normal rules: deprecated syntax");
68 }
69
70 // Empty static patterns should not produce rules, but need to eat the
71 // commands So return a rule with no outputs nor output_patterns
72 if (outputs.empty()) {
73 return;
74 }
75
76 StringPiece target_prereq = prereq_string.substr(0, separator_pos);
77 StringPiece prereq_patterns = prereq_string.substr(separator_pos + 1);
78
79 for (StringPiece target_pattern : WordScanner(target_prereq)) {
80 target_pattern = TrimLeadingCurdir(target_pattern);
81 for (Symbol target : outputs) {
82 if (!Pattern(target_pattern).Match(target.str())) {
83 WARN_LOC(loc, "target `%s' doesn't match the target pattern",
84 target.c_str());
85 }
86 }
87 output_patterns.push_back(Intern(target_pattern));
88 }
89
90 if (output_patterns.empty()) {
91 ERROR_LOC(loc, "*** missing target pattern.");
92 }
93 if (output_patterns.size() > 1) {
94 ERROR_LOC(loc, "*** multiple target patterns.");
95 }
96 if (!IsPatternRule(output_patterns[0].str())) {
97 ERROR_LOC(loc, "*** target pattern contains no '%%'.");
98 }
99 ParseInputs(prereq_patterns);
100 }
101
DebugString() const102 string Rule::DebugString() const {
103 vector<string> v;
104 v.push_back(StringPrintf("outputs=[%s]", JoinSymbols(outputs, ",").c_str()));
105 v.push_back(StringPrintf("inputs=[%s]", JoinSymbols(inputs, ",").c_str()));
106 if (!order_only_inputs.empty()) {
107 v.push_back(StringPrintf("order_only_inputs=[%s]",
108 JoinSymbols(order_only_inputs, ",").c_str()));
109 }
110 if (!output_patterns.empty()) {
111 v.push_back(StringPrintf("output_patterns=[%s]",
112 JoinSymbols(output_patterns, ",").c_str()));
113 }
114 if (is_double_colon)
115 v.push_back("is_double_colon");
116 if (is_suffix_rule)
117 v.push_back("is_suffix_rule");
118 if (!cmds.empty()) {
119 v.push_back(StringPrintf("cmds=[%s]", JoinValues(cmds, ",").c_str()));
120 }
121 return JoinStrings(v, " ");
122 }
123