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 " If specified, arguments from the --args command line flag are used. If\n" 30 " that flag is not specified, args from previous builds in the build\n" 31 " directory will be used (this is in the file args.gn in the build\n" 32 " directory).\n" 33 "\n" 34 " Last, for targets being compiled with a non-default toolchain, the\n" 35 " 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 " If you specify an override for a build argument that never appears in\n" 42 " a \"declare_args\" call, a nonfatal error will be displayed.\n" 43 "\n" 44 "Examples\n" 45 "\n" 46 " gn args out/FooBar\n" 47 " Create the directory out/FooBar and open an editor. You would type\n" 48 " something like this into that file:\n" 49 " enable_doom_melon=false\n" 50 " os=\"android\"\n" 51 "\n" 52 " gn gen out/FooBar --args=\"enable_doom_melon=true os=\\\"android\\\"\"\n" 53 " This will overwrite the build directory with the given arguments.\n" 54 " (Note that the quotes inside the args command will usually need to\n" 55 " be escaped for your shell to pass through strings values.)\n" 56 "\n" 57 "How build arguments are used\n" 58 "\n" 59 " If you want to use an argument, you use declare_args() and specify\n" 60 " default values. These default values will apply if none of the steps\n" 61 " listed in the \"How build arguments are set\" section above apply to\n" 62 " the given argument, but the defaults will not override any of these.\n" 63 "\n" 64 " Often, the root build config file will declare global arguments that\n" 65 " will be passed to all buildfiles. Individual build files can also\n" 66 " specify arguments that apply only to those files. It is also useful\n" 67 " to specify build args in an \"import\"-ed file if you want such\n" 68 " arguments to apply to multiple buildfiles.\n"; 69 70 Args::Args() { 71 } 72 73 Args::Args(const Args& other) 74 : overrides_(other.overrides_), 75 all_overrides_(other.all_overrides_), 76 declared_arguments_(other.declared_arguments_) { 77 } 78 79 Args::~Args() { 80 } 81 82 void Args::AddArgOverride(const char* name, const Value& value) { 83 base::AutoLock lock(lock_); 84 85 overrides_[base::StringPiece(name)] = value; 86 all_overrides_[base::StringPiece(name)] = value; 87 } 88 89 void Args::AddArgOverrides(const Scope::KeyValueMap& overrides) { 90 base::AutoLock lock(lock_); 91 92 for (Scope::KeyValueMap::const_iterator i = overrides.begin(); 93 i != overrides.end(); ++i) { 94 overrides_[i->first] = i->second; 95 all_overrides_[i->first] = i->second; 96 } 97 } 98 99 const Value* Args::GetArgOverride(const char* name) const { 100 base::AutoLock lock(lock_); 101 102 Scope::KeyValueMap::const_iterator found = 103 all_overrides_.find(base::StringPiece(name)); 104 if (found == all_overrides_.end()) 105 return NULL; 106 return &found->second; 107 } 108 109 Scope::KeyValueMap Args::GetAllOverrides() const { 110 base::AutoLock lock(lock_); 111 return all_overrides_; 112 } 113 114 void Args::SetupRootScope(Scope* dest, 115 const Scope::KeyValueMap& toolchain_overrides) const { 116 base::AutoLock lock(lock_); 117 118 SetSystemVarsLocked(dest); 119 ApplyOverridesLocked(overrides_, dest); 120 ApplyOverridesLocked(toolchain_overrides, dest); 121 SaveOverrideRecordLocked(toolchain_overrides); 122 } 123 124 bool Args::DeclareArgs(const Scope::KeyValueMap& args, 125 Scope* scope_to_set, 126 Err* err) const { 127 base::AutoLock lock(lock_); 128 129 for (Scope::KeyValueMap::const_iterator i = args.begin(); 130 i != args.end(); ++i) { 131 // Verify that the value hasn't already been declared. We want each value 132 // to be declared only once. 133 // 134 // The tricky part is that a buildfile can be interpreted multiple times 135 // when used from different toolchains, so we can't just check that we've 136 // seen it before. Instead, we check that the location matches. 137 Scope::KeyValueMap::iterator previously_declared = 138 declared_arguments_.find(i->first); 139 if (previously_declared != declared_arguments_.end()) { 140 if (previously_declared->second.origin() != i->second.origin()) { 141 // Declaration location mismatch. 142 *err = Err(i->second.origin(), "Duplicate build argument declaration.", 143 "Here you're declaring an argument that was already declared " 144 "elsewhere.\nYou can only declare each argument once in the entire " 145 "build so there is one\ncanonical place for documentation and the " 146 "default value. Either move this\nargument to the build config " 147 "file (for visibility everywhere) or to a .gni file\nthat you " 148 "\"import\" from the files where you need it (preferred)."); 149 err->AppendSubErr(Err(previously_declared->second.origin(), 150 "Previous declaration.", 151 "See also \"gn help buildargs\" for more on how " 152 "build arguments work.")); 153 return false; 154 } 155 } else { 156 declared_arguments_.insert(*i); 157 } 158 159 // Only set on the current scope to the new value if it hasn't been already 160 // set. Mark the variable used so the build script can override it in 161 // certain cases without getting unused value errors. 162 if (!scope_to_set->GetValue(i->first)) { 163 scope_to_set->SetValue(i->first, i->second, i->second.origin()); 164 scope_to_set->MarkUsed(i->first); 165 } 166 } 167 168 return true; 169 } 170 171 bool Args::VerifyAllOverridesUsed(Err* err) const { 172 base::AutoLock lock(lock_); 173 return VerifyAllOverridesUsed(all_overrides_, declared_arguments_, err); 174 } 175 176 bool Args::VerifyAllOverridesUsed( 177 const Scope::KeyValueMap& overrides, 178 const Scope::KeyValueMap& declared_arguments, 179 Err* err) { 180 for (Scope::KeyValueMap::const_iterator i = overrides.begin(); 181 i != overrides.end(); ++i) { 182 if (declared_arguments.find(i->first) == declared_arguments.end()) { 183 // Get a list of all possible overrides for help with error finding. 184 // 185 // It might be nice to do edit distance checks to see if we can find one 186 // close to what you typed. 187 std::string all_declared_str; 188 for (Scope::KeyValueMap::const_iterator cur_str = 189 declared_arguments.begin(); 190 cur_str != declared_arguments.end(); ++cur_str) { 191 if (cur_str != declared_arguments.begin()) 192 all_declared_str += ", "; 193 all_declared_str += cur_str->first.as_string(); 194 } 195 196 *err = Err(i->second.origin(), "Build argument has no effect.", 197 "The variable \"" + i->first.as_string() + "\" was set as a build " 198 "argument\nbut never appeared in a declare_args() block in any " 199 "buildfile.\n\nPossible arguments: " + all_declared_str); 200 return false; 201 } 202 } 203 return true; 204 } 205 206 void Args::MergeDeclaredArguments(Scope::KeyValueMap* dest) const { 207 base::AutoLock lock(lock_); 208 209 for (Scope::KeyValueMap::const_iterator i = declared_arguments_.begin(); 210 i != declared_arguments_.end(); ++i) 211 (*dest)[i->first] = i->second; 212 } 213 214 void Args::SetSystemVarsLocked(Scope* dest) const { 215 lock_.AssertAcquired(); 216 217 // Host OS. 218 const char* os = NULL; 219 #if defined(OS_WIN) 220 os = "win"; 221 #elif defined(OS_MACOSX) 222 os = "mac"; 223 #elif defined(OS_LINUX) 224 os = "linux"; 225 #elif defined(OS_ANDROID) 226 os = "android"; 227 #else 228 #error Unknown OS type. 229 #endif 230 Value os_val(NULL, std::string(os)); 231 dest->SetValue(variables::kBuildOs, os_val, NULL); 232 dest->SetValue(variables::kOs, os_val, NULL); 233 234 // Host architecture. 235 static const char kX86[] = "x86"; 236 static const char kX64[] = "x64"; 237 const char* arch = NULL; 238 #if defined(OS_WIN) 239 // ...on Windows, set the CPU architecture based on the underlying OS, not 240 // whatever the current bit-tedness of the GN binary is. 241 const base::win::OSInfo* os_info = base::win::OSInfo::GetInstance(); 242 switch (os_info->architecture()) { 243 case base::win::OSInfo::X86_ARCHITECTURE: 244 arch = kX86; 245 break; 246 case base::win::OSInfo::X64_ARCHITECTURE: 247 arch = kX64; 248 break; 249 default: 250 CHECK(false) << "Windows architecture not handled."; 251 break; 252 } 253 #else 254 // ...on all other platforms, just use the bit-tedness of the current 255 // process. 256 #if defined(ARCH_CPU_X86_64) 257 arch = kX64; 258 #elif defined(ARCH_CPU_X86) 259 arch = kX86; 260 #elif defined(ARCH_CPU_ARMEL) 261 static const char kArm[] = "arm"; 262 arch = kArm; 263 #else 264 #error Unknown architecture. 265 #endif 266 #endif 267 // Avoid unused var warning. 268 (void)kX86; 269 (void)kX64; 270 271 Value arch_val(NULL, std::string(arch)); 272 dest->SetValue(variables::kBuildCpuArch, arch_val, NULL); 273 dest->SetValue(variables::kCpuArch, arch_val, NULL); 274 275 // Save the OS and architecture as build arguments that are implicitly 276 // declared. This is so they can be overridden in a toolchain build args 277 // override, and so that they will appear in the "gn args" output. 278 // 279 // Do not declare the build* variants since these shouldn't be changed. 280 // 281 // Mark these variables used so the build config file can override them 282 // without geting a warning about overwriting an unused variable. 283 declared_arguments_[variables::kOs] = os_val; 284 declared_arguments_[variables::kCpuArch] = arch_val; 285 dest->MarkUsed(variables::kCpuArch); 286 dest->MarkUsed(variables::kOs); 287 } 288 289 void Args::ApplyOverridesLocked(const Scope::KeyValueMap& values, 290 Scope* scope) const { 291 lock_.AssertAcquired(); 292 for (Scope::KeyValueMap::const_iterator i = values.begin(); 293 i != values.end(); ++i) 294 scope->SetValue(i->first, i->second, i->second.origin()); 295 } 296 297 void Args::SaveOverrideRecordLocked(const Scope::KeyValueMap& values) const { 298 lock_.AssertAcquired(); 299 for (Scope::KeyValueMap::const_iterator i = values.begin(); 300 i != values.end(); ++i) 301 all_overrides_[i->first] = i->second; 302 } 303