win ninja: Speculative fix for pdb locking errors

There's longstanding occasional errors where the compiler complains that
the pdb is locked. This isn't really a condition that should be exposed
to the build system, and no one has been able to come up with a reliable
repro. Retrying causes the build to succeed.

In chromium, two targets that often fail this way are 'net' and
'libphonenumber_without_metadata'. These targets are distinctive in that
they build early in the build, contain at least one .c file, and use
pch for their .cc files.

The locking error seems to manifest with the compile step for the obj
associated with creating the .pdb, so the hypothesis is that the .c
compilation is colliding with the creation of the pdb that the
precompile does. This race should be handled by mspdbsrv, but for
appears to be buggy for whatever reason. (This bug has been filed on
connect.microsoft.com, but without a repro it's not very likely that
action will be taken.)

In order to avoid this, have the .c and .cc files use separate .pdb
files. This is otherwise unnecessary, but shouldn't cause any material
drawback either.

R=thakis@chromium.org
BUG=chromium:142362

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

git-svn-id: http://gyp.googlecode.com/svn/trunk@1800 78cadc50-ecff-11dd-a971-7dbc132099af
diff --git a/pylib/gyp/generator/ninja.py b/pylib/gyp/generator/ninja.py
index 1d21d4d..f799fdf 100644
--- a/pylib/gyp/generator/ninja.py
+++ b/pylib/gyp/generator/ninja.py
@@ -814,15 +814,18 @@
       cflags_c = self.msvs_settings.GetCflagsC(config_name)
       cflags_cc = self.msvs_settings.GetCflagsCC(config_name)
       extra_defines = self.msvs_settings.GetComputedDefines(config_name)
-      pdbpath = self.msvs_settings.GetCompilerPdbName(
+      # See comment at cc_command for why there's two .pdb files.
+      pdbpath_c = pdbpath_cc = self.msvs_settings.GetCompilerPdbName(
           config_name, self.ExpandSpecial)
-      if not pdbpath:
+      if not pdbpath_c:
         obj = 'obj'
         if self.toolset != 'target':
           obj += '.' + self.toolset
-        pdbpath = os.path.normpath(os.path.join(obj, self.base_dir,
-                                                self.name + '.pdb'))
-      self.WriteVariableList(ninja_file, 'pdbname', [pdbpath])
+        pdbpath = os.path.normpath(os.path.join(obj, self.base_dir, self.name))
+        pdbpath_c = pdbpath + '.c.pdb'
+        pdbpath_cc = pdbpath + '.cc.pdb'
+      self.WriteVariableList(ninja_file, 'pdbname_c', [pdbpath_c])
+      self.WriteVariableList(ninja_file, 'pdbname_cc', [pdbpath_cc])
       self.WriteVariableList(ninja_file, 'pchprefix', [self.name])
     else:
       cflags = config.get('cflags', [])
@@ -1797,14 +1800,20 @@
       depfile='$out.d',
       deps=deps)
   else:
+    # TODO(scottmg) Separate pdb names is a test to see if it works around
+    # http://crbug.com/142362. It seems there's a race between the creation of
+    # the .pdb by the precompiled header step for .cc and the compilation of
+    # .c files. This should be handled by mspdbsrv, but rarely errors out with
+    #   c1xx : fatal error C1033: cannot open program database
+    # By making the rules target separate pdb files this might be avoided.
     cc_command = ('ninja -t msvc -e $arch ' +
                   '-- '
                   '$cc /nologo /showIncludes /FC '
-                  '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
+                  '@$out.rsp /c $in /Fo$out /Fd$pdbname_c ')
     cxx_command = ('ninja -t msvc -e $arch ' +
                    '-- '
                    '$cxx /nologo /showIncludes /FC '
-                   '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
+                   '@$out.rsp /c $in /Fo$out /Fd$pdbname_cc ')
     master_ninja.rule(
       'cc',
       description='CC $out',
diff --git a/test/win/gyptest-cl-pdbname.py b/test/win/gyptest-cl-pdbname.py
index f7fd332..f09ac23 100644
--- a/test/win/gyptest-cl-pdbname.py
+++ b/test/win/gyptest-cl-pdbname.py
@@ -21,7 +21,7 @@
 
   # Confirm that the default behaviour is to name the .pdb per-target (rather
   # than per .cc file).
-  test.built_file_must_exist('obj/test_pdbname.pdb', chdir=CHDIR)
+  test.built_file_must_exist('obj/test_pdbname.cc.pdb', chdir=CHDIR)
 
   # Confirm that there should be a .pdb alongside the executable.
   test.built_file_must_exist('test_pdbname.exe', chdir=CHDIR)