Index: tools/gn/command_gyp.cc |
diff --git a/tools/gn/command_gyp.cc b/tools/gn/command_gyp.cc |
index bc5ab5dba068f1ca23a1ab926ad32965332d3aa0..9c005136088a25f5fbd889e671c58d99064b2a35 100644 |
--- a/tools/gn/command_gyp.cc |
+++ b/tools/gn/command_gyp.cc |
@@ -2,357 +2,313 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include <algorithm> |
-#include <fstream> |
+#include <iostream> |
+#include <map> |
+#include <utility> |
+#include <vector> |
-#include "base/atomicops.h" |
-#include "base/bind.h" |
#include "base/command_line.h" |
-#include "base/file_util.h" |
-#include "base/process/launch.h" |
+#include "base/environment.h" |
#include "base/strings/string_number_conversions.h" |
-#include "base/strings/string_util.h" |
#include "base/time/time.h" |
#include "tools/gn/build_settings.h" |
#include "tools/gn/commands.h" |
#include "tools/gn/err.h" |
-#include "tools/gn/filesystem_utils.h" |
-#include "tools/gn/ninja_target_writer.h" |
-#include "tools/gn/ninja_writer.h" |
-#include "tools/gn/output_file.h" |
-#include "tools/gn/path_output.h" |
+#include "tools/gn/gyp_helper.h" |
+#include "tools/gn/gyp_target_writer.h" |
+#include "tools/gn/item_node.h" |
+#include "tools/gn/location.h" |
#include "tools/gn/setup.h" |
+#include "tools/gn/source_file.h" |
#include "tools/gn/standard_out.h" |
+#include "tools/gn/target.h" |
namespace commands { |
namespace { |
-// Suppress output on success. |
-const char kSwitchQuiet[] = "q"; |
- |
-// Skip actually executing GYP. This is for when you're working on the GN |
-// build and don't want to wait for GYP to regenerate. All GN files are |
-// regenerated, but the GYP ones are not. |
-const char kSwitchNoGyp[] = "no-gyp"; |
- |
-// Where to have GYP write its outputs. |
-const char kDirOut[] = "out.gn"; |
- |
-// We'll do the GN build to here. |
-const char kBuildSourceDir[] = "//out.gn/Debug/"; |
- |
-// File that GYP will write dependency information to. |
-const char kGypDepsSourceFileName[] = "//out.gn/gyp_deps.txt"; |
- |
-void TargetResolvedCallback(base::subtle::Atomic32* write_counter, |
- const Target* target) { |
- base::subtle::NoBarrier_AtomicIncrement(write_counter, 1); |
- NinjaTargetWriter::RunAndWriteFile(target); |
-} |
- |
-bool SimpleNinjaParse(const std::string& data, |
- std::set<std::string>* subninjas, |
- size_t* first_subninja_offset) { |
- const size_t kSubninjaPrefixLen = 10; |
- const char kSubninjaPrefix[kSubninjaPrefixLen + 1] = "\nsubninja "; |
- |
- *first_subninja_offset = std::string::npos; |
- size_t next_subninja = 0; |
- while ((next_subninja = data.find(kSubninjaPrefix, next_subninja)) != |
- std::string::npos) { |
- if (*first_subninja_offset == std::string::npos) |
- *first_subninja_offset = next_subninja; |
- |
- size_t line_end = data.find('\n', next_subninja + 1); |
- if (line_end == std::string::npos) |
- return false; |
- |
- std::string filename = data.substr( |
- next_subninja + kSubninjaPrefixLen, |
- line_end - next_subninja - kSubninjaPrefixLen); |
- TrimWhitespaceASCII(filename, TRIM_ALL, &filename); |
-#if defined(OS_WIN) |
- // We always want our array to use forward slashes. |
- std::replace(filename.begin(), filename.end(), '\\', '/'); |
-#endif |
- subninjas->insert(filename); |
- |
- next_subninja = line_end; |
+typedef GypTargetWriter::TargetPair TargetPair; |
+typedef std::map<Label, TargetPair> CorrelatedTargetsMap; |
+typedef std::map<SourceFile, std::vector<TargetPair> > GroupedTargetsMap; |
+typedef std::map<std::string, std::string> StringStringMap; |
+ |
+// Groups targets sharing the same label between debug and release. |
+void CorrelateTargets(const std::vector<const Target*>& debug_targets, |
+ const std::vector<const Target*>& release_targets, |
+ CorrelatedTargetsMap* correlated) { |
+ for (size_t i = 0; i < debug_targets.size(); i++) { |
+ const Target* target = debug_targets[i]; |
+ (*correlated)[target->label()].debug = target; |
+ } |
+ for (size_t i = 0; i < release_targets.size(); i++) { |
+ const Target* target = release_targets[i]; |
+ (*correlated)[target->label()].release = target; |
} |
- return *first_subninja_offset != std::string::npos; |
} |
-bool FixupBuildNinja(const BuildSettings* build_settings, |
- const base::FilePath& buildfile) { |
- std::string contents; |
- if (!base::ReadFileToString(buildfile, &contents)) { |
- Err(Location(), "Could not load " + FilePathToUTF8(buildfile)) |
- .PrintToStdout(); |
+// Verifies that both debug and release variants match. They can differ only |
+// by flags. |
+bool EnsureTargetsMatch(const TargetPair& pair, Err* err) { |
+ // Check that both debug and release made this target. |
+ if (!pair.debug || !pair.release) { |
+ const Target* non_null_one = pair.debug ? pair.debug : pair.release; |
+ *err = Err(Location(), "The debug and release builds did not both generate " |
+ "a target with the name\n" + |
+ non_null_one->label().GetUserVisibleName(true)); |
return false; |
} |
- std::set<std::string> subninjas; |
- size_t first_subninja_offset = 0; |
- if (!SimpleNinjaParse(contents, &subninjas, &first_subninja_offset)) { |
- Err(Location(), "Could not parse " + FilePathToUTF8(buildfile)) |
- .PrintToStdout(); |
+ // Check the flags that determine if and where we write the GYP file. |
+ if (pair.debug->item_node()->should_generate() != |
+ pair.release->item_node()->should_generate() || |
+ pair.debug->external() != pair.release->external() || |
+ pair.debug->gyp_file() != pair.release->gyp_file()) { |
+ *err = Err(Location(), "The metadata for the target\n" + |
+ pair.debug->label().GetUserVisibleName(true) + |
+ "\ndoesn't match between the debug and release builds."); |
return false; |
} |
- // Write toolchain files. |
- std::vector<const Settings*> all_settings; |
- if (!NinjaWriter::RunAndWriteToolchainFiles( |
- build_settings, subninjas, &all_settings)) |
+ // Check that the sources match. |
+ if (pair.debug->sources().size() != pair.release->sources().size()) { |
+ *err = Err(Location(), "The source file count for the target\n" + |
+ pair.debug->label().GetUserVisibleName(true) + |
+ "\ndoesn't have the same number of files between the debug and " |
+ "release builds."); |
return false; |
+ } |
+ for (size_t i = 0; i < pair.debug->sources().size(); i++) { |
+ if (pair.debug->sources()[i] != pair.release->sources()[i]) { |
+ *err = Err(Location(), "The debug and release version of the target \n" + |
+ pair.debug->label().GetUserVisibleName(true) + |
+ "\ndon't agree on the file\n" + |
+ pair.debug->sources()[i].value()); |
+ return false; |
+ } |
+ } |
- // Copy first part of buildfile to the output. |
- std::ofstream file; |
- file.open(FilePathToUTF8(buildfile).c_str(), |
- std::ios_base::out | std::ios_base::binary); |
- if (file.fail()) { |
- Err(Location(), "Could not write " + FilePathToUTF8(buildfile)) |
- .PrintToStdout(); |
+ // Check that the deps match. |
+ if (pair.debug->deps().size() != pair.release->deps().size()) { |
+ *err = Err(Location(), "The source file count for the target\n" + |
+ pair.debug->label().GetUserVisibleName(true) + |
+ "\ndoesn't have the same number of deps between the debug and " |
+ "release builds."); |
return false; |
} |
- file.write(contents.data(), first_subninja_offset); |
- |
- // Add refs for our toolchains to the original build.ninja. |
- NinjaHelper helper(build_settings); |
- PathOutput path_output(build_settings->build_dir(), ESCAPE_NINJA, true); |
- file << "\n# GN-added toolchain files.\n"; |
- for (size_t i = 0; i < all_settings.size(); i++) { |
- file << "subninja "; |
- path_output.WriteFile(file, |
- helper.GetNinjaFileForToolchain(all_settings[i])); |
- file << std::endl; |
+ for (size_t i = 0; i < pair.debug->deps().size(); i++) { |
+ if (pair.debug->deps()[i]->label() != pair.release->deps()[i]->label()) { |
+ *err = Err(Location(), "The debug and release version of the target \n" + |
+ pair.debug->label().GetUserVisibleName(true) + |
+ "\ndon't agree on the dep\n" + |
+ pair.debug->deps()[i]->label().GetUserVisibleName(true)); |
+ return false; |
+ } |
} |
- file << "\n# GYP-written subninjas."; |
- // Write remaining old subninjas from original file. |
- file.write(&contents[first_subninja_offset], |
- contents.size() - first_subninja_offset); |
return true; |
} |
-bool RunGyp(const BuildSettings* build_settings) { |
- if (!CommandLine::ForCurrentProcess()->HasSwitch(kSwitchQuiet)) |
- OutputString("Running GYP...\n"); |
- |
- const base::FilePath& python_path = build_settings->python_path(); |
- |
- // Construct the command line. Note that AppendArgPath and AppendSwitchPath |
- // don't preserve the relative ordering, and we need the python file to be |
- // first, so we have to convert switch values to strings before appending. |
- // |
- // Note that GYP will get confused if this path is quoted, so don't quote it |
- // and hope that there are no spaces! |
- CommandLine cmdline(python_path); |
- cmdline.AppendArgPath( |
- build_settings->GetFullPath(SourceFile("//build/gyp_chromium.py"))); |
- |
- // Override the default output directory so we can coexist in parallel |
- // with a normal Ninja GYP build. |
- cmdline.AppendArg("-G"); |
- cmdline.AppendArg(std::string("output_dir=") + kDirOut); |
- |
- // Force the Ninja generator. |
- cmdline.AppendArg("-f"); |
- cmdline.AppendArg("ninja"); |
- |
- // Write deps for libraries so we can pick them up. |
- cmdline.AppendArg("-G"); |
- cmdline.AppendArg("link_deps_file=" + FilePathToUTF8( |
- build_settings->GetFullPath(SourceFile(kGypDepsSourceFileName)))); |
- |
- std::string output; |
- if (!base::GetAppOutput(cmdline, &output)) { |
- Err(Location(), "GYP execution failed.", output).PrintToStdout(); |
- return false; |
+// Python uses shlex.split, which we partially emulate here. |
+// |
+// Advances to the next "word" in a GYP_DEFINES entry. This is something |
+// separated by whitespace or '='. We allow backslash escaping and quoting. |
+// The return value will be the index into the array immediately following the |
+// word, and the contents of the word will be placed into |*word|. |
+size_t GetNextGypDefinesWord(const std::string& defines, |
+ size_t cur, |
+ std::string* word) { |
+ size_t i = cur; |
+ bool is_quoted = false; |
+ if (cur < defines.size() && defines[cur] == '"') { |
+ i++; |
+ is_quoted = true; |
} |
- return true; |
+ |
+ for (; i < defines.size(); i++) { |
+ // Handle certain escape sequences: \\, \", \<space>. |
+ if (defines[i] == '\\' && i < defines.size() - 1 && |
+ (defines[i + 1] == '\\' || |
+ defines[i + 1] == ' ' || |
+ defines[i + 1] == '=' || |
+ defines[i + 1] == '"')) { |
+ i++; |
+ word->push_back(defines[i]); |
+ continue; |
+ } |
+ if (is_quoted && defines[i] == '"') { |
+ // Got to the end of the quoted sequence. |
+ return i + 1; |
+ } |
+ if (!is_quoted && (defines[i] == ' ' || defines[i] == '=')) { |
+ return i; |
+ } |
+ word->push_back(defines[i]); |
+ } |
+ return i; |
} |
-} // namespace |
+// Advances to the beginning of the next word, or the size of the string if |
+// the end was encountered. |
+size_t AdvanceToNextGypDefinesWord(const std::string& defines, size_t cur) { |
+ while (cur < defines.size() && defines[cur] == ' ') |
+ cur++; |
+ return cur; |
+} |
-// Converts a GYP qualified target which looks like: |
-// "/home/you/src/third_party/icu/icu.gyp:icui18n#target" to a GN label like |
-// "//third_party/icu:icui18n". On failure returns an empty label and sets the |
-// error. |
-Label GypQualifiedTargetToLabel(const std::string& source_root_prefix, |
- const base::StringPiece& target, |
- Err* err) { |
- // Prefix should end in canonical path separator. |
- const char kSep = static_cast<char>(base::FilePath::kSeparators[0]); |
- DCHECK(source_root_prefix[source_root_prefix.size() - 1] == kSep); |
- |
- if (!target.starts_with(source_root_prefix)) { |
- *err = Err(Location(), "GYP deps parsing failed.", |
- "The line was \"" + target.as_string() + "\" and it should have " |
- "started with \"" + source_root_prefix + "\""); |
- return Label(); |
- } |
+// The GYP defines looks like: |
+// component=shared_library |
+// component=shared_library foo=1 |
+// component=shared_library foo=1 windows_sdk_dir="C:\Program Files\..." |
+StringStringMap GetGypDefines() { |
+ StringStringMap result; |
- size_t begin = source_root_prefix.size(); |
- size_t colon = target.find(':', begin); |
- if (colon == std::string::npos) { |
- *err = Err(Location(), "Expected :", target.as_string()); |
- return Label(); |
- } |
+ scoped_ptr<base::Environment> env(base::Environment::Create()); |
+ std::string defines; |
+ if (!env->GetVar("GYP_DEFINES", &defines) || defines.empty()) |
+ return result; |
- size_t octothorpe = target.find('#', colon); |
- if (octothorpe == std::string::npos) { |
- *err = Err(Location(), "Expected #", target.as_string()); |
- return Label(); |
- } |
+ size_t cur = 0; |
+ while (cur < defines.size()) { |
+ std::string key; |
+ cur = AdvanceToNextGypDefinesWord(defines, cur); |
+ cur = GetNextGypDefinesWord(defines, cur, &key); |
+ |
+ // The words should be separated by an equals. |
+ cur = AdvanceToNextGypDefinesWord(defines, cur); |
+ if (cur == defines.size()) |
+ break; |
+ if (defines[cur] != '=') |
+ continue; |
+ cur++; // Skip over '='. |
- // This will look like "third_party/icu/icu.gyp" |
- base::StringPiece gyp_file = target.substr(begin, colon - begin); |
+ std::string value; |
+ cur = AdvanceToNextGypDefinesWord(defines, cur); |
+ cur = GetNextGypDefinesWord(defines, cur, &value); |
- // Strip the file name from the end to get "third_party/icu". |
- size_t last_sep = gyp_file.find_last_of(kSep); |
- if (last_sep == std::string::npos) { |
- *err = Err(Location(), "Expected path separator.", target.as_string()); |
- return Label(); |
+ result[key] = value; |
} |
- base::StringPiece path = gyp_file.substr(0, last_sep); |
- SourceDir dir("//" + path.as_string()); |
- |
- base::StringPiece name = target.substr(colon + 1, octothorpe - colon - 1); |
- return Label(dir, name); |
+ return result; |
} |
-// Parses the link deps file, filling the given map. Returns true on sucess. |
-// On failure fills the error and returns false. |
-// |
-// Example format for each line: |
-// /home/you/src/third_party/icu/icu.gyp:icui18n#target lib/libi18n.so |
-bool ParseLinkDepsFile(const BuildSettings* build_settings, |
- const std::string& contents, |
- BuildSettings::AdditionalLibsMap* deps, |
- Err* err) { |
- std::string source_root_prefix = FilePathToUTF8(build_settings->root_path()); |
- source_root_prefix.push_back(base::FilePath::kSeparators[0]); |
+// Returns a set of args from known GYP define values. |
+Scope::KeyValueMap GetArgsFromGypDefines() { |
+ StringStringMap gyp_defines = GetGypDefines(); |
- size_t cur = 0; |
- while (cur < contents.size()) { |
- // The source file is everything up to the space. |
- size_t space = contents.find(' ', cur); |
- if (space == std::string::npos) |
- break; |
- Label source(GypQualifiedTargetToLabel( |
- source_root_prefix, |
- base::StringPiece(&contents[cur], space - cur), |
- err)); |
- if (source.is_null()) |
- return false; |
+ Scope::KeyValueMap result; |
- // The library file is everything between the space and EOL. |
- cur = space + 1; |
- size_t eol = contents.find('\n', cur); |
- if (eol == std::string::npos) { |
- *err = Err(Location(), "Expected newline at end of link deps file."); |
- return false; |
- } |
- OutputFile lib(contents.substr(cur, eol - cur)); |
+ if (gyp_defines["component"] == "shared_library") { |
+ result["is_component_build"] = Value(NULL, true); |
+ } else { |
+ result["is_component_build"] = Value(NULL, false); |
+ } |
- deps->insert(std::make_pair(source, lib)); |
- cur = eol + 1; |
+ // Windows SDK path. GYP and the GN build use the same name. |
+ const char kWinSdkPath[] = "windows_sdk_path"; |
+ if (gyp_defines[kWinSdkPath].empty()) |
+ result[kWinSdkPath] = Value(NULL, gyp_defines[kWinSdkPath]); |
+ |
+ return result; |
+} |
+ |
+// Returns the number of targets, number of GYP files. |
+std::pair<int, int> WriteGypFiles( |
+ const BuildSettings& debug_settings, |
+ const BuildSettings& release_settings, |
+ Err* err) { |
+ // Group all targets by output GYP file name. |
+ std::vector<const Target*> debug_targets; |
+ std::vector<const Target*> release_targets; |
+ debug_settings.target_manager().GetAllTargets(&debug_targets); |
+ release_settings.target_manager().GetAllTargets(&release_targets); |
+ |
+ // Match up the debug and release version of each target by label. |
+ CorrelatedTargetsMap correlated; |
+ CorrelateTargets(debug_targets, release_targets, &correlated); |
+ |
+ GypHelper helper; |
+ GroupedTargetsMap grouped_targets; |
+ int target_count = 0; |
+ for (CorrelatedTargetsMap::iterator i = correlated.begin(); |
+ i != correlated.end(); ++i) { |
+ const TargetPair& pair = i->second; |
+ if (!EnsureTargetsMatch(pair, err)) |
+ return std::make_pair(0, 0); |
+ |
+ if (!pair.debug->item_node()->should_generate()) |
+ continue; // Skip non-generated ones. |
+ if (pair.debug->external()) |
+ continue; // Skip external ones. |
+ if (pair.debug->gyp_file().is_null()) |
+ continue; // Skip ones without GYP files. |
+ |
+ target_count++; |
+ grouped_targets[helper.GetGypFileForTarget(pair.debug, err)].push_back( |
+ pair); |
+ if (err->has_error()) |
+ return std::make_pair(0, 0); |
} |
- return true; |
+ |
+ // Write each GYP file. |
+ for (GroupedTargetsMap::iterator i = grouped_targets.begin(); |
+ i != grouped_targets.end(); ++i) { |
+ GypTargetWriter::WriteFile(i->first, i->second, err); |
+ if (err->has_error()) |
+ return std::make_pair(0, 0); |
+ } |
+ |
+ return std::make_pair(target_count, |
+ static_cast<int>(grouped_targets.size())); |
} |
+} // namespace |
+ |
+// Suppress output on success. |
+const char kSwitchQuiet[] = "q"; |
+ |
const char kGyp[] = "gyp"; |
const char kGyp_HelpShort[] = |
- "gyp: Run GYP and then GN."; |
-const char kGyp_Help[] = |
- "gyp: Run GYP and then GN.\n" |
- "\n" |
- " Generate a hybrid GYP/GN build where some targets are generated by\n" |
- " each of the tools. As long as target names and locations match between\n" |
- " the two tools, they can depend on each other.\n" |
- "\n" |
- " When GN is run in this mode, it will not write out any targets\n" |
- " annotated with \"external = true\". Otherwise, GYP targets with the\n" |
- " same name and location will be overwritten.\n" |
- "\n" |
- " References to the GN ninja files will be inserted into the\n" |
- " GYP-generated build.ninja file.\n" |
- "\n" |
- "Option:\n" |
- " --no-gyp\n" |
- " Don't actually run GYP or modify build.ninja. This is used when\n" |
- " working on the GN build when it is known that no GYP files have\n" |
- " changed and you want it to run faster.\n"; |
- |
-// Note: partially duplicated from command_gen.cc. |
+ "gyp: Make GYP files from GN."; |
+const char kGyp_Help[] = "Doooooom.\n"; |
+ |
int RunGyp(const std::vector<std::string>& args) { |
const CommandLine* cmdline = CommandLine::ForCurrentProcess(); |
- bool no_gyp = cmdline->HasSwitch(kSwitchNoGyp); |
- |
- // Deliberately leaked to avoid expensive process teardown. |
- Setup* setup = new Setup; |
- if (!setup->DoSetup()) |
- return 1; |
- |
- setup->build_settings().SetBuildDir(SourceDir(kBuildSourceDir)); |
- setup->build_settings().set_using_external_generator(true); |
- |
- // Provide a way for buildfiles to know we're doing a GYP build. |
- /* |
- Scope::KeyValueMap variable_overrides; |
- variable_overrides["is_gyp"] = Value(NULL, true); |
- setup->build_settings().build_args().AddArgOverrides(variable_overrides); |
- */ |
- |
- base::FilePath link_deps_file = |
- setup->build_settings().GetFullPath(SourceFile(kGypDepsSourceFileName)); |
- if (!no_gyp) |
- base::DeleteFile(link_deps_file, false); |
base::TimeTicks begin_time = base::TimeTicks::Now(); |
- if (!no_gyp) { |
- if (!RunGyp(&setup->build_settings())) |
- return 1; |
- } |
- base::TimeTicks end_gyp_time = base::TimeTicks::Now(); |
- // Read in the GYP link dependencies. |
- std::string link_deps_contents; |
- if (!base::ReadFileToString(link_deps_file, &link_deps_contents)) { |
- Err(Location(), "Couldn't load link deps file.", |
- FilePathToUTF8(link_deps_file)).PrintToStdout(); |
+ // Deliberately leaked to avoid expensive process teardown. |
+ Setup* setup_debug = new Setup; |
+ if (!setup_debug->DoSetup()) |
return 1; |
- } |
- Err err; |
- if (!ParseLinkDepsFile(&setup->build_settings(), |
- link_deps_contents, |
- &setup->build_settings().external_link_deps(), &err)) { |
- err.PrintToStdout(); |
+ const char kIsDebug[] = "is_debug"; |
+ setup_debug->build_settings().build_args().AddArgOverrides( |
+ GetArgsFromGypDefines()); |
+ setup_debug->build_settings().build_args().AddArgOverride( |
+ kIsDebug, Value(NULL, true)); |
+ |
+ // Make a release build based on the debug one. We use a new directory for |
+ // the build output so that they don't stomp on each other. |
+ DependentSetup* setup_release = new DependentSetup(*setup_debug); |
+ setup_release->build_settings().build_args().AddArgOverride( |
+ kIsDebug, Value(NULL, false)); |
+ setup_release->build_settings().SetBuildDir( |
+ SourceDir(setup_release->build_settings().build_dir().value() + |
+ "gn_release.tmp/")); |
+ |
+ // Run both debug and release builds in parallel. |
+ setup_release->RunPreMessageLoop(); |
+ if (!setup_debug->Run()) |
return 1; |
- } |
- |
- if (!cmdline->HasSwitch(kSwitchQuiet)) |
- OutputString("Running GN...\n"); |
- |
- // Cause the load to also generate the ninja files for each target. We wrap |
- // the writing to maintain a counter. |
- base::subtle::Atomic32 write_counter = 0; |
- setup->build_settings().set_target_resolved_callback( |
- base::Bind(&TargetResolvedCallback, &write_counter)); |
- |
- // Do the actual load. This will also write out the target ninja files. |
- if (!setup->Run()) |
+ if (!setup_release->RunPostMessageLoop()) |
return 1; |
- // Integrate with the GYP build. |
- if (!no_gyp) { |
- base::FilePath ninja_buildfile(setup->build_settings().GetFullPath( |
- SourceFile(setup->build_settings().build_dir().value() + |
- "build.ninja"))); |
- if (!FixupBuildNinja(&setup->build_settings(), ninja_buildfile)) |
- return 1; |
+ Err err; |
+ std::pair<int, int> counts = WriteGypFiles(setup_debug->build_settings(), |
+ setup_release->build_settings(), |
+ &err); |
+ if (err.has_error()) { |
+ err.PrintToStdout(); |
+ return 1; |
} |
// Timing info. |
@@ -361,15 +317,12 @@ int RunGyp(const std::vector<std::string>& args) { |
OutputString("Done. ", DECORATION_GREEN); |
std::string stats = "Wrote " + |
- base::IntToString(static_cast<int>(write_counter)) + |
- " targets from " + |
+ base::IntToString(counts.first) + " targets to " + |
+ base::IntToString(counts.second) + " GYP files read from " + |
base::IntToString( |
- setup->scheduler().input_file_manager()->GetInputFileCount()) + |
- " files in " + |
- base::IntToString((end_time - end_gyp_time).InMilliseconds()) + "ms " + |
- "(GYP took " + |
- base::IntToString((end_gyp_time - begin_time).InMilliseconds()) + |
- "ms)\n"; |
+ setup_debug->scheduler().input_file_manager()->GetInputFileCount()) |
+ + " GN files in " + |
+ base::IntToString((end_time - begin_time).InMilliseconds()) + "ms\n"; |
OutputString(stats); |
} |