[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 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 | |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 7 | #include "build/build_config.h" |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 8 | #include "tools/gn/variables.h" |
| 9 | |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 10 | #if defined(OS_WIN) |
| 11 | #include "base/win/windows_version.h" |
| 12 | #endif |
| 13 | |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 14 | const char kBuildArgs_Help[] = |
[email protected] | ea3690c | 2013-09-23 17:59:22 | [diff] [blame] | 15 | "Build Arguments Overview\n" |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 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" |
[email protected] | ea3690c | 2013-09-23 17:59:22 | [diff] [blame] | 20 | "How build arguments are set\n" |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 21 | "\n" |
| 22 | " First, system default arguments are set based on the current system.\n" |
| 23 | " The built-in arguments are:\n" |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 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" |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 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" |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 33 | " gn --args=\"enable_doom_melon=false\" os=\\\"beos\\\"\n" |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 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" |
[email protected] | ea3690c | 2013-09-23 17:59:22 | [diff] [blame] | 44 | "How build arguments are used\n" |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 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 | |
| 57 | Args::Args() { |
| 58 | } |
| 59 | |
[email protected] | e3730f81 | 2013-10-16 16:46:14 | [diff] [blame] | 60 | Args::Args(const Args& other) |
| 61 | : overrides_(other.overrides_), |
| 62 | all_overrides_(other.all_overrides_), |
| 63 | declared_arguments_(other.declared_arguments_) { |
| 64 | } |
| 65 | |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 66 | Args::~Args() { |
| 67 | } |
| 68 | |
[email protected] | e3730f81 | 2013-10-16 16:46:14 | [diff] [blame] | 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 | |
[email protected] | 0a79fe4 | 2013-08-29 21:06:26 | [diff] [blame] | 74 | void Args::AddArgOverrides(const Scope::KeyValueMap& overrides) { |
| 75 | for (Scope::KeyValueMap::const_iterator i = overrides.begin(); |
| 76 | i != overrides.end(); ++i) { |
[email protected] | e3730f81 | 2013-10-16 16:46:14 | [diff] [blame] | 77 | overrides_[i->first] = i->second; |
| 78 | all_overrides_[i->first] = i->second; |
[email protected] | 0a79fe4 | 2013-08-29 21:06:26 | [diff] [blame] | 79 | } |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 80 | } |
| 81 | |
| 82 | 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 | |
| 90 | 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 |
[email protected] | 42b80ef | 2013-10-29 23:43:57 | [diff] [blame] | 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)) { |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 141 | scope_to_set->SetValue(i->first, i->second, i->second.origin()); |
[email protected] | 42b80ef | 2013-10-29 23:43:57 | [diff] [blame] | 142 | scope_to_set->MarkUsed(i->first); |
| 143 | } |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 144 | } |
| 145 | |
| 146 | return true; |
| 147 | } |
| 148 | |
| 149 | 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 | |
| 165 | void Args::SetSystemVars(Scope* dest) const { |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 166 | // Host OS. |
| 167 | const char* os = NULL; |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 168 | #if defined(OS_WIN) |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 169 | os = "win"; |
| 170 | #elif defined(OS_MACOSX) |
| 171 | os = "mac"; |
| 172 | #elif defined(OS_LINUX) |
| 173 | os = "linux"; |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 174 | #else |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 175 | #error Unknown OS type. |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 176 | #endif |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 177 | Value os_val(NULL, std::string(os)); |
| 178 | dest->SetValue(variables::kBuildOs, os_val, NULL); |
| 179 | dest->SetValue(variables::kOs, os_val, NULL); |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 180 | |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 181 | // Host architecture. |
[email protected] | 777ad7f | 2013-11-22 22:38:39 | [diff] [blame^] | 182 | static const char kX86[] = "x86"; |
| 183 | static const char kX64[] = "x64"; |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 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: |
[email protected] | 777ad7f | 2013-11-22 22:38:39 | [diff] [blame^] | 191 | arch = kX86; |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 192 | break; |
| 193 | case base::win::OSInfo::X64_ARCHITECTURE: |
[email protected] | 777ad7f | 2013-11-22 22:38:39 | [diff] [blame^] | 194 | arch = kX64; |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 195 | break; |
| 196 | default: |
| 197 | CHECK(false) << "Windows architecture not handled."; |
| 198 | break; |
| 199 | } |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 200 | #else |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 201 | // ...on all other platforms, just use the bit-tedness of the current |
| 202 | // process. |
| 203 | #if defined(ARCH_CPU_X86_64) |
[email protected] | 777ad7f | 2013-11-22 22:38:39 | [diff] [blame^] | 204 | arch = kX64; |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 205 | #elif defined(ARCH_CPU_X86) |
[email protected] | 777ad7f | 2013-11-22 22:38:39 | [diff] [blame^] | 206 | arch = kX86; |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 207 | #elif defined(ARCH_CPU_ARMEL) |
| 208 | static const char kArm[] = "arm"; |
| 209 | arch = kArm; |
| 210 | #else |
| 211 | #error Unknown architecture. |
| 212 | #endif |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 213 | #endif |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 214 | // Avoid unused var warning. |
[email protected] | 777ad7f | 2013-11-22 22:38:39 | [diff] [blame^] | 215 | (void)kX86; |
| 216 | (void)kX64; |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 217 | |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 218 | Value arch_val(NULL, std::string(arch)); |
| 219 | dest->SetValue(variables::kBuildCpuArch, arch_val, NULL); |
| 220 | dest->SetValue(variables::kCpuArch, arch_val, NULL); |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 221 | |
[email protected] | dbd915b4 | 2013-10-25 22:23:17 | [diff] [blame] | 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 | // |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 228 | // Mark these variables used so the build config file can override them |
| 229 | // without geting a warning about overwriting an unused variable. |
[email protected] | dbd915b4 | 2013-10-25 22:23:17 | [diff] [blame] | 230 | declared_arguments_[variables::kOs] = os_val; |
| 231 | declared_arguments_[variables::kCpuArch] = arch_val; |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 232 | dest->MarkUsed(variables::kCpuArch); |
| 233 | dest->MarkUsed(variables::kOs); |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 234 | } |
| 235 | |
[email protected] | 145e5a1 | 2013-10-18 21:57:13 | [diff] [blame] | 236 | |
[email protected] | 60749e1c | 2013-08-19 21:11:05 | [diff] [blame] | 237 | 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 | |
| 244 | 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 | } |