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.
4
5 #include "tools/gn/args.h"
6
7 #include "build/build_config.h"
8 #include "tools/gn/variables.h"
9
10 #if defined(OS_WIN)
11 #include "base/win/windows_version.h"
12 #endif
13
14 const char kBuildArgs_Help[] =
15 "Build Arguments Overview\n"
16 "\n"
17 " Build arguments are variables passed in from outside of the build\n"
18 " that build files can query to determine how the build works.\n"
19 "\n"
20 "How build arguments are set\n"
21 "\n"
22 " First, system default arguments are set based on the current system.\n"
23 " The built-in arguments are:\n"
24 " - cpu_arch (by default this is the same as \"default_cpu_arch\")\n"
25 " - default_cpu_arch\n"
26 " - default_os\n"
27 " - os (by default this is the same as \"default_os\")\n"
28 "\n"
29 " Second, arguments specified on the command-line via \"--args\" are\n"
30 " applied. These can override the system default ones, and add new ones.\n"
31 " These are whitespace-separated. For example:\n"
32 "\n"
33 " gn --args=\"enable_doom_melon=false\" os=\\\"beos\\\"\n"
34 "\n"
35 " Third, toolchain overrides are applied. These are specified in the\n"
36 " toolchain_args section of a toolchain definition. The use-case for\n"
37 " this is that a toolchain may be building code for a different\n"
38 " platform, and that it may want to always specify Posix, for example.\n"
39 " See \"gn help toolchain_args\" for more.\n"
40 "\n"
41 " It is an error to specify an override for a build argument that never\n"
42 " appears in a \"declare_args\" call.\n"
43 "\n"
44 "How build arguments are used\n"
45 "\n"
46 " If you want to use an argument, you use declare_args() and specify\n"
47 " default values. These default values will apply if none of the steps\n"
48 " listed in the \"How build arguments are set\" section above apply to\n"
49 " the given argument, but the defaults will not override any of these.\n"
50 "\n"
51 " Often, the root build config file will declare global arguments that\n"
52 " will be passed to all buildfiles. Individual build files can also\n"
53 " specify arguments that apply only to those files. It is also usedful\n"
54 " to specify build args in an \"import\"-ed file if you want such\n"
55 " arguments to apply to multiple buildfiles.\n";
56
Args()57 Args::Args() {
58 }
59
Args(const Args & other)60 Args::Args(const Args& other)
61 : overrides_(other.overrides_),
62 all_overrides_(other.all_overrides_),
63 declared_arguments_(other.declared_arguments_) {
64 }
65
~Args()66 Args::~Args() {
67 }
68
AddArgOverride(const char * name,const Value & value)69 void Args::AddArgOverride(const char* name, const Value& value) {
70 overrides_[base::StringPiece(name)] = value;
71 all_overrides_[base::StringPiece(name)] = value;
72 }
73
AddArgOverrides(const Scope::KeyValueMap & overrides)74 void Args::AddArgOverrides(const Scope::KeyValueMap& overrides) {
75 for (Scope::KeyValueMap::const_iterator i = overrides.begin();
76 i != overrides.end(); ++i) {
77 overrides_[i->first] = i->second;
78 all_overrides_[i->first] = i->second;
79 }
80 }
81
SetupRootScope(Scope * dest,const Scope::KeyValueMap & toolchain_overrides) const82 void Args::SetupRootScope(Scope* dest,
83 const Scope::KeyValueMap& toolchain_overrides) const {
84 SetSystemVars(dest);
85 ApplyOverrides(overrides_, dest);
86 ApplyOverrides(toolchain_overrides, dest);
87 SaveOverrideRecord(toolchain_overrides);
88 }
89
DeclareArgs(const Scope::KeyValueMap & args,Scope * scope_to_set,Err * err) const90 bool Args::DeclareArgs(const Scope::KeyValueMap& args,
91 Scope* scope_to_set,
92 Err* err) const {
93 base::AutoLock lock(lock_);
94
95 for (Scope::KeyValueMap::const_iterator i = args.begin();
96 i != args.end(); ++i) {
97 // Verify that the value hasn't already been declared. We want each value
98 // to be declared only once.
99 //
100 // The tricky part is that a buildfile can be interpreted multiple times
101 // when used from different toolchains, so we can't just check that we've
102 // seen it before. Instead, we check that the location matches. We
103 // additionally check that the value matches to prevent people from
104 // declaring defaults based on other parameters that may change. The
105 // rationale is that you should have exactly one default value for each
106 // argument that we can display in the help.
107 Scope::KeyValueMap::iterator previously_declared =
108 declared_arguments_.find(i->first);
109 if (previously_declared != declared_arguments_.end()) {
110 if (previously_declared->second.origin() != i->second.origin()) {
111 // Declaration location mismatch.
112 *err = Err(i->second.origin(), "Duplicate build arg declaration.",
113 "Here you're declaring an argument that was already declared "
114 "elsewhere.\nYou can only declare each argument once in the entire "
115 "build so there is one\ncanonical place for documentation and the "
116 "default value. Either move this\nargument to the build config "
117 "file (for visibility everywhere) or to a .gni file\nthat you "
118 "\"import\" from the files where you need it (preferred).");
119 err->AppendSubErr(Err(previously_declared->second.origin(),
120 "Previous declaration.",
121 "See also \"gn help buildargs\" for more on how "
122 "build args work."));
123 return false;
124 } else if (previously_declared->second != i->second) {
125 // Default value mismatch.
126 *err = Err(i->second.origin(),
127 "Non-constant default value for build arg.",
128 "Each build arg should have one default value so we report it "
129 "nicely in the\n\"gn args\" command. Please make this value "
130 "constant.");
131 return false;
132 }
133 } else {
134 declared_arguments_.insert(*i);
135 }
136
137 // Only set on the current scope to the new value if it hasn't been already
138 // set. Mark the variable used so the build script can override it in
139 // certain cases without getting unused value errors.
140 if (!scope_to_set->GetValue(i->first)) {
141 scope_to_set->SetValue(i->first, i->second, i->second.origin());
142 scope_to_set->MarkUsed(i->first);
143 }
144 }
145
146 return true;
147 }
148
VerifyAllOverridesUsed(Err * err) const149 bool Args::VerifyAllOverridesUsed(Err* err) const {
150 base::AutoLock lock(lock_);
151
152 for (Scope::KeyValueMap::const_iterator i = all_overrides_.begin();
153 i != all_overrides_.end(); ++i) {
154 if (declared_arguments_.find(i->first) == declared_arguments_.end()) {
155 *err = Err(i->second.origin(), "Build arg has no effect.",
156 "The value \"" + i->first.as_string() + "\" was set a build "
157 "argument\nbut never appeared in a declare_args() block in any "
158 "buildfile.");
159 return false;
160 }
161 }
162 return true;
163 }
164
SetSystemVars(Scope * dest) const165 void Args::SetSystemVars(Scope* dest) const {
166 // Host OS.
167 const char* os = NULL;
168 #if defined(OS_WIN)
169 os = "win";
170 #elif defined(OS_MACOSX)
171 os = "mac";
172 #elif defined(OS_LINUX)
173 os = "linux";
174 #else
175 #error Unknown OS type.
176 #endif
177 Value os_val(NULL, std::string(os));
178 dest->SetValue(variables::kBuildOs, os_val, NULL);
179 dest->SetValue(variables::kOs, os_val, NULL);
180
181 // Host architecture.
182 static const char kX86[] = "x86";
183 static const char kX64[] = "x64";
184 const char* arch = NULL;
185 #if defined(OS_WIN)
186 // ...on Windows, set the CPU architecture based on the underlying OS, not
187 // whatever the current bit-tedness of the GN binary is.
188 const base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
189 switch (os_info->architecture()) {
190 case base::win::OSInfo::X86_ARCHITECTURE:
191 arch = kX86;
192 break;
193 case base::win::OSInfo::X64_ARCHITECTURE:
194 arch = kX64;
195 break;
196 default:
197 CHECK(false) << "Windows architecture not handled.";
198 break;
199 }
200 #else
201 // ...on all other platforms, just use the bit-tedness of the current
202 // process.
203 #if defined(ARCH_CPU_X86_64)
204 arch = kX64;
205 #elif defined(ARCH_CPU_X86)
206 arch = kX86;
207 #elif defined(ARCH_CPU_ARMEL)
208 static const char kArm[] = "arm";
209 arch = kArm;
210 #else
211 #error Unknown architecture.
212 #endif
213 #endif
214 // Avoid unused var warning.
215 (void)kX86;
216 (void)kX64;
217
218 Value arch_val(NULL, std::string(arch));
219 dest->SetValue(variables::kBuildCpuArch, arch_val, NULL);
220 dest->SetValue(variables::kCpuArch, arch_val, NULL);
221
222 // Save the OS and architecture as build arguments that are implicitly
223 // declared. This is so they can be overridden in a toolchain build args
224 // override, and so that they will appear in the "gn args" output.
225 //
226 // Do not declare the build* variants since these shouldn't be changed.
227 //
228 // Mark these variables used so the build config file can override them
229 // without geting a warning about overwriting an unused variable.
230 declared_arguments_[variables::kOs] = os_val;
231 declared_arguments_[variables::kCpuArch] = arch_val;
232 dest->MarkUsed(variables::kCpuArch);
233 dest->MarkUsed(variables::kOs);
234 }
235
236
ApplyOverrides(const Scope::KeyValueMap & values,Scope * scope) const237 void Args::ApplyOverrides(const Scope::KeyValueMap& values,
238 Scope* scope) const {
239 for (Scope::KeyValueMap::const_iterator i = values.begin();
240 i != values.end(); ++i)
241 scope->SetValue(i->first, i->second, i->second.origin());
242 }
243
SaveOverrideRecord(const Scope::KeyValueMap & values) const244 void Args::SaveOverrideRecord(const Scope::KeyValueMap& values) const {
245 base::AutoLock lock(lock_);
246 for (Scope::KeyValueMap::const_iterator i = values.begin();
247 i != values.end(); ++i)
248 all_overrides_[i->first] = i->second;
249 }
250