blob: fe0c2a845f5419c41aff6f6bd4b8dd377ad8284a [file] [log] [blame]
Shinichiro Hamaji1d545aa2015-06-23 15:29:13 +09001// 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
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090015#include "rule.h"
16
17#include "log.h"
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090018#include "parser.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090019#include "stringprintf.h"
20#include "strutil.h"
21#include "value.h"
22
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090023namespace {
24
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090025// Strip leading sequences of './' from file names, so that ./file
26// and file are considered to be the same file.
27// From http://www.gnu.org/software/make/manual/make.html#Features
28StringPiece TrimLeadingCurdir(StringPiece s) {
29 if (s.substr(0, 2) != "./")
30 return s;
31 return s.substr(2);
32}
33
34static void ParseInputs(Rule* r, StringPiece s) {
35 bool is_order_only = false;
36 for (StringPiece input : WordScanner(s)) {
37 if (input == "|") {
38 is_order_only = true;
39 continue;
40 }
41 input = Intern(TrimLeadingCurdir(input));
42 if (is_order_only) {
43 r->order_only_inputs.push_back(input);
44 } else {
45 r->inputs.push_back(input);
46 }
47 }
48}
49
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090050bool IsPatternRule(StringPiece s) {
51 return s.find('%') != string::npos;
52}
53
54} // namespace
55
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090056Rule::Rule()
57 : is_double_colon(false),
58 is_suffix_rule(false),
Shinichiro Hamaji0562c302015-06-19 15:30:49 +090059 cmd_lineno(0) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090060}
61
Shinichiro Hamaji784b9952015-06-23 14:29:32 +090062void ParseRule(Loc& loc, StringPiece line, bool is_assign,
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090063 Rule** out_rule, RuleVar* rule_var) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090064 size_t index = line.find(':');
65 if (index == string::npos) {
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090066 ERROR("%s:%d: *** missing separator.", LOCF(loc));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090067 }
68
69 StringPiece first = line.substr(0, index);
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090070 vector<StringPiece> outputs;
71 for (StringPiece tok : WordScanner(first)) {
72 outputs.push_back(Intern(TrimLeadingCurdir(tok)));
73 }
74
75 CHECK(!outputs.empty());
76 const bool is_first_pattern = IsPatternRule(outputs[0]);
77 if (is_first_pattern) {
78 if (outputs.size() > 1) {
79 // TODO: Multiple output patterns are not supported yet.
80 ERROR("%s:%d: *** mixed implicit and normal rules: deprecated syntax",
81 LOCF(loc));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090082 }
83 }
84
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090085 bool is_double_colon = false;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090086 index++;
87 if (line.get(index) == ':') {
88 is_double_colon = true;
89 index++;
90 }
91
92 StringPiece rest = line.substr(index);
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090093 size_t equal_index = rest.find('=');
Shinichiro Hamaji784b9952015-06-23 14:29:32 +090094 if (equal_index != string::npos || is_assign) {
95 if (equal_index == string::npos)
96 equal_index = rest.size();
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090097 rule_var->outputs.swap(outputs);
98 ParseAssignStatement(rest, equal_index,
99 &rule_var->lhs, &rule_var->rhs, &rule_var->op);
100 *out_rule = NULL;
101 return;
102 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900103
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900104 Rule* rule = new Rule();
105 *out_rule = rule;
106 rule->loc = loc;
107 rule->is_double_colon = is_double_colon;
108 if (is_first_pattern) {
109 rule->output_patterns.swap(outputs);
110 } else {
111 rule->outputs.swap(outputs);
112 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900113
114 index = rest.find(':');
115 if (index == string::npos) {
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900116 ParseInputs(rule, rest);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900117 return;
118 }
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900119
120 if (is_first_pattern) {
121 ERROR("%s:%d: *** mixed implicit and normal rules: deprecated syntax",
122 LOCF(loc));
123 }
124
125 StringPiece second = rest.substr(0, index);
126 StringPiece third = rest.substr(index+1);
127
128 for (StringPiece tok : WordScanner(second)) {
129 rule->output_patterns.push_back(tok);
130 }
131
132 if (rule->output_patterns.empty()) {
133 ERROR("%s:%d: *** missing target pattern.", LOCF(loc));
134 }
135 if (rule->output_patterns.size() > 1) {
136 ERROR("%s:%d: *** multiple target patterns.", LOCF(loc));
137 }
138 if (!IsPatternRule(rule->output_patterns[0])) {
139 ERROR("%s:%d: *** target pattern contains no '%%'.", LOCF(loc));
140 }
141 ParseInputs(rule, third);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900142}
143
144string Rule::DebugString() const {
145 vector<string> v;
146 v.push_back(StringPrintf("outputs=[%s]", JoinStrings(outputs, ",").c_str()));
147 v.push_back(StringPrintf("inputs=[%s]", JoinStrings(inputs, ",").c_str()));
148 if (!order_only_inputs.empty()) {
149 v.push_back(StringPrintf("order_only_inputs=[%s]",
150 JoinStrings(order_only_inputs, ",").c_str()));
151 }
152 if (is_double_colon)
153 v.push_back("is_double_colon");
154 if (is_suffix_rule)
155 v.push_back("is_suffix_rule");
156 if (!cmds.empty()) {
157 v.push_back(StringPrintf("cmds=[%s]", JoinValues(cmds, ",").c_str()));
158 }
159 return JoinStrings(v, " ");
160}