| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "tools/gn/args.h" |
| |
| #include "build/build_config.h" |
| #include "tools/gn/variables.h" |
| |
| #if defined(OS_WIN) |
| #include "base/win/windows_version.h" |
| #endif |
| |
| const char kBuildArgs_Help[] = |
| "Build Arguments Overview\n" |
| "\n" |
| " Build arguments are variables passed in from outside of the build\n" |
| " that build files can query to determine how the build works.\n" |
| "\n" |
| "How build arguments are set\n" |
| "\n" |
| " First, system default arguments are set based on the current system.\n" |
| " The built-in arguments are:\n" |
| " - cpu_arch (by default this is the same as \"default_cpu_arch\")\n" |
| " - default_cpu_arch\n" |
| " - default_os\n" |
| " - os (by default this is the same as \"default_os\")\n" |
| "\n" |
| " Second, arguments specified on the command-line via \"--args\" are\n" |
| " applied. These can override the system default ones, and add new ones.\n" |
| " These are whitespace-separated. For example:\n" |
| "\n" |
| " gn --args=\"enable_doom_melon=false\" os=\\\"beos\\\"\n" |
| "\n" |
| " Third, toolchain overrides are applied. These are specified in the\n" |
| " toolchain_args section of a toolchain definition. The use-case for\n" |
| " this is that a toolchain may be building code for a different\n" |
| " platform, and that it may want to always specify Posix, for example.\n" |
| " See \"gn help toolchain_args\" for more.\n" |
| "\n" |
| " It is an error to specify an override for a build argument that never\n" |
| " appears in a \"declare_args\" call.\n" |
| "\n" |
| "How build arguments are used\n" |
| "\n" |
| " If you want to use an argument, you use declare_args() and specify\n" |
| " default values. These default values will apply if none of the steps\n" |
| " listed in the \"How build arguments are set\" section above apply to\n" |
| " the given argument, but the defaults will not override any of these.\n" |
| "\n" |
| " Often, the root build config file will declare global arguments that\n" |
| " will be passed to all buildfiles. Individual build files can also\n" |
| " specify arguments that apply only to those files. It is also usedful\n" |
| " to specify build args in an \"import\"-ed file if you want such\n" |
| " arguments to apply to multiple buildfiles.\n"; |
| |
| Args::Args() { |
| // These system values are always overridden and won't appear in a |
| // declare_args call, so mark them as used to prevent a warning later. |
| declared_arguments_[variables::kOs] = Value(); |
| declared_arguments_[variables::kCpuArch] = Value(); |
| } |
| |
| Args::Args(const Args& other) |
| : overrides_(other.overrides_), |
| all_overrides_(other.all_overrides_), |
| declared_arguments_(other.declared_arguments_) { |
| } |
| |
| Args::~Args() { |
| } |
| |
| void Args::AddArgOverride(const char* name, const Value& value) { |
| overrides_[base::StringPiece(name)] = value; |
| all_overrides_[base::StringPiece(name)] = value; |
| } |
| |
| void Args::AddArgOverrides(const Scope::KeyValueMap& overrides) { |
| for (Scope::KeyValueMap::const_iterator i = overrides.begin(); |
| i != overrides.end(); ++i) { |
| overrides_[i->first] = i->second; |
| all_overrides_[i->first] = i->second; |
| } |
| } |
| |
| void Args::SetupRootScope(Scope* dest, |
| const Scope::KeyValueMap& toolchain_overrides) const { |
| SetSystemVars(dest); |
| ApplyOverrides(overrides_, dest); |
| ApplyOverrides(toolchain_overrides, dest); |
| SaveOverrideRecord(toolchain_overrides); |
| } |
| |
| bool Args::DeclareArgs(const Scope::KeyValueMap& args, |
| Scope* scope_to_set, |
| Err* err) const { |
| base::AutoLock lock(lock_); |
| |
| for (Scope::KeyValueMap::const_iterator i = args.begin(); |
| i != args.end(); ++i) { |
| // Verify that the value hasn't already been declared. We want each value |
| // to be declared only once. |
| // |
| // The tricky part is that a buildfile can be interpreted multiple times |
| // when used from different toolchains, so we can't just check that we've |
| // seen it before. Instead, we check that the location matches. We |
| // additionally check that the value matches to prevent people from |
| // declaring defaults based on other parameters that may change. The |
| // rationale is that you should have exactly one default value for each |
| // argument that we can display in the help. |
| Scope::KeyValueMap::iterator previously_declared = |
| declared_arguments_.find(i->first); |
| if (previously_declared != declared_arguments_.end()) { |
| if (previously_declared->second.origin() != i->second.origin()) { |
| // Declaration location mismatch. |
| *err = Err(i->second.origin(), "Duplicate build arg declaration.", |
| "Here you're declaring an argument that was already declared " |
| "elsewhere.\nYou can only declare each argument once in the entire " |
| "build so there is one\ncanonical place for documentation and the " |
| "default value. Either move this\nargument to the build config " |
| "file (for visibility everywhere) or to a .gni file\nthat you " |
| "\"import\" from the files where you need it (preferred)."); |
| err->AppendSubErr(Err(previously_declared->second.origin(), |
| "Previous declaration.", |
| "See also \"gn help buildargs\" for more on how " |
| "build args work.")); |
| return false; |
| } else if (previously_declared->second != i->second) { |
| // Default value mismatch. |
| *err = Err(i->second.origin(), |
| "Non-constant default value for build arg.", |
| "Each build arg should have one default value so we report it " |
| "nicely in the\n\"gn args\" command. Please make this value " |
| "constant."); |
| return false; |
| } |
| } else { |
| declared_arguments_.insert(*i); |
| } |
| |
| // Only set on the current scope to the new value if it hasn't been already |
| // set. |
| if (!scope_to_set->GetValue(i->first)) |
| scope_to_set->SetValue(i->first, i->second, i->second.origin()); |
| } |
| |
| return true; |
| } |
| |
| bool Args::VerifyAllOverridesUsed(Err* err) const { |
| base::AutoLock lock(lock_); |
| |
| for (Scope::KeyValueMap::const_iterator i = all_overrides_.begin(); |
| i != all_overrides_.end(); ++i) { |
| if (declared_arguments_.find(i->first) == declared_arguments_.end()) { |
| *err = Err(i->second.origin(), "Build arg has no effect.", |
| "The value \"" + i->first.as_string() + "\" was set a build " |
| "argument\nbut never appeared in a declare_args() block in any " |
| "buildfile."); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| void Args::SetSystemVars(Scope* dest) const { |
| // Host OS. |
| const char* os = NULL; |
| #if defined(OS_WIN) |
| os = "win"; |
| #elif defined(OS_MACOSX) |
| os = "mac"; |
| #elif defined(OS_LINUX) |
| os = "linux"; |
| #else |
| #error Unknown OS type. |
| #endif |
| Value os_val(NULL, std::string(os)); |
| dest->SetValue(variables::kBuildOs, os_val, NULL); |
| dest->SetValue(variables::kOs, os_val, NULL); |
| declared_arguments_[variables::kBuildOs] = os_val; |
| declared_arguments_[variables::kOs] = os_val; |
| |
| // Host architecture. |
| static const char kIa32[] = "ia32"; |
| static const char kIa64[] = "ia64"; |
| const char* arch = NULL; |
| #if defined(OS_WIN) |
| // ...on Windows, set the CPU architecture based on the underlying OS, not |
| // whatever the current bit-tedness of the GN binary is. |
| const base::win::OSInfo* os_info = base::win::OSInfo::GetInstance(); |
| switch (os_info->architecture()) { |
| case base::win::OSInfo::X86_ARCHITECTURE: |
| arch = kIa32; |
| break; |
| case base::win::OSInfo::X64_ARCHITECTURE: |
| arch = kIa64; |
| break; |
| default: |
| CHECK(false) << "Windows architecture not handled."; |
| break; |
| } |
| #else |
| // ...on all other platforms, just use the bit-tedness of the current |
| // process. |
| #if defined(ARCH_CPU_X86_64) |
| arch = kIa64; |
| #elif defined(ARCH_CPU_X86) |
| arch = kIa32; |
| #elif defined(ARCH_CPU_ARMEL) |
| static const char kArm[] = "arm"; |
| arch = kArm; |
| #else |
| #error Unknown architecture. |
| #endif |
| #endif |
| // Avoid unused var warning. |
| (void)kIa32; |
| (void)kIa64; |
| |
| Value arch_val(NULL, std::string(arch)); |
| dest->SetValue(variables::kBuildCpuArch, arch_val, NULL); |
| dest->SetValue(variables::kCpuArch, arch_val, NULL); |
| declared_arguments_[variables::kBuildOs] = arch_val; |
| declared_arguments_[variables::kOs] = arch_val; |
| |
| // Mark these variables used so the build config file can override them |
| // without geting a warning about overwriting an unused variable. |
| dest->MarkUsed(variables::kCpuArch); |
| dest->MarkUsed(variables::kOs); |
| } |
| |
| |
| void Args::ApplyOverrides(const Scope::KeyValueMap& values, |
| Scope* scope) const { |
| for (Scope::KeyValueMap::const_iterator i = values.begin(); |
| i != values.end(); ++i) |
| scope->SetValue(i->first, i->second, i->second.origin()); |
| } |
| |
| void Args::SaveOverrideRecord(const Scope::KeyValueMap& values) const { |
| base::AutoLock lock(lock_); |
| for (Scope::KeyValueMap::const_iterator i = values.begin(); |
| i != values.end(); ++i) |
| all_overrides_[i->first] = i->second; |
| } |