blob: d60f1e7169d84affe9acbf78e6c4eb1520eb37f6 [file] [log] [blame]
[email protected]60749e1c2013-08-19 21:11:051// 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 "tools/gn/variables.h"
8
9const char kBuildArgs_Help[] =
10 "Build Arguments Overview.\n"
11 "\n"
12 " Build arguments are variables passed in from outside of the build\n"
13 " that build files can query to determine how the build works.\n"
14 "\n"
15 "How build arguments are set:\n"
16 "\n"
17 " First, system default arguments are set based on the current system.\n"
18 " The built-in arguments are:\n"
19 " - is_linux\n"
20 " - is_mac\n"
21 " - is_posix (set for Linux and Mac)\n"
22 " - is_win\n"
23 "\n"
24 " Second, arguments specified on the command-line via \"--args\" are\n"
25 " applied. These can override the system default ones, and add new ones.\n"
26 " These are whitespace-separated. For example:\n"
27 "\n"
28 " gn --args=\"teleportation_level=3 is_win=1 is_evil=0\"\n"
29 "\n"
30 " Third, toolchain overrides are applied. These are specified in the\n"
31 " toolchain_args section of a toolchain definition. The use-case for\n"
32 " this is that a toolchain may be building code for a different\n"
33 " platform, and that it may want to always specify Posix, for example.\n"
34 " See \"gn help toolchain_args\" for more.\n"
35 "\n"
36 " It is an error to specify an override for a build argument that never\n"
37 " appears in a \"declare_args\" call.\n"
38 "\n"
39 "How build arguments are used:\n"
40 "\n"
41 " If you want to use an argument, you use declare_args() and specify\n"
42 " default values. These default values will apply if none of the steps\n"
43 " listed in the \"How build arguments are set\" section above apply to\n"
44 " the given argument, but the defaults will not override any of these.\n"
45 "\n"
46 " Often, the root build config file will declare global arguments that\n"
47 " will be passed to all buildfiles. Individual build files can also\n"
48 " specify arguments that apply only to those files. It is also usedful\n"
49 " to specify build args in an \"import\"-ed file if you want such\n"
50 " arguments to apply to multiple buildfiles.\n";
51
52Args::Args() {
53}
54
55Args::~Args() {
56}
57
58void Args::SwapInArgOverrides(Scope::KeyValueMap* overrides) {
59 DCHECK(overrides_.empty());
60 overrides_.swap(*overrides);
61 for (Scope::KeyValueMap::const_iterator i = overrides_.begin();
62 i != overrides_.end(); ++i)
63 all_overrides_.insert(*i);
64}
65
66void Args::SetupRootScope(Scope* dest,
67 const Scope::KeyValueMap& toolchain_overrides) const {
68 SetSystemVars(dest);
69 ApplyOverrides(overrides_, dest);
70 ApplyOverrides(toolchain_overrides, dest);
71 SaveOverrideRecord(toolchain_overrides);
72}
73
74bool Args::DeclareArgs(const Scope::KeyValueMap& args,
75 Scope* scope_to_set,
76 Err* err) const {
77 base::AutoLock lock(lock_);
78
79 for (Scope::KeyValueMap::const_iterator i = args.begin();
80 i != args.end(); ++i) {
81 // Verify that the value hasn't already been declared. We want each value
82 // to be declared only once.
83 //
84 // The tricky part is that a buildfile can be interpreted multiple times
85 // when used from different toolchains, so we can't just check that we've
86 // seen it before. Instead, we check that the location matches. We
87 // additionally check that the value matches to prevent people from
88 // declaring defaults based on other parameters that may change. The
89 // rationale is that you should have exactly one default value for each
90 // argument that we can display in the help.
91 Scope::KeyValueMap::iterator previously_declared =
92 declared_arguments_.find(i->first);
93 if (previously_declared != declared_arguments_.end()) {
94 if (previously_declared->second.origin() != i->second.origin()) {
95 // Declaration location mismatch.
96 *err = Err(i->second.origin(), "Duplicate build arg declaration.",
97 "Here you're declaring an argument that was already declared "
98 "elsewhere.\nYou can only declare each argument once in the entire "
99 "build so there is one\ncanonical place for documentation and the "
100 "default value. Either move this\nargument to the build config "
101 "file (for visibility everywhere) or to a .gni file\nthat you "
102 "\"import\" from the files where you need it (preferred).");
103 err->AppendSubErr(Err(previously_declared->second.origin(),
104 "Previous declaration.",
105 "See also \"gn help buildargs\" for more on how "
106 "build args work."));
107 return false;
108 } else if (previously_declared->second != i->second) {
109 // Default value mismatch.
110 *err = Err(i->second.origin(),
111 "Non-constant default value for build arg.",
112 "Each build arg should have one default value so we report it "
113 "nicely in the\n\"gn args\" command. Please make this value "
114 "constant.");
115 return false;
116 }
117 } else {
118 declared_arguments_.insert(*i);
119 }
120
121 // Only set on the current scope to the new value if it hasn't been already
122 // set.
123 if (!scope_to_set->GetValue(i->first))
124 scope_to_set->SetValue(i->first, i->second, i->second.origin());
125 }
126
127 return true;
128}
129
130bool Args::VerifyAllOverridesUsed(Err* err) const {
131 base::AutoLock lock(lock_);
132
133 for (Scope::KeyValueMap::const_iterator i = all_overrides_.begin();
134 i != all_overrides_.end(); ++i) {
135 if (declared_arguments_.find(i->first) == declared_arguments_.end()) {
136 *err = Err(i->second.origin(), "Build arg has no effect.",
137 "The value \"" + i->first.as_string() + "\" was set a build "
138 "argument\nbut never appeared in a declare_args() block in any "
139 "buildfile.");
140 return false;
141 }
142 }
143 return true;
144}
145
146void Args::SetSystemVars(Scope* dest) const {
147#if defined(OS_WIN)
148 Value is_win(NULL, 1);
149 Value is_posix(NULL, 0);
150#else
151 Value is_win(NULL, 0);
152 Value is_posix(NULL, 1);
153#endif
154 dest->SetValue(variables::kIsWin, is_win, NULL);
155 dest->SetValue(variables::kIsPosix, is_posix, NULL);
156 declared_arguments_[variables::kIsWin] = is_win;
157 declared_arguments_[variables::kIsPosix] = is_posix;
158
159#if defined(OS_MACOSX)
160 Value is_mac(NULL, 1);
161#else
162 Value is_mac(NULL, 0);
163#endif
164 dest->SetValue(variables::kIsMac, is_mac, NULL);
165 declared_arguments_[variables::kIsMac] = is_mac;
166
167#if defined(OS_LINUX)
168 Value is_linux(NULL, 1);
169#else
170 Value is_linux(NULL, 0);
171#endif
172 dest->SetValue(variables::kIsLinux, is_linux, NULL);
173 declared_arguments_[variables::kIsLinux] = is_linux;
174}
175
176void Args::ApplyOverrides(const Scope::KeyValueMap& values,
177 Scope* scope) const {
178 for (Scope::KeyValueMap::const_iterator i = values.begin();
179 i != values.end(); ++i)
180 scope->SetValue(i->first, i->second, i->second.origin());
181}
182
183void Args::SaveOverrideRecord(const Scope::KeyValueMap& values) const {
184 base::AutoLock lock(lock_);
185 for (Scope::KeyValueMap::const_iterator i = values.begin();
186 i != values.end(); ++i)
187 all_overrides_[i->first] = i->second;
188}