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
3 // found in the LICENSE file.
5 #include "tools/gn/err.h"
6 #include "tools/gn/functions.h"
7 #include "tools/gn/parse_tree.h"
8 #include "tools/gn/scope.h"
14 void ForwardAllValues(const FunctionCallNode
* function
,
18 Scope::MergeOptions options
;
19 // 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 // default stuff like configs set up in both scopes, so it would always
22 // fail if it didn't clobber.
23 options
.clobber_existing
= true;
24 options
.skip_private_vars
= true;
25 options
.mark_dest_used
= false;
26 source
->NonRecursiveMergeTo(dest
, options
, function
,
28 source
->MarkAllUsed();
31 void ForwardValuesFromList(Scope
* source
,
33 const std::vector
<Value
>& list
,
35 for (const Value
& cur
: list
) {
36 if (!cur
.VerifyTypeIs(Value::STRING
, err
))
38 const Value
* value
= source
->GetValue(cur
.string_value(), true);
40 // 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
42 // 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.
44 base::StringPiece storage_key
= source
->GetStorageKey(cur
.string_value());
45 if (storage_key
.empty()) {
46 // Programmatic value, don't allow copying.
47 *err
= Err(cur
, "This value can't be forwarded.",
48 "The variable \"" + cur
.string_value() + "\" is a built-in.");
52 // Keep the origin information from the original value. The normal
53 // usage is for this to be used in a template, and if there's an error,
54 // the user expects to see the line where they set the variable
55 // blamed, rather than a template call to forward_variables_from().
56 dest
->SetValue(storage_key
, *value
, value
->origin());
63 const char kForwardVariablesFrom
[] = "forward_variables_from";
64 const char kForwardVariablesFrom_HelpShort
[] =
65 "forward_variables_from: Copies variables from a different scope.";
66 const char kForwardVariablesFrom_Help
[] =
67 "forward_variables_from: Copies variables from a different scope.\n"
69 " forward_variables_from(from_scope, variable_list_or_star)\n"
71 " 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"
73 " use the values of variables defined in the template invocation to\n"
74 " a template-defined target.\n"
76 " 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"
78 " nothing will happen and they be left undefined in the current scope.\n"
80 " 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"
82 " copies variables set directly on the from_scope, not enclosing ones.\n"
83 " Otherwise it would duplicate all global variables.\n"
85 " 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"
87 " If \"*\" is specified, variables in the current scope will be\n"
88 " 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"
92 " The sources assignment filter (see \"gn help "
93 "set_sources_assignment_filter\")\n"
94 " 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"
99 " # 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"
101 " # and the visibility from the invoker if it's defined. It also injects\n"
102 " # an additional dependency to all targets.\n"
103 " template(\"my_test\") {\n"
104 " action(target_name) {\n"
105 " forward_variables_from(invoker, [ \"data_deps\", \"deps\",\n"
106 " \"public_deps\", \"visibility\" "
108 " # Add our test code to the dependencies.\n"
109 " # \"deps\" may or may not be defined at this point.\n"
110 " if (defined(deps)) {\n"
111 " deps += [ \"//tools/doom_melon\" ]\n"
113 " deps = [ \"//tools/doom_melon\" ]\n"
118 " # 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"
120 " template(\"my_wrapper\") {\n"
121 " target(my_wrapper_target_type, target_name) {\n"
122 " forward_variables_from(invoker, \"*\")\n"
126 // 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
128 // in the source scope can be marked as used.
129 Value
RunForwardVariablesFrom(Scope
* scope
,
130 const FunctionCallNode
* function
,
131 const ListNode
* args_list
,
133 const std::vector
<const ParseNode
*>& args_vector
= args_list
->contents();
134 if (args_vector
.size() != 2) {
135 *err
= Err(function
, "Wrong number of arguments.",
136 "Expecting exactly two.");
140 // 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
142 // 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.
144 const IdentifierNode
* identifier
= args_vector
[0]->AsIdentifier();
146 *err
= Err(args_vector
[0], "Expected an identifier for the scope.");
150 // Extract the source scope.
151 Value
* value
= scope
->GetMutableValue(identifier
->value().value(), true);
153 *err
= Err(identifier
, "Undefined identifier.");
156 if (!value
->VerifyTypeIs(Value::SCOPE
, err
))
158 Scope
* source
= value
->scope_value();
160 // 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
);
162 if (err
->has_error())
164 if (what_value
.type() == Value::STRING
) {
165 if (what_value
.string_value() == "*") {
166 ForwardAllValues(function
, source
, scope
, err
);
170 if (what_value
.type() == Value::LIST
) {
171 ForwardValuesFromList(source
, scope
, what_value
.list_value(), err
);
176 // Not the right type of argument.
177 *err
= Err(what_value
, "Not a valid list of variables to copy.",
178 "Expecting either the string \"*\" or a list of strings.");
182 } // namespace functions