Home | History | Annotate | Download | only in gn
      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