Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(267)

Side by Side Diff: tools/gn/command_gyp.cc

Issue 26561005: GYP generator for GN (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/gn/build_settings.cc ('k') | tools/gn/escape.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <algorithm> 5 #include <iostream>
6 #include <fstream> 6 #include <map>
7 7 #include <utility>
8 #include "base/atomicops.h" 8 #include <vector>
9 #include "base/bind.h" 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
11 #include "base/file_util.h" 11 #include "base/environment.h"
12 #include "base/process/launch.h"
13 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "base/time/time.h" 13 #include "base/time/time.h"
16 #include "tools/gn/build_settings.h" 14 #include "tools/gn/build_settings.h"
17 #include "tools/gn/commands.h" 15 #include "tools/gn/commands.h"
18 #include "tools/gn/err.h" 16 #include "tools/gn/err.h"
19 #include "tools/gn/filesystem_utils.h" 17 #include "tools/gn/gyp_helper.h"
20 #include "tools/gn/ninja_target_writer.h" 18 #include "tools/gn/gyp_target_writer.h"
21 #include "tools/gn/ninja_writer.h" 19 #include "tools/gn/item_node.h"
22 #include "tools/gn/output_file.h" 20 #include "tools/gn/location.h"
23 #include "tools/gn/path_output.h"
24 #include "tools/gn/setup.h" 21 #include "tools/gn/setup.h"
22 #include "tools/gn/source_file.h"
25 #include "tools/gn/standard_out.h" 23 #include "tools/gn/standard_out.h"
24 #include "tools/gn/target.h"
26 25
27 namespace commands { 26 namespace commands {
28 27
29 namespace { 28 namespace {
30 29
30 typedef GypTargetWriter::TargetPair TargetPair;
31 typedef std::map<Label, TargetPair> CorrelatedTargetsMap;
32 typedef std::map<SourceFile, std::vector<TargetPair> > GroupedTargetsMap;
33 typedef std::map<std::string, std::string> StringStringMap;
34
35 // Groups targets sharing the same label between debug and release.
36 void CorrelateTargets(const std::vector<const Target*>& debug_targets,
37 const std::vector<const Target*>& release_targets,
38 CorrelatedTargetsMap* correlated) {
39 for (size_t i = 0; i < debug_targets.size(); i++) {
40 const Target* target = debug_targets[i];
41 (*correlated)[target->label()].debug = target;
42 }
43 for (size_t i = 0; i < release_targets.size(); i++) {
44 const Target* target = release_targets[i];
45 (*correlated)[target->label()].release = target;
46 }
47 }
48
49 // Verifies that both debug and release variants match. They can differ only
50 // by flags.
51 bool EnsureTargetsMatch(const TargetPair& pair, Err* err) {
52 // Check that both debug and release made this target.
53 if (!pair.debug || !pair.release) {
54 const Target* non_null_one = pair.debug ? pair.debug : pair.release;
55 *err = Err(Location(), "The debug and release builds did not both generate "
56 "a target with the name\n" +
57 non_null_one->label().GetUserVisibleName(true));
58 return false;
59 }
60
61 // Check the flags that determine if and where we write the GYP file.
62 if (pair.debug->item_node()->should_generate() !=
63 pair.release->item_node()->should_generate() ||
64 pair.debug->external() != pair.release->external() ||
65 pair.debug->gyp_file() != pair.release->gyp_file()) {
66 *err = Err(Location(), "The metadata for the target\n" +
67 pair.debug->label().GetUserVisibleName(true) +
68 "\ndoesn't match between the debug and release builds.");
69 return false;
70 }
71
72 // Check that the sources match.
73 if (pair.debug->sources().size() != pair.release->sources().size()) {
74 *err = Err(Location(), "The source file count for the target\n" +
75 pair.debug->label().GetUserVisibleName(true) +
76 "\ndoesn't have the same number of files between the debug and "
77 "release builds.");
78 return false;
79 }
80 for (size_t i = 0; i < pair.debug->sources().size(); i++) {
81 if (pair.debug->sources()[i] != pair.release->sources()[i]) {
82 *err = Err(Location(), "The debug and release version of the target \n" +
83 pair.debug->label().GetUserVisibleName(true) +
84 "\ndon't agree on the file\n" +
85 pair.debug->sources()[i].value());
86 return false;
87 }
88 }
89
90 // Check that the deps match.
91 if (pair.debug->deps().size() != pair.release->deps().size()) {
92 *err = Err(Location(), "The source file count for the target\n" +
93 pair.debug->label().GetUserVisibleName(true) +
94 "\ndoesn't have the same number of deps between the debug and "
95 "release builds.");
96 return false;
97 }
98 for (size_t i = 0; i < pair.debug->deps().size(); i++) {
99 if (pair.debug->deps()[i]->label() != pair.release->deps()[i]->label()) {
100 *err = Err(Location(), "The debug and release version of the target \n" +
101 pair.debug->label().GetUserVisibleName(true) +
102 "\ndon't agree on the dep\n" +
103 pair.debug->deps()[i]->label().GetUserVisibleName(true));
104 return false;
105 }
106 }
107
108 return true;
109 }
110
111 // Python uses shlex.split, which we partially emulate here.
112 //
113 // Advances to the next "word" in a GYP_DEFINES entry. This is something
114 // separated by whitespace or '='. We allow backslash escaping and quoting.
115 // The return value will be the index into the array immediately following the
116 // word, and the contents of the word will be placed into |*word|.
117 size_t GetNextGypDefinesWord(const std::string& defines,
118 size_t cur,
119 std::string* word) {
120 size_t i = cur;
121 bool is_quoted = false;
122 if (cur < defines.size() && defines[cur] == '"') {
123 i++;
124 is_quoted = true;
125 }
126
127 for (; i < defines.size(); i++) {
128 // Handle certain escape sequences: \\, \", \<space>.
129 if (defines[i] == '\\' && i < defines.size() - 1 &&
130 (defines[i + 1] == '\\' ||
131 defines[i + 1] == ' ' ||
132 defines[i + 1] == '=' ||
133 defines[i + 1] == '"')) {
134 i++;
135 word->push_back(defines[i]);
136 continue;
137 }
138 if (is_quoted && defines[i] == '"') {
139 // Got to the end of the quoted sequence.
140 return i + 1;
141 }
142 if (!is_quoted && (defines[i] == ' ' || defines[i] == '=')) {
143 return i;
144 }
145 word->push_back(defines[i]);
146 }
147 return i;
148 }
149
150 // Advances to the beginning of the next word, or the size of the string if
151 // the end was encountered.
152 size_t AdvanceToNextGypDefinesWord(const std::string& defines, size_t cur) {
153 while (cur < defines.size() && defines[cur] == ' ')
154 cur++;
155 return cur;
156 }
157
158 // The GYP defines looks like:
159 // component=shared_library
160 // component=shared_library foo=1
161 // component=shared_library foo=1 windows_sdk_dir="C:\Program Files\..."
162 StringStringMap GetGypDefines() {
163 StringStringMap result;
164
165 scoped_ptr<base::Environment> env(base::Environment::Create());
166 std::string defines;
167 if (!env->GetVar("GYP_DEFINES", &defines) || defines.empty())
168 return result;
169
170 size_t cur = 0;
171 while (cur < defines.size()) {
172 std::string key;
173 cur = AdvanceToNextGypDefinesWord(defines, cur);
174 cur = GetNextGypDefinesWord(defines, cur, &key);
175
176 // The words should be separated by an equals.
177 cur = AdvanceToNextGypDefinesWord(defines, cur);
178 if (cur == defines.size())
179 break;
180 if (defines[cur] != '=')
181 continue;
182 cur++; // Skip over '='.
183
184 std::string value;
185 cur = AdvanceToNextGypDefinesWord(defines, cur);
186 cur = GetNextGypDefinesWord(defines, cur, &value);
187
188 result[key] = value;
189 }
190
191 return result;
192 }
193
194 // Returns a set of args from known GYP define values.
195 Scope::KeyValueMap GetArgsFromGypDefines() {
196 StringStringMap gyp_defines = GetGypDefines();
197
198 Scope::KeyValueMap result;
199
200 if (gyp_defines["component"] == "shared_library") {
201 result["is_component_build"] = Value(NULL, true);
202 } else {
203 result["is_component_build"] = Value(NULL, false);
204 }
205
206 // Windows SDK path. GYP and the GN build use the same name.
207 const char kWinSdkPath[] = "windows_sdk_path";
208 if (gyp_defines[kWinSdkPath].empty())
209 result[kWinSdkPath] = Value(NULL, gyp_defines[kWinSdkPath]);
210
211 return result;
212 }
213
214 // Returns the number of targets, number of GYP files.
215 std::pair<int, int> WriteGypFiles(
216 const BuildSettings& debug_settings,
217 const BuildSettings& release_settings,
218 Err* err) {
219 // Group all targets by output GYP file name.
220 std::vector<const Target*> debug_targets;
221 std::vector<const Target*> release_targets;
222 debug_settings.target_manager().GetAllTargets(&debug_targets);
223 release_settings.target_manager().GetAllTargets(&release_targets);
224
225 // Match up the debug and release version of each target by label.
226 CorrelatedTargetsMap correlated;
227 CorrelateTargets(debug_targets, release_targets, &correlated);
228
229 GypHelper helper;
230 GroupedTargetsMap grouped_targets;
231 int target_count = 0;
232 for (CorrelatedTargetsMap::iterator i = correlated.begin();
233 i != correlated.end(); ++i) {
234 const TargetPair& pair = i->second;
235 if (!EnsureTargetsMatch(pair, err))
236 return std::make_pair(0, 0);
237
238 if (!pair.debug->item_node()->should_generate())
239 continue; // Skip non-generated ones.
240 if (pair.debug->external())
241 continue; // Skip external ones.
242 if (pair.debug->gyp_file().is_null())
243 continue; // Skip ones without GYP files.
244
245 target_count++;
246 grouped_targets[helper.GetGypFileForTarget(pair.debug, err)].push_back(
247 pair);
248 if (err->has_error())
249 return std::make_pair(0, 0);
250 }
251
252 // Write each GYP file.
253 for (GroupedTargetsMap::iterator i = grouped_targets.begin();
254 i != grouped_targets.end(); ++i) {
255 GypTargetWriter::WriteFile(i->first, i->second, err);
256 if (err->has_error())
257 return std::make_pair(0, 0);
258 }
259
260 return std::make_pair(target_count,
261 static_cast<int>(grouped_targets.size()));
262 }
263
264 } // namespace
265
31 // Suppress output on success. 266 // Suppress output on success.
32 const char kSwitchQuiet[] = "q"; 267 const char kSwitchQuiet[] = "q";
33 268
34 // Skip actually executing GYP. This is for when you're working on the GN
35 // build and don't want to wait for GYP to regenerate. All GN files are
36 // regenerated, but the GYP ones are not.
37 const char kSwitchNoGyp[] = "no-gyp";
38
39 // Where to have GYP write its outputs.
40 const char kDirOut[] = "out.gn";
41
42 // We'll do the GN build to here.
43 const char kBuildSourceDir[] = "//out.gn/Debug/";
44
45 // File that GYP will write dependency information to.
46 const char kGypDepsSourceFileName[] = "//out.gn/gyp_deps.txt";
47
48 void TargetResolvedCallback(base::subtle::Atomic32* write_counter,
49 const Target* target) {
50 base::subtle::NoBarrier_AtomicIncrement(write_counter, 1);
51 NinjaTargetWriter::RunAndWriteFile(target);
52 }
53
54 bool SimpleNinjaParse(const std::string& data,
55 std::set<std::string>* subninjas,
56 size_t* first_subninja_offset) {
57 const size_t kSubninjaPrefixLen = 10;
58 const char kSubninjaPrefix[kSubninjaPrefixLen + 1] = "\nsubninja ";
59
60 *first_subninja_offset = std::string::npos;
61 size_t next_subninja = 0;
62 while ((next_subninja = data.find(kSubninjaPrefix, next_subninja)) !=
63 std::string::npos) {
64 if (*first_subninja_offset == std::string::npos)
65 *first_subninja_offset = next_subninja;
66
67 size_t line_end = data.find('\n', next_subninja + 1);
68 if (line_end == std::string::npos)
69 return false;
70
71 std::string filename = data.substr(
72 next_subninja + kSubninjaPrefixLen,
73 line_end - next_subninja - kSubninjaPrefixLen);
74 TrimWhitespaceASCII(filename, TRIM_ALL, &filename);
75 #if defined(OS_WIN)
76 // We always want our array to use forward slashes.
77 std::replace(filename.begin(), filename.end(), '\\', '/');
78 #endif
79 subninjas->insert(filename);
80
81 next_subninja = line_end;
82 }
83 return *first_subninja_offset != std::string::npos;
84 }
85
86 bool FixupBuildNinja(const BuildSettings* build_settings,
87 const base::FilePath& buildfile) {
88 std::string contents;
89 if (!base::ReadFileToString(buildfile, &contents)) {
90 Err(Location(), "Could not load " + FilePathToUTF8(buildfile))
91 .PrintToStdout();
92 return false;
93 }
94
95 std::set<std::string> subninjas;
96 size_t first_subninja_offset = 0;
97 if (!SimpleNinjaParse(contents, &subninjas, &first_subninja_offset)) {
98 Err(Location(), "Could not parse " + FilePathToUTF8(buildfile))
99 .PrintToStdout();
100 return false;
101 }
102
103 // Write toolchain files.
104 std::vector<const Settings*> all_settings;
105 if (!NinjaWriter::RunAndWriteToolchainFiles(
106 build_settings, subninjas, &all_settings))
107 return false;
108
109 // Copy first part of buildfile to the output.
110 std::ofstream file;
111 file.open(FilePathToUTF8(buildfile).c_str(),
112 std::ios_base::out | std::ios_base::binary);
113 if (file.fail()) {
114 Err(Location(), "Could not write " + FilePathToUTF8(buildfile))
115 .PrintToStdout();
116 return false;
117 }
118 file.write(contents.data(), first_subninja_offset);
119
120 // Add refs for our toolchains to the original build.ninja.
121 NinjaHelper helper(build_settings);
122 PathOutput path_output(build_settings->build_dir(), ESCAPE_NINJA, true);
123 file << "\n# GN-added toolchain files.\n";
124 for (size_t i = 0; i < all_settings.size(); i++) {
125 file << "subninja ";
126 path_output.WriteFile(file,
127 helper.GetNinjaFileForToolchain(all_settings[i]));
128 file << std::endl;
129 }
130 file << "\n# GYP-written subninjas.";
131
132 // Write remaining old subninjas from original file.
133 file.write(&contents[first_subninja_offset],
134 contents.size() - first_subninja_offset);
135 return true;
136 }
137
138 bool RunGyp(const BuildSettings* build_settings) {
139 if (!CommandLine::ForCurrentProcess()->HasSwitch(kSwitchQuiet))
140 OutputString("Running GYP...\n");
141
142 const base::FilePath& python_path = build_settings->python_path();
143
144 // Construct the command line. Note that AppendArgPath and AppendSwitchPath
145 // don't preserve the relative ordering, and we need the python file to be
146 // first, so we have to convert switch values to strings before appending.
147 //
148 // Note that GYP will get confused if this path is quoted, so don't quote it
149 // and hope that there are no spaces!
150 CommandLine cmdline(python_path);
151 cmdline.AppendArgPath(
152 build_settings->GetFullPath(SourceFile("//build/gyp_chromium.py")));
153
154 // Override the default output directory so we can coexist in parallel
155 // with a normal Ninja GYP build.
156 cmdline.AppendArg("-G");
157 cmdline.AppendArg(std::string("output_dir=") + kDirOut);
158
159 // Force the Ninja generator.
160 cmdline.AppendArg("-f");
161 cmdline.AppendArg("ninja");
162
163 // Write deps for libraries so we can pick them up.
164 cmdline.AppendArg("-G");
165 cmdline.AppendArg("link_deps_file=" + FilePathToUTF8(
166 build_settings->GetFullPath(SourceFile(kGypDepsSourceFileName))));
167
168 std::string output;
169 if (!base::GetAppOutput(cmdline, &output)) {
170 Err(Location(), "GYP execution failed.", output).PrintToStdout();
171 return false;
172 }
173 return true;
174 }
175
176 } // namespace
177
178 // Converts a GYP qualified target which looks like:
179 // "/home/you/src/third_party/icu/icu.gyp:icui18n#target" to a GN label like
180 // "//third_party/icu:icui18n". On failure returns an empty label and sets the
181 // error.
182 Label GypQualifiedTargetToLabel(const std::string& source_root_prefix,
183 const base::StringPiece& target,
184 Err* err) {
185 // Prefix should end in canonical path separator.
186 const char kSep = static_cast<char>(base::FilePath::kSeparators[0]);
187 DCHECK(source_root_prefix[source_root_prefix.size() - 1] == kSep);
188
189 if (!target.starts_with(source_root_prefix)) {
190 *err = Err(Location(), "GYP deps parsing failed.",
191 "The line was \"" + target.as_string() + "\" and it should have "
192 "started with \"" + source_root_prefix + "\"");
193 return Label();
194 }
195
196 size_t begin = source_root_prefix.size();
197 size_t colon = target.find(':', begin);
198 if (colon == std::string::npos) {
199 *err = Err(Location(), "Expected :", target.as_string());
200 return Label();
201 }
202
203 size_t octothorpe = target.find('#', colon);
204 if (octothorpe == std::string::npos) {
205 *err = Err(Location(), "Expected #", target.as_string());
206 return Label();
207 }
208
209 // This will look like "third_party/icu/icu.gyp"
210 base::StringPiece gyp_file = target.substr(begin, colon - begin);
211
212 // Strip the file name from the end to get "third_party/icu".
213 size_t last_sep = gyp_file.find_last_of(kSep);
214 if (last_sep == std::string::npos) {
215 *err = Err(Location(), "Expected path separator.", target.as_string());
216 return Label();
217 }
218 base::StringPiece path = gyp_file.substr(0, last_sep);
219 SourceDir dir("//" + path.as_string());
220
221 base::StringPiece name = target.substr(colon + 1, octothorpe - colon - 1);
222
223 return Label(dir, name);
224 }
225
226 // Parses the link deps file, filling the given map. Returns true on sucess.
227 // On failure fills the error and returns false.
228 //
229 // Example format for each line:
230 // /home/you/src/third_party/icu/icu.gyp:icui18n#target lib/libi18n.so
231 bool ParseLinkDepsFile(const BuildSettings* build_settings,
232 const std::string& contents,
233 BuildSettings::AdditionalLibsMap* deps,
234 Err* err) {
235 std::string source_root_prefix = FilePathToUTF8(build_settings->root_path());
236 source_root_prefix.push_back(base::FilePath::kSeparators[0]);
237
238 size_t cur = 0;
239 while (cur < contents.size()) {
240 // The source file is everything up to the space.
241 size_t space = contents.find(' ', cur);
242 if (space == std::string::npos)
243 break;
244 Label source(GypQualifiedTargetToLabel(
245 source_root_prefix,
246 base::StringPiece(&contents[cur], space - cur),
247 err));
248 if (source.is_null())
249 return false;
250
251 // The library file is everything between the space and EOL.
252 cur = space + 1;
253 size_t eol = contents.find('\n', cur);
254 if (eol == std::string::npos) {
255 *err = Err(Location(), "Expected newline at end of link deps file.");
256 return false;
257 }
258 OutputFile lib(contents.substr(cur, eol - cur));
259
260 deps->insert(std::make_pair(source, lib));
261 cur = eol + 1;
262 }
263 return true;
264 }
265
266 const char kGyp[] = "gyp"; 269 const char kGyp[] = "gyp";
267 const char kGyp_HelpShort[] = 270 const char kGyp_HelpShort[] =
268 "gyp: Run GYP and then GN."; 271 "gyp: Make GYP files from GN.";
269 const char kGyp_Help[] = 272 const char kGyp_Help[] = "Doooooom.\n";
270 "gyp: Run GYP and then GN.\n" 273
271 "\n"
272 " Generate a hybrid GYP/GN build where some targets are generated by\n"
273 " each of the tools. As long as target names and locations match between\n"
274 " the two tools, they can depend on each other.\n"
275 "\n"
276 " When GN is run in this mode, it will not write out any targets\n"
277 " annotated with \"external = true\". Otherwise, GYP targets with the\n"
278 " same name and location will be overwritten.\n"
279 "\n"
280 " References to the GN ninja files will be inserted into the\n"
281 " GYP-generated build.ninja file.\n"
282 "\n"
283 "Option:\n"
284 " --no-gyp\n"
285 " Don't actually run GYP or modify build.ninja. This is used when\n"
286 " working on the GN build when it is known that no GYP files have\n"
287 " changed and you want it to run faster.\n";
288
289 // Note: partially duplicated from command_gen.cc.
290 int RunGyp(const std::vector<std::string>& args) { 274 int RunGyp(const std::vector<std::string>& args) {
291 const CommandLine* cmdline = CommandLine::ForCurrentProcess(); 275 const CommandLine* cmdline = CommandLine::ForCurrentProcess();
292 bool no_gyp = cmdline->HasSwitch(kSwitchNoGyp); 276
277 base::TimeTicks begin_time = base::TimeTicks::Now();
293 278
294 // Deliberately leaked to avoid expensive process teardown. 279 // Deliberately leaked to avoid expensive process teardown.
295 Setup* setup = new Setup; 280 Setup* setup_debug = new Setup;
296 if (!setup->DoSetup()) 281 if (!setup_debug->DoSetup())
297 return 1; 282 return 1;
298 283 const char kIsDebug[] = "is_debug";
299 setup->build_settings().SetBuildDir(SourceDir(kBuildSourceDir)); 284 setup_debug->build_settings().build_args().AddArgOverrides(
300 setup->build_settings().set_using_external_generator(true); 285 GetArgsFromGypDefines());
301 286 setup_debug->build_settings().build_args().AddArgOverride(
302 // Provide a way for buildfiles to know we're doing a GYP build. 287 kIsDebug, Value(NULL, true));
303 /* 288
304 Scope::KeyValueMap variable_overrides; 289 // Make a release build based on the debug one. We use a new directory for
305 variable_overrides["is_gyp"] = Value(NULL, true); 290 // the build output so that they don't stomp on each other.
306 setup->build_settings().build_args().AddArgOverrides(variable_overrides); 291 DependentSetup* setup_release = new DependentSetup(*setup_debug);
307 */ 292 setup_release->build_settings().build_args().AddArgOverride(
308 293 kIsDebug, Value(NULL, false));
309 base::FilePath link_deps_file = 294 setup_release->build_settings().SetBuildDir(
310 setup->build_settings().GetFullPath(SourceFile(kGypDepsSourceFileName)); 295 SourceDir(setup_release->build_settings().build_dir().value() +
311 if (!no_gyp) 296 "gn_release.tmp/"));
312 base::DeleteFile(link_deps_file, false); 297
313 298 // Run both debug and release builds in parallel.
314 base::TimeTicks begin_time = base::TimeTicks::Now(); 299 setup_release->RunPreMessageLoop();
315 if (!no_gyp) { 300 if (!setup_debug->Run())
316 if (!RunGyp(&setup->build_settings()))
317 return 1;
318 }
319 base::TimeTicks end_gyp_time = base::TimeTicks::Now();
320
321 // Read in the GYP link dependencies.
322 std::string link_deps_contents;
323 if (!base::ReadFileToString(link_deps_file, &link_deps_contents)) {
324 Err(Location(), "Couldn't load link deps file.",
325 FilePathToUTF8(link_deps_file)).PrintToStdout();
326 return 1; 301 return 1;
327 } 302 if (!setup_release->RunPostMessageLoop())
303 return 1;
304
328 Err err; 305 Err err;
329 if (!ParseLinkDepsFile(&setup->build_settings(), 306 std::pair<int, int> counts = WriteGypFiles(setup_debug->build_settings(),
330 link_deps_contents, 307 setup_release->build_settings(),
331 &setup->build_settings().external_link_deps(), &err)) { 308 &err);
309 if (err.has_error()) {
332 err.PrintToStdout(); 310 err.PrintToStdout();
333 return 1; 311 return 1;
334 } 312 }
335 313
336 if (!cmdline->HasSwitch(kSwitchQuiet))
337 OutputString("Running GN...\n");
338
339 // Cause the load to also generate the ninja files for each target. We wrap
340 // the writing to maintain a counter.
341 base::subtle::Atomic32 write_counter = 0;
342 setup->build_settings().set_target_resolved_callback(
343 base::Bind(&TargetResolvedCallback, &write_counter));
344
345 // Do the actual load. This will also write out the target ninja files.
346 if (!setup->Run())
347 return 1;
348
349 // Integrate with the GYP build.
350 if (!no_gyp) {
351 base::FilePath ninja_buildfile(setup->build_settings().GetFullPath(
352 SourceFile(setup->build_settings().build_dir().value() +
353 "build.ninja")));
354 if (!FixupBuildNinja(&setup->build_settings(), ninja_buildfile))
355 return 1;
356 }
357
358 // Timing info. 314 // Timing info.
359 base::TimeTicks end_time = base::TimeTicks::Now(); 315 base::TimeTicks end_time = base::TimeTicks::Now();
360 if (!cmdline->HasSwitch(kSwitchQuiet)) { 316 if (!cmdline->HasSwitch(kSwitchQuiet)) {
361 OutputString("Done. ", DECORATION_GREEN); 317 OutputString("Done. ", DECORATION_GREEN);
362 318
363 std::string stats = "Wrote " + 319 std::string stats = "Wrote " +
364 base::IntToString(static_cast<int>(write_counter)) + 320 base::IntToString(counts.first) + " targets to " +
365 " targets from " + 321 base::IntToString(counts.second) + " GYP files read from " +
366 base::IntToString( 322 base::IntToString(
367 setup->scheduler().input_file_manager()->GetInputFileCount()) + 323 setup_debug->scheduler().input_file_manager()->GetInputFileCount())
368 " files in " + 324 + " GN files in " +
369 base::IntToString((end_time - end_gyp_time).InMilliseconds()) + "ms " + 325 base::IntToString((end_time - begin_time).InMilliseconds()) + "ms\n";
370 "(GYP took " +
371 base::IntToString((end_gyp_time - begin_time).InMilliseconds()) +
372 "ms)\n";
373 326
374 OutputString(stats); 327 OutputString(stats);
375 } 328 }
376 329
377 return 0; 330 return 0;
378 } 331 }
379 332
380 } // namespace commands 333 } // namespace commands
OLDNEW
« no previous file with comments | « tools/gn/build_settings.cc ('k') | tools/gn/escape.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698