[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / tools / gn / args.cc
blob60ee7b2ce33d385f58957c9f01858536a3c4d147
1 // Copyright (c) 2013 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/args.h"
7 #include "base/sys_info.h"
8 #include "build/build_config.h"
9 #include "tools/gn/variables.h"
11 const char kBuildArgs_Help[] =
12 "Build Arguments Overview\n"
13 "\n"
14 " Build arguments are variables passed in from outside of the build\n"
15 " that build files can query to determine how the build works.\n"
16 "\n"
17 "How build arguments are set\n"
18 "\n"
19 " First, system default arguments are set based on the current system.\n"
20 " The built-in arguments are:\n"
21 " - host_cpu\n"
22 " - host_os\n"
23 " - current_cpu\n"
24 " - current_os\n"
25 " - target_cpu\n"
26 " - target_os\n"
27 "\n"
28 " If specified, arguments from the --args command line flag are used. If\n"
29 " that flag is not specified, args from previous builds in the build\n"
30 " directory will be used (this is in the file args.gn in the build\n"
31 " directory).\n"
32 "\n"
33 " Last, for targets being compiled with a non-default toolchain, the\n"
34 " toolchain overrides are applied. These are specified in the\n"
35 " toolchain_args section of a toolchain definition. The use-case for\n"
36 " this is that a toolchain may be building code for a different\n"
37 " platform, and that it may want to always specify Posix, for example.\n"
38 " See \"gn help toolchain_args\" for more.\n"
39 "\n"
40 " If you specify an override for a build argument that never appears in\n"
41 " a \"declare_args\" call, a nonfatal error will be displayed.\n"
42 "\n"
43 "Examples\n"
44 "\n"
45 " gn args out/FooBar\n"
46 " Create the directory out/FooBar and open an editor. You would type\n"
47 " something like this into that file:\n"
48 " enable_doom_melon=false\n"
49 " os=\"android\"\n"
50 "\n"
51 " gn gen out/FooBar --args=\"enable_doom_melon=true os=\\\"android\\\"\"\n"
52 " This will overwrite the build directory with the given arguments.\n"
53 " (Note that the quotes inside the args command will usually need to\n"
54 " be escaped for your shell to pass through strings values.)\n"
55 "\n"
56 "How build arguments are used\n"
57 "\n"
58 " If you want to use an argument, you use declare_args() and specify\n"
59 " default values. These default values will apply if none of the steps\n"
60 " listed in the \"How build arguments are set\" section above apply to\n"
61 " the given argument, but the defaults will not override any of these.\n"
62 "\n"
63 " Often, the root build config file will declare global arguments that\n"
64 " will be passed to all buildfiles. Individual build files can also\n"
65 " specify arguments that apply only to those files. It is also useful\n"
66 " to specify build args in an \"import\"-ed file if you want such\n"
67 " arguments to apply to multiple buildfiles.\n";
69 namespace {
71 // Removes all entries in |overrides| that are in |declared_overrides|.
72 void RemoveDeclaredOverrides(const Scope::KeyValueMap& declared_arguments,
73 Scope::KeyValueMap* overrides) {
74 for (Scope::KeyValueMap::iterator override = overrides->begin();
75 override != overrides->end();) {
76 if (declared_arguments.find(override->first) == declared_arguments.end())
77 ++override;
78 else
79 overrides->erase(override++);
83 } // namespace
85 Args::Args() {
88 Args::Args(const Args& other)
89 : overrides_(other.overrides_),
90 all_overrides_(other.all_overrides_),
91 declared_arguments_per_toolchain_(
92 other.declared_arguments_per_toolchain_) {
95 Args::~Args() {
98 void Args::AddArgOverride(const char* name, const Value& value) {
99 base::AutoLock lock(lock_);
101 overrides_[base::StringPiece(name)] = value;
102 all_overrides_[base::StringPiece(name)] = value;
105 void Args::AddArgOverrides(const Scope::KeyValueMap& overrides) {
106 base::AutoLock lock(lock_);
108 for (const auto& cur_override : overrides) {
109 overrides_[cur_override.first] = cur_override.second;
110 all_overrides_[cur_override.first] = cur_override.second;
114 const Value* Args::GetArgOverride(const char* name) const {
115 base::AutoLock lock(lock_);
117 Scope::KeyValueMap::const_iterator found =
118 all_overrides_.find(base::StringPiece(name));
119 if (found == all_overrides_.end())
120 return nullptr;
121 return &found->second;
124 Scope::KeyValueMap Args::GetAllOverrides() const {
125 base::AutoLock lock(lock_);
126 return all_overrides_;
129 void Args::SetupRootScope(Scope* dest,
130 const Scope::KeyValueMap& toolchain_overrides) const {
131 base::AutoLock lock(lock_);
133 SetSystemVarsLocked(dest);
134 ApplyOverridesLocked(overrides_, dest);
135 ApplyOverridesLocked(toolchain_overrides, dest);
136 SaveOverrideRecordLocked(toolchain_overrides);
139 bool Args::DeclareArgs(const Scope::KeyValueMap& args,
140 Scope* scope_to_set,
141 Err* err) const {
142 base::AutoLock lock(lock_);
144 Scope::KeyValueMap& declared_arguments(
145 DeclaredArgumentsForToolchainLocked(scope_to_set));
146 for (const auto& arg : args) {
147 // Verify that the value hasn't already been declared. We want each value
148 // to be declared only once.
150 // The tricky part is that a buildfile can be interpreted multiple times
151 // when used from different toolchains, so we can't just check that we've
152 // seen it before. Instead, we check that the location matches.
153 Scope::KeyValueMap::iterator previously_declared =
154 declared_arguments.find(arg.first);
155 if (previously_declared != declared_arguments.end()) {
156 if (previously_declared->second.origin() != arg.second.origin()) {
157 // Declaration location mismatch.
158 *err = Err(arg.second.origin(),
159 "Duplicate build argument declaration.",
160 "Here you're declaring an argument that was already declared "
161 "elsewhere.\nYou can only declare each argument once in the entire "
162 "build so there is one\ncanonical place for documentation and the "
163 "default value. Either move this\nargument to the build config "
164 "file (for visibility everywhere) or to a .gni file\nthat you "
165 "\"import\" from the files where you need it (preferred).");
166 err->AppendSubErr(Err(previously_declared->second.origin(),
167 "Previous declaration.",
168 "See also \"gn help buildargs\" for more on how "
169 "build arguments work."));
170 return false;
172 } else {
173 declared_arguments.insert(arg);
176 // Only set on the current scope to the new value if it hasn't been already
177 // set. Mark the variable used so the build script can override it in
178 // certain cases without getting unused value errors.
179 if (!scope_to_set->GetValue(arg.first)) {
180 scope_to_set->SetValue(arg.first, arg.second, arg.second.origin());
181 scope_to_set->MarkUsed(arg.first);
185 return true;
188 bool Args::VerifyAllOverridesUsed(Err* err) const {
189 base::AutoLock lock(lock_);
190 Scope::KeyValueMap all_overrides(all_overrides_);
191 for (const auto& map_pair : declared_arguments_per_toolchain_)
192 RemoveDeclaredOverrides(map_pair.second, &all_overrides);
194 if (all_overrides.empty())
195 return true;
197 // Get a list of all possible overrides for help with error finding.
199 // It might be nice to do edit distance checks to see if we can find one close
200 // to what you typed.
201 std::string all_declared_str;
202 for (const auto& map_pair : declared_arguments_per_toolchain_) {
203 for (const auto& cur_str : map_pair.second) {
204 if (!all_declared_str.empty())
205 all_declared_str += ", ";
206 all_declared_str += cur_str.first.as_string();
210 *err = Err(
211 all_overrides.begin()->second.origin(), "Build argument has no effect.",
212 "The variable \"" + all_overrides.begin()->first.as_string() +
213 "\" was set as a build argument\nbut never appeared in a " +
214 "declare_args() block in any buildfile.\n\nPossible arguments: " +
215 all_declared_str);
216 return false;
219 void Args::MergeDeclaredArguments(Scope::KeyValueMap* dest) const {
220 base::AutoLock lock(lock_);
221 for (const auto& map_pair : declared_arguments_per_toolchain_) {
222 for (const auto& arg : map_pair.second)
223 (*dest)[arg.first] = arg.second;
227 void Args::SetSystemVarsLocked(Scope* dest) const {
228 lock_.AssertAcquired();
230 // Host OS.
231 const char* os = nullptr;
232 #if defined(OS_WIN)
233 os = "win";
234 #elif defined(OS_MACOSX)
235 os = "mac";
236 #elif defined(OS_LINUX)
237 os = "linux";
238 #elif defined(OS_ANDROID)
239 os = "android";
240 #else
241 #error Unknown OS type.
242 #endif
244 // Host architecture.
245 static const char kX86[] = "x86";
246 static const char kX64[] = "x64";
247 static const char kArm[] = "arm";
248 const char* arch = nullptr;
250 // Set the host CPU architecture based on the underlying OS, not
251 // whatever the current bit-tedness of the GN binary is.
252 std::string os_arch = base::SysInfo::OperatingSystemArchitecture();
253 if (os_arch == "x86")
254 arch = kX86;
255 else if (os_arch == "x86_64")
256 arch = kX64;
257 else if (os_arch.substr(3) == "arm")
258 arch = kArm;
259 else
260 CHECK(false) << "OS architecture not handled.";
262 // Save the OS and architecture as build arguments that are implicitly
263 // declared. This is so they can be overridden in a toolchain build args
264 // override, and so that they will appear in the "gn args" output.
265 Value empty_string(nullptr, std::string());
267 Value os_val(nullptr, std::string(os));
268 dest->SetValue(variables::kHostOs, os_val, nullptr);
269 dest->SetValue(variables::kTargetOs, empty_string, nullptr);
270 dest->SetValue(variables::kCurrentOs, empty_string, nullptr);
272 Value arch_val(nullptr, std::string(arch));
273 dest->SetValue(variables::kHostCpu, arch_val, nullptr);
274 dest->SetValue(variables::kTargetCpu, empty_string, nullptr);
275 dest->SetValue(variables::kCurrentCpu, empty_string, nullptr);
277 Scope::KeyValueMap& declared_arguments(
278 DeclaredArgumentsForToolchainLocked(dest));
279 declared_arguments[variables::kHostOs] = os_val;
280 declared_arguments[variables::kCurrentOs] = empty_string;
281 declared_arguments[variables::kTargetOs] = empty_string;
282 declared_arguments[variables::kHostCpu] = arch_val;
283 declared_arguments[variables::kCurrentCpu] = empty_string;
284 declared_arguments[variables::kTargetCpu] = empty_string;
286 // Mark these variables used so the build config file can override them
287 // without geting a warning about overwriting an unused variable.
288 dest->MarkUsed(variables::kHostCpu);
289 dest->MarkUsed(variables::kCurrentCpu);
290 dest->MarkUsed(variables::kTargetCpu);
291 dest->MarkUsed(variables::kHostOs);
292 dest->MarkUsed(variables::kCurrentOs);
293 dest->MarkUsed(variables::kTargetOs);
296 void Args::ApplyOverridesLocked(const Scope::KeyValueMap& values,
297 Scope* scope) const {
298 lock_.AssertAcquired();
299 for (const auto& val : values)
300 scope->SetValue(val.first, val.second, val.second.origin());
303 void Args::SaveOverrideRecordLocked(const Scope::KeyValueMap& values) const {
304 lock_.AssertAcquired();
305 for (const auto& val : values)
306 all_overrides_[val.first] = val.second;
309 Scope::KeyValueMap& Args::DeclaredArgumentsForToolchainLocked(
310 Scope* scope) const {
311 lock_.AssertAcquired();
312 return declared_arguments_per_toolchain_[scope->settings()];