GN: Fix Visual Studio project build command

The previous solution didn't work for building projects with
non-default toolchains.
Now it calls ninja with the dependency output of a target
instead of the project name, this seems to work in all cases.

R=brettw@chromium.org, tmoniuszko@opera.com
BUG=

Review URL: https://codereview.chromium.org/1723663006

Cr-Original-Commit-Position: refs/heads/master@{#377277}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: d8d1d8e78b428862455838efef25593c0f69a46a
diff --git a/tools/gn/visual_studio_writer.cc b/tools/gn/visual_studio_writer.cc
index 4b64f1e..a404461 100644
--- a/tools/gn/visual_studio_writer.cc
+++ b/tools/gn/visual_studio_writer.cc
@@ -179,7 +179,10 @@
 
 VisualStudioWriter::VisualStudioWriter(const BuildSettings* build_settings,
                                        Version version)
-    : build_settings_(build_settings) {
+    : build_settings_(build_settings),
+      ninja_path_output_(build_settings->build_dir(),
+                         build_settings->root_path_utf8(),
+                         EscapingMode::ESCAPE_NINJA_COMMAND) {
   const Value* value = build_settings->build_args().GetArgOverride("is_debug");
   is_debug_config_ = value == nullptr || value->boolean_value();
   config_platform_ = "Win32";
@@ -496,12 +499,14 @@
                     "$(VCTargetsPath)\\BuildCustomizations\\masm.targets"));
   project.SubElement("ImportGroup", XmlAttributes("Label", "ExtensionTargets"));
 
+  std::string ninja_target = GetNinjaTarget(target);
+
   {
     scoped_ptr<XmlElementWriter> build =
         project.SubElement("Target", XmlAttributes("Name", "Build"));
     build->SubElement(
-        "Exec",
-        XmlAttributes("Command", "call ninja.exe -C $(OutDir) $(ProjectName)"));
+        "Exec", XmlAttributes("Command",
+                              "call ninja.exe -C $(OutDir) " + ninja_target));
   }
 
   {
@@ -510,7 +515,7 @@
     clean->SubElement(
         "Exec",
         XmlAttributes("Command",
-                      "call ninja.exe -C $(OutDir) -tclean $(ProjectName)"));
+                      "call ninja.exe -C $(OutDir) -tclean " + ninja_target));
   }
 
   return true;
@@ -751,3 +756,11 @@
     parents.push_back(folder);
   }
 }
+
+std::string VisualStudioWriter::GetNinjaTarget(const Target* target) {
+  std::ostringstream ninja_target_out;
+  DCHECK(!target->dependency_output_file().value().empty());
+  ninja_path_output_.WriteFile(ninja_target_out,
+                               target->dependency_output_file());
+  return ninja_target_out.str();
+}
diff --git a/tools/gn/visual_studio_writer.h b/tools/gn/visual_studio_writer.h
index 0409220..8ca92fb 100644
--- a/tools/gn/visual_studio_writer.h
+++ b/tools/gn/visual_studio_writer.h
@@ -11,6 +11,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "tools/gn/path_output.h"
 
 namespace base {
 class FilePath;
@@ -91,6 +92,8 @@
   // and updates |root_folder_dir_|. Also sets |parent_folder| for |projects_|.
   void ResolveSolutionFolders();
 
+  std::string GetNinjaTarget(const Target* target);
+
   const BuildSettings* build_settings_;
 
   // Toolset version.
@@ -121,6 +124,9 @@
   // Semicolon-separated Windows SDK include directories.
   std::string windows_kits_include_dirs_;
 
+  // Path formatter for ninja targets.
+  PathOutput ninja_path_output_;
+
   DISALLOW_COPY_AND_ASSIGN(VisualStudioWriter);
 };