OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/err.h" | 5 #include "tools/gn/err.h" |
6 #include "tools/gn/functions.h" | 6 #include "tools/gn/functions.h" |
7 #include "tools/gn/parse_tree.h" | 7 #include "tools/gn/parse_tree.h" |
8 #include "tools/gn/scope.h" | 8 #include "tools/gn/scope.h" |
9 | 9 |
10 namespace functions { | 10 namespace functions { |
11 | 11 |
12 namespace { | 12 namespace { |
13 | 13 |
14 void ForwardAllValues(const FunctionCallNode* function, | 14 void ForwardAllValues(const FunctionCallNode* function, |
15 Scope* source, | 15 Scope* source, |
16 Scope* dest, | 16 Scope* dest, |
17 const std::set<std::string>& exclusion_set, | |
17 Err* err) { | 18 Err* err) { |
18 Scope::MergeOptions options; | 19 Scope::MergeOptions options; |
19 // This function needs to clobber existing for it to be useful. It will be | 20 // This function needs to clobber existing for it to be useful. It will be |
20 // called in a template to forward all values, but there will be some | 21 // called in a template to forward all values, but there will be some |
21 // default stuff like configs set up in both scopes, so it would always | 22 // default stuff like configs set up in both scopes, so it would always |
22 // fail if it didn't clobber. | 23 // fail if it didn't clobber. |
23 options.clobber_existing = true; | 24 options.clobber_existing = true; |
24 options.skip_private_vars = true; | 25 options.skip_private_vars = true; |
25 options.mark_dest_used = false; | 26 options.mark_dest_used = false; |
27 options.excluded_values = exclusion_set; | |
26 source->NonRecursiveMergeTo(dest, options, function, | 28 source->NonRecursiveMergeTo(dest, options, function, |
27 "source scope", err); | 29 "source scope", err); |
28 source->MarkAllUsed(); | 30 source->MarkAllUsed(); |
29 } | 31 } |
30 | 32 |
31 void ForwardValuesFromList(Scope* source, | 33 void ForwardValuesFromList(Scope* source, |
32 Scope* dest, | 34 Scope* dest, |
33 const std::vector<Value>& list, | 35 const std::vector<Value>& list, |
36 const std::set<std::string>& exclusion_set, | |
34 Err* err) { | 37 Err* err) { |
35 for (const Value& cur : list) { | 38 for (const Value& cur : list) { |
36 if (!cur.VerifyTypeIs(Value::STRING, err)) | 39 if (!cur.VerifyTypeIs(Value::STRING, err)) |
37 return; | 40 return; |
41 if (exclusion_set.find(cur.string_value()) != exclusion_set.end()) | |
42 continue; | |
38 const Value* value = source->GetValue(cur.string_value(), true); | 43 const Value* value = source->GetValue(cur.string_value(), true); |
39 if (value) { | 44 if (value) { |
40 // Use the storage key for the original value rather than the string in | 45 // Use the storage key for the original value rather than the string in |
41 // "cur" because "cur" is a temporary that will be deleted, and Scopes | 46 // "cur" because "cur" is a temporary that will be deleted, and Scopes |
42 // expect a persistent StringPiece (it won't copy). Not doing this will | 47 // expect a persistent StringPiece (it won't copy). Not doing this will |
43 // lead the scope's key to point to invalid memory after this returns. | 48 // lead the scope's key to point to invalid memory after this returns. |
44 base::StringPiece storage_key = source->GetStorageKey(cur.string_value()); | 49 base::StringPiece storage_key = source->GetStorageKey(cur.string_value()); |
45 if (storage_key.empty()) { | 50 if (storage_key.empty()) { |
46 // Programmatic value, don't allow copying. | 51 // Programmatic value, don't allow copying. |
47 *err = Err(cur, "This value can't be forwarded.", | 52 *err = Err(cur, "This value can't be forwarded.", |
(...skipping 13 matching lines...) Expand all Loading... | |
61 } // namespace | 66 } // namespace |
62 | 67 |
63 const char kForwardVariablesFrom[] = "forward_variables_from"; | 68 const char kForwardVariablesFrom[] = "forward_variables_from"; |
64 const char kForwardVariablesFrom_HelpShort[] = | 69 const char kForwardVariablesFrom_HelpShort[] = |
65 "forward_variables_from: Copies variables from a different scope."; | 70 "forward_variables_from: Copies variables from a different scope."; |
66 const char kForwardVariablesFrom_Help[] = | 71 const char kForwardVariablesFrom_Help[] = |
67 "forward_variables_from: Copies variables from a different scope.\n" | 72 "forward_variables_from: Copies variables from a different scope.\n" |
68 "\n" | 73 "\n" |
69 " forward_variables_from(from_scope, variable_list_or_star)\n" | 74 " forward_variables_from(from_scope, variable_list_or_star)\n" |
70 "\n" | 75 "\n" |
76 " forward_variables_from(from_scope, variable_list_or_star,\n" | |
brettw
2016/01/25 20:44:41
Check out the help for rebase_path, I used C++-sty
sdefresne
2016/01/26 11:59:44
Done.
| |
77 " variable_to_not_forward_list)\n" | |
78 "\n" | |
71 " Copies the given variables from the given scope to the local scope\n" | 79 " Copies the given variables from the given scope to the local scope\n" |
72 " if they exist. This is normally used in the context of templates to\n" | 80 " if they exist. This is normally used in the context of templates to\n" |
73 " use the values of variables defined in the template invocation to\n" | 81 " use the values of variables defined in the template invocation to\n" |
74 " a template-defined target.\n" | 82 " a template-defined target.\n" |
75 "\n" | 83 "\n" |
76 " The variables in the given variable_list will be copied if they exist\n" | 84 " The variables in the given variable_list will be copied if they exist\n" |
77 " in the given scope or any enclosing scope. If they do not exist,\n" | 85 " in the given scope or any enclosing scope. If they do not exist,\n" |
78 " nothing will happen and they be left undefined in the current scope.\n" | 86 " nothing will happen and they be left undefined in the current scope.\n" |
79 "\n" | 87 "\n" |
80 " As a special case, if the variable_list is a string with the value of\n" | 88 " As a special case, if the variable_list is a string with the value of\n" |
81 " \"*\", all variables from the given scope will be copied. \"*\" only\n" | 89 " \"*\", all variables from the given scope will be copied. \"*\" only\n" |
82 " copies variables set directly on the from_scope, not enclosing ones.\n" | 90 " copies variables set directly on the from_scope, not enclosing ones.\n" |
83 " Otherwise it would duplicate all global variables.\n" | 91 " Otherwise it would duplicate all global variables.\n" |
84 "\n" | 92 "\n" |
85 " When an explicit list of variables is supplied, if the variable exists\n" | 93 " When an explicit list of variables is supplied, if the variable exists\n" |
86 " in the current (destination) scope already, an error will be thrown.\n" | 94 " in the current (destination) scope already, an error will be thrown.\n" |
87 " If \"*\" is specified, variables in the current scope will be\n" | 95 " If \"*\" is specified, variables in the current scope will be\n" |
88 " clobbered (the latter is important because most targets have an\n" | 96 " clobbered (the latter is important because most targets have an\n" |
89 " implicit configs list, which means it wouldn't work at all if it\n" | 97 " implicit configs list, which means it wouldn't work at all if it\n" |
90 " didn't clobber).\n" | 98 " didn't clobber).\n" |
91 "\n" | 99 "\n" |
92 " The sources assignment filter (see \"gn help " | 100 " The sources assignment filter (see \"gn help " |
93 "set_sources_assignment_filter\")\n" | 101 "set_sources_assignment_filter\")\n" |
94 " is never applied by this function. It's assumed than any desired\n" | 102 " is never applied by this function. It's assumed than any desired\n" |
95 " filtering was already done when sources was set on the from_scope.\n" | 103 " filtering was already done when sources was set on the from_scope.\n" |
96 "\n" | 104 "\n" |
105 " The second form of the function allows to give a list of variables not\n" | |
106 " to forward. This is mostly useful when used in combination with \"*\".\n" | |
107 "\n" | |
97 "Examples\n" | 108 "Examples\n" |
98 "\n" | 109 "\n" |
99 " # This is a common action template. It would invoke a script with\n" | 110 " # This is a common action template. It would invoke a script with\n" |
100 " # some given parameters, and wants to use the various types of deps\n" | 111 " # some given parameters, and wants to use the various types of deps\n" |
101 " # and the visibility from the invoker if it's defined. It also injects\n" | 112 " # and the visibility from the invoker if it's defined. It also injects\n" |
102 " # an additional dependency to all targets.\n" | 113 " # an additional dependency to all targets.\n" |
103 " template(\"my_test\") {\n" | 114 " template(\"my_test\") {\n" |
104 " action(target_name) {\n" | 115 " action(target_name) {\n" |
105 " forward_variables_from(invoker, [ \"data_deps\", \"deps\",\n" | 116 " forward_variables_from(invoker, [ \"data_deps\", \"deps\",\n" |
106 " \"public_deps\", \"visibility\" " | 117 " \"public_deps\", \"visibility\" " |
107 "])\n" | 118 "])\n" |
108 " # Add our test code to the dependencies.\n" | 119 " # Add our test code to the dependencies.\n" |
109 " # \"deps\" may or may not be defined at this point.\n" | 120 " # \"deps\" may or may not be defined at this point.\n" |
110 " if (defined(deps)) {\n" | 121 " if (defined(deps)) {\n" |
111 " deps += [ \"//tools/doom_melon\" ]\n" | 122 " deps += [ \"//tools/doom_melon\" ]\n" |
112 " } else {\n" | 123 " } else {\n" |
113 " deps = [ \"//tools/doom_melon\" ]\n" | 124 " deps = [ \"//tools/doom_melon\" ]\n" |
114 " }\n" | 125 " }\n" |
115 " }\n" | 126 " }\n" |
116 " }\n" | 127 " }\n" |
117 "\n" | 128 "\n" |
118 " # This is a template around either a target whose type depends on a\n" | 129 " # This is a template around either a target whose type depends on a\n" |
119 " # global variable. It forwards all values from the invoker.\n" | 130 " # global variable. It forwards all values from the invoker.\n" |
120 " template(\"my_wrapper\") {\n" | 131 " template(\"my_wrapper\") {\n" |
121 " target(my_wrapper_target_type, target_name) {\n" | 132 " target(my_wrapper_target_type, target_name) {\n" |
122 " forward_variables_from(invoker, \"*\")\n" | 133 " forward_variables_from(invoker, \"*\")\n" |
123 " }\n" | 134 " }\n" |
124 " }\n"; | 135 " }\n" |
136 "\n" | |
137 " # This is a template around another template that uses a variable to\n" | |
brettw
2016/01/25 20:44:41
How about "A template that wraps another. It adds
sdefresne
2016/01/26 11:59:44
Done.
| |
138 " # initialize another variable and is only interested in that one.\n" | |
139 " template(\"my_ios_test_app\") {\n" | |
140 " ios_test_app(target_name) {\n" | |
141 " forward_variables_from(invoker, \"*\", [\"test_bundle_name\"])\n" | |
142 " if (!defined(extra_substitutions)) {\n" | |
143 " extra_substitutions = []\n" | |
144 " }\n" | |
145 " extra_substitutions += [ \"BUNDLE_ID_TEST_NAME=$test_bundle_name\" " | |
146 "]\n" | |
147 " }\n" | |
148 " }\n"; | |
125 | 149 |
126 // This function takes a ListNode rather than a resolved vector of values | 150 // This function takes a ListNode rather than a resolved vector of values |
127 // both avoid copying the potentially-large source scope, and so the variables | 151 // both avoid copying the potentially-large source scope, and so the variables |
128 // in the source scope can be marked as used. | 152 // in the source scope can be marked as used. |
129 Value RunForwardVariablesFrom(Scope* scope, | 153 Value RunForwardVariablesFrom(Scope* scope, |
130 const FunctionCallNode* function, | 154 const FunctionCallNode* function, |
131 const ListNode* args_list, | 155 const ListNode* args_list, |
132 Err* err) { | 156 Err* err) { |
133 const std::vector<const ParseNode*>& args_vector = args_list->contents(); | 157 const std::vector<const ParseNode*>& args_vector = args_list->contents(); |
134 if (args_vector.size() != 2) { | 158 if (args_vector.size() != 2 && args_vector.size() != 3) { |
135 *err = Err(function, "Wrong number of arguments.", | 159 *err = Err(function, "Wrong number of arguments.", |
136 "Expecting exactly two."); | 160 "Expecting two or three arguments."); |
137 return Value(); | 161 return Value(); |
138 } | 162 } |
139 | 163 |
140 // Extract the scope identifier. This assumes the first parameter is an | 164 // Extract the scope identifier. This assumes the first parameter is an |
141 // identifier. It is difficult to write code where this is not the case, and | 165 // identifier. It is difficult to write code where this is not the case, and |
142 // this saves an expensive scope copy. If necessary, this could be expanded | 166 // this saves an expensive scope copy. If necessary, this could be expanded |
143 // to execute the ParseNode and get the value out if it's not an identifer. | 167 // to execute the ParseNode and get the value out if it's not an identifer. |
144 const IdentifierNode* identifier = args_vector[0]->AsIdentifier(); | 168 const IdentifierNode* identifier = args_vector[0]->AsIdentifier(); |
145 if (!identifier) { | 169 if (!identifier) { |
146 *err = Err(args_vector[0], "Expected an identifier for the scope."); | 170 *err = Err(args_vector[0], "Expected an identifier for the scope."); |
147 return Value(); | 171 return Value(); |
148 } | 172 } |
149 | 173 |
150 // Extract the source scope. | 174 // Extract the source scope. |
151 Value* value = scope->GetMutableValue(identifier->value().value(), true); | 175 Value* value = scope->GetMutableValue(identifier->value().value(), true); |
152 if (!value) { | 176 if (!value) { |
153 *err = Err(identifier, "Undefined identifier."); | 177 *err = Err(identifier, "Undefined identifier."); |
154 return Value(); | 178 return Value(); |
155 } | 179 } |
156 if (!value->VerifyTypeIs(Value::SCOPE, err)) | 180 if (!value->VerifyTypeIs(Value::SCOPE, err)) |
157 return Value(); | 181 return Value(); |
158 Scope* source = value->scope_value(); | 182 Scope* source = value->scope_value(); |
159 | 183 |
184 // Extract the exclusion list if defined. | |
185 std::set<std::string> exclusion_set; | |
186 if (args_vector.size() == 3) { | |
187 Value exclusion_value = args_vector[2]->Execute(scope, err); | |
188 if (err->has_error()) | |
189 return Value(); | |
190 | |
191 if (exclusion_value.type() != Value::LIST) { | |
192 *err = Err(exclusion_value, "Not a valid list of variables to exclude.", | |
193 "Expecting a list of strings."); | |
194 return Value(); | |
195 } | |
196 | |
197 for (const Value& cur : exclusion_value.list_value()) { | |
198 if (!cur.VerifyTypeIs(Value::STRING, err)) | |
199 return Value(); | |
200 | |
201 exclusion_set.insert(exclusion_set.end(), cur.string_value()); | |
brettw
2016/01/25 20:44:41
I think you can just delete the first parameter.
sdefresne
2016/01/26 11:59:44
Done.
| |
202 } | |
203 } | |
204 | |
160 // Extract the list. If all_values is not set, the what_value will be a list. | 205 // Extract the list. If all_values is not set, the what_value will be a list. |
161 Value what_value = args_vector[1]->Execute(scope, err); | 206 Value what_value = args_vector[1]->Execute(scope, err); |
162 if (err->has_error()) | 207 if (err->has_error()) |
163 return Value(); | 208 return Value(); |
164 if (what_value.type() == Value::STRING) { | 209 if (what_value.type() == Value::STRING) { |
165 if (what_value.string_value() == "*") { | 210 if (what_value.string_value() == "*") { |
166 ForwardAllValues(function, source, scope, err); | 211 ForwardAllValues(function, source, scope, exclusion_set, err); |
167 return Value(); | 212 return Value(); |
168 } | 213 } |
169 } else { | 214 } else { |
170 if (what_value.type() == Value::LIST) { | 215 if (what_value.type() == Value::LIST) { |
171 ForwardValuesFromList(source, scope, what_value.list_value(), err); | 216 ForwardValuesFromList(source, scope, what_value.list_value(), |
217 exclusion_set, err); | |
172 return Value(); | 218 return Value(); |
173 } | 219 } |
174 } | 220 } |
175 | 221 |
176 // Not the right type of argument. | 222 // Not the right type of argument. |
177 *err = Err(what_value, "Not a valid list of variables to copy.", | 223 *err = Err(what_value, "Not a valid list of variables to copy.", |
178 "Expecting either the string \"*\" or a list of strings."); | 224 "Expecting either the string \"*\" or a list of strings."); |
179 return Value(); | 225 return Value(); |
180 } | 226 } |
181 | 227 |
182 } // namespace functions | 228 } // namespace functions |
OLD | NEW |