title: Combining PCH, PDB, and Zi leads to puzzling C2859 compile error with VS2017
body: <p>I have a project that doesn't currently use precompiled headers, but I'd like to make it do so, as I've demonstrated that it leads to real compilation speed improvements in the project.</p>
  
  <p>I'd also like to use <code>/Zi</code>, so I can capitalize on the parallel build benefits associated with <code>/Zf</code>, which is implied by <code>/Zi</code>.</p>
  
  <p>I'm using the VS2017 C++ compiler, but I'm using a build system that is not Visual Studio, so answers relating to configuring VS aren't helpful. </p>
  
  <p>What I'm finding is that I can set up the build to use precompiled headers just fine, or I can set it up to use <code>/Zi</code> just fine, but I can't seem to form a proper series of invocations to do both. When I try to do what I think is correct, I end up with error <code>C2958</code> stopping the build, and I don't see what I'm doing wrong.</p>
  
  <p>I've built a toy project to demonstrate what I'm seeing. The <code>pch.hpp</code> header looks like this:</p>
  
  <pre><code>#pragma once
  #include &lt;vector&gt;
  </code></pre>
  
  <p>And we make a short mainline in <code>main.cpp</code>:</p>
  
  <pre><code>int main() {
      std::vector&lt;int&gt; xs = { 1, 2, 3 };
      return xs.size();
  }
  </code></pre>
  
  <p>Note that this is the complete file contents for <code>main.cpp</code>: I haven't omitted anything. I am intentionally <em>not</em> including <code>pch.hpp</code> here, because we are going to force inject it with <code>/Fi</code> later. The real project doesn't have include lines for a precompiled header in all the right places, and there would be thousands of files to update to do so. Note that the approach using <code>/Fi</code> does appear to work in the command lines below, and has the advantage that a forceincludes based mechanism can work with GCC style precompiled headers as well.</p>
  
  <p>If we build things without <code>/Zi</code>, everything goes fine:</p>
  
  <pre><code>cl /Fobuild\pch.obj /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /c pch.hpp /Yc /Fpbuild\pch.pch
  pch.hpp
  
  cl /Fobuild\main.obj /c main.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Yupch.hpp /Fpbuild/pch.pch
  main.cpp
  </code></pre>
  
  <p>We find the files we would expect to find under the build directory:</p>
  
  <pre><code>main.obj  pch.obj  pch.pch
  </code></pre>
  
  <p>However, if we try to use <code>/Fi</code> and <code>/Fd</code> to generate a per-file <code>.pdb</code> and control its name, it doesn't work at all:</p>
  
  <p>We can compile the precompiled header that way OK:</p>
  
  <pre><code>cl /Fobuild\pch.obj /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /c pch.hpp /Yc /Fpbuild\pch.pch /Zi /Fdbuild\pch.pch.pdb
  </code></pre>
  
  <p>And things look OK in the <code>build</code> directory so far:</p>
  
  <pre><code>pch.obj  pch.pch  pch.pch.pdb
  </code></pre>
  
  <p>But when we try to build the object file for main, it all falls apart:</p>
  
  <pre><code>cl /Fobuild\main.obj /c main.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Yupch.hpp /Fpbuild/pch.pch /Zi /Fdbuild\main.obj.pdb
  main.cpp
  main.cpp: error C2859: Z:\data\acm\src\example\build\main.obj.pdb is not the pdb file that was used when this precompiled header was created, recreate the precompiled header.
  </code></pre>
  
  <p>This is a very puzzling error, because the error message suggests that <code>main.obj.pdb</code> is being treated as an <em>input</em> somehow, but in fact it is intended to be the name of the <code>.pdb</code> file generated as <em>output</em>, per the value of the <code>/Fd</code> flag for the build of <code>main.obj</code>.</p>
  
  <p>Googling hasn't resulted in much useful guidance, with a lot of hints about reconfiguring VS settings, which isn't really useful in the case of a build driven by something else.</p>
  
  <p>I've also verified that my trickery with the <code>/Fi</code> of <code>pch.hpp</code> isn't the issue. If I update <code>main.cpp</code> to <code>#include pch.hpp</code> and remove the <code>/Fipch.hpp</code> from the compile line for <code>main.obj</code>, the same <code>C2859</code> error still occurs.</p>
  
  <p>I realize there are a lot of flags to get right when using precompiled headers, among them the <code>/Yc</code> and <code>/Yu</code> and <code>/Fp</code> flags, but I think I've got those handled correctly.</p>
  
  <p>Does anyone see where I've got things wrong?</p>
  
  <p><strong>Edit 1 - Demonstrating that /Fd can name different PDB files</strong> </p>
  
  <p>In response to the comment below, it doesn't actually appear to be the case that all targets must share the <code>/Fd</code> argument. Here is an example without the use of precompiled headers that demonstrates that:</p>
  
  <p>Here, I've needed to add <code>common.cpp</code> and create a <code>main1.cpp</code> and <code>main2.cpp</code> which both link it:</p>
  
  <p>The <code>common.hpp</code> header looks like:</p>
  
  <pre><code>#pragma once
  
  int common(int arg);
  </code></pre>
  
  <p>With a trivial implementation in <code>common.cpp</code>:</p>
  
  <pre><code>#include "common.hpp"
  
  int common(int arg) {
      return arg + 42;
  }
  </code></pre>
  
  <p>Then introduce two different mainlines:</p>
  
  <p><code>main1.cpp</code>:</p>
  
  <pre><code>#include "common.hpp"
  
  int main() {
      std::vector&lt;int&gt; xs = { 1, 2, 3 };
      return common(xs.size());
  }
  </code></pre>
  
  <p>And <code>main2.cpp</code>:</p>
  
  <pre><code>#include "common.hpp"
  
  int main() {
      std::vector&lt;int&gt; xs = { 1, 2, 3, 4};
      return common(xs.size());
  }
  </code></pre>
  
  <p>Then compile all three object files. Note that we still have the <code>/Fipch.hpp</code> here to make the includes work right, but we aren't using any of the actual PCH machinery:</p>
  
  <pre><code>cl /Fobuild\common.obj /c common.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Zi /Fdbuild\common.obj.pdb
  
  cl /Fobuild\main1.obj /c main1.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Zi /Fdbuild\main1.obj.pdb
  
  cl /Fobuild\main2.obj /c main2.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Zi /Fdbuild\main2.obj.pdb
  </code></pre>
  
  <p>And we find what we would expect in the <code>build</code> directory:</p>
  
  <pre><code>common.obj  common.obj.pdb  main1.obj  main1.obj.pdb  main2.obj  main2.obj.pdb
  </code></pre>
  
  <p>Then we can go ahead and link:</p>
  
  <pre><code>link /nologo /DEBUG /INCREMENTAL:NO /LARGEADDRESSAWARE /OPT:REF /OUT:build\main1.exe /PDB:build\main1.pdb build\common.obj build\main1.obj
  
  link /nologo /DEBUG /INCREMENTAL:NO /LARGEADDRESSAWARE /OPT:REF /OUT:build\main2.exe /PDB:build\main2.pdb build\common.obj build\main2.obj
  </code></pre>
  
  <p>And we find that we get both executables and PDB files for those executables in the <code>build</code> directory:</p>
  
  <pre><code>common.obj      main1.exe  main1.obj.pdb  main2.exe  main2.obj.pdb
  common.obj.pdb  main1.obj  main1.pdb      main2.obj  main2.pdb
  </code></pre>