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"
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"
17 "How build arguments are set\n"
19 " First, system default arguments are set based on the current system.\n"
20 " The built-in arguments are:\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"
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"
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"
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"
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"
56 "How build arguments are used\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"
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";
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())
79 overrides
->erase(override
++);
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_
) {
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())
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
,
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."));
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
);
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())
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();
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: " +
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();
231 const char* os
= nullptr;
234 #elif defined(OS_MACOSX)
236 #elif defined(OS_LINUX)
238 #elif defined(OS_ANDROID)
241 #error Unknown OS type.
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")
255 else if (os_arch
== "x86_64")
257 else if (os_arch
.substr(3) == "arm")
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()];