Sharing precompiled headers between projects in Visual Studio

12,754

Solution 1

Yes it is possible and I can assure you, the time savings are significant. When you compile your PCH, you have to copy the .pdb and .idb files from the project that is creating the PCH file. In my case, I have a simple two file project that is creating a PCH file. The header will be your PCH header and the source will be told to create the PCH under project settings - this is similar to what you would do normally in any project. As you mentioned, you have to have the same compile settings for each configuration otherwise a discrepancy will arise and the compiler will complain.

Copying the above mentioned files every time there is a rebuild or every time the PCH is recompiled is going to be a pain, so we will automate it. To automate copying, perform a pre-build event where the above mentioned files are copied over to the appropriate directory. For example, if you are compiling Debug and Release builds of your PCH, copy the files from Debug of your PCH project over to your dependent project's Debug. So a copy command would look like this

copy PchPath\Debug*.pdb Debug\ /-Y

Note the /-Y at the end. After the first build, each subsequent build is incrementally compiled, therefore if you replace the files again, Visual Studio will complain about corrupted symbols. If they do get corrupted, you can always perform a rebuild, which will copy the files again (this time it won't skip them as they no longer exist - the cleanup deletes the files).

I hope this helps. It took me quite some time to be able to do this, but it was worth it. I have several projects that depend on one big framework, and the PCH needs to be compiled only once. All the dependent projects now compile very quickly.

EDIT: Along with several other people, I have tested this under VS2010 and VS2012 and it does appear to work properly.

Solution 2

While this is an old question I want to give a new answer which works in Visual Studio 2017 and does not involve any copying. Only disadvantage: Edit and continue doesn't work anymore.

Basically you have to create a new project for the precompiled header and have all other project depend on it. Here is what I did:

Step by step:

  1. Create a new project withnin your solution which includes the header (called pch.h from hereon) and a one line cpp file which includes pch.h. The project should create a static lib. Setup the new project to create a precompiled header. The output file needs to be accessible by all projects. for me this relative to IntDir, but for default settings it could be relative to $(SolutionDir). The pch project must only have defines all others projects have too.

    pch project settings

  2. Have all other projects depend on this new project. Otherwise the build order might be wrong.

    project references

  3. Setup all other projects to use the pch.h. See, how the output file parameters are the same as in the pch project. Additional include directories also need to point to the pch.h directory. Optionally you can force include the pch file in every cpp (or you include it manually in the first line of every cpp file).

    pch include include

    1. Setup all projects (including the pch project) to use the same compiler symbol file (the linker symbol file is not affected). Again, in my example this is OutDir but in your solution this might vary. It has to point to the same file on disk. The Debug Information Format needs to be set to C7 (see screenshot above), otherwise Visual Studio will not be able to compile projects in parallel. pdb

I hope I didn't forget anything. For my solution (130k loc, 160 projects) this lead to a compile time of ~2:30mins instead of ~3:30mins.

Solution 3

Samaursa's answer worked for me.

I also saw this link that works (look for Reginald's answer near the bottom).

This one uses copy while Reginald's uses xcopy (I prefer xcopy). Either way, thanks--this sped up my builds considerably.

Solution 4

It seems it's not possible because each source file has to be compiled against the same PDB against which the PCH was compiled. darn it.

Solution 5

This sounds like a case of "diminishing returns" to me. Suppose including the common headers directly wastes 1 second per .cpp file, and each target (DLL/EXE) has 10 .cpp files. By using a .pch per target, you save 10 seconds per target. If your whole project has 10 targets, you save 1.5 minutes on the whole build, which is good.

But by reducing it to one .pch for the whole project, you'd only save a further 9 seconds. Is it worth it? The extra effort (which may be a lot more fiddly to set up, being a non-standard configuration unsupported by VS wizards) produces only a 10th of the saving.

Share:
12,754
Assaf Lavie
Author by

Assaf Lavie

assaflavie.com

Updated on June 06, 2022

Comments

  • Assaf Lavie
    Assaf Lavie almost 2 years

    I have a solution with many Visual C++ projects, all using PCH, but some have particular compiler switches turned on for project-specific needs.

    Most of these projects share the same set of headers in their respective stdafx.h (STL, boost, etc). I'm wondering if it's possible to share PCH between projects, so that instead of compiling every PCH per-project I could maybe have one common PCH that most projects in the solution could just use.

    It seems possible to specify the location of the PCH as a shared location in the project settings, so I have a hunch this could work. I'm also assuming that all source files in all projects that use a shared PCH would have to have the same compiler settings, or else the compiler would complain about inconsistencies between the PCH and the source file being compiled.

    Has anyone tried this? Does it work?

    A related question: should such a shard PCH be overly inclusive, or would that hurt overall build time? For example, a shared PCH could include many STL headers that are widely used, but some projecst might only need <string> and <vector>. Would the time saved by using a shared PCH have to be paid back at a later point in the build process when the optimizer would have to discard all the unused stuff dragged into the project by the PCH?

    • shoosh
      shoosh about 15 years
      Why don't you just try it out and let us know? in the time it took you to write this post you could have been half way through a simple 2 project proof of concept.
    • Assaf Lavie
      Assaf Lavie about 15 years
      I don't think a 2 project POC would prove anything. The large number of project plays a part in this.
    • Scott Langham
      Scott Langham over 10 years
    • Robin
      Robin over 7 years
      According to above, this is now Supported, but there is no info on how to set it up. Anyone got it working?
  • Assaf Lavie
    Assaf Lavie about 15 years
    Think 200 projects in the solution with a pch that can take 10 seconds to compile, and then it's not so clear if the returns are so diminished.
  • Daniel Earwicker
    Daniel Earwicker about 15 years
    How long does the whole build take?
  • Trevor Robinson
    Trevor Robinson almost 14 years
    Yeah, I hit this too. :-( Error C2859: vc90.pdb is not the pdb file that was used when this precompiled header was created, recreate the precompiled header. msdn.microsoft.com/en-us/library/3bw58yy6.aspx
  • Samaursa
    Samaursa over 13 years
    It is possible, please see my answer.
  • Hertzel Guinness
    Hertzel Guinness about 13 years
    Did someone try this on vs2010?
  • Yakov Galka
    Yakov Galka almost 13 years
    +1, this one is even better because it automatically rebuilds when the stdafxes have changed.
  • paulm
    paulm over 11 years
    Yes it appears to not work, I get the error: \vc100.pdb is not the pdb file that was used when this precompiled header was created, recreate the precompiled header. Also the Microsoft.Cpp.Win32.targets had to be changed otherwise it attempts to first delete the PCH!
  • Yakov Galka
    Yakov Galka almost 11 years
    @DanielEarwicker: 40-50min for one configuration x (32,64 bit) x (Debug, Release). And it is ~400 projects already.
  • paulm
    paulm over 10 years
    This is absolutely not usable in a production environment, it breaks rebuild and has all sorts of issues
  • Jherico
    Jherico about 10 years
    This works for me for release builds, but not debug builds, where I get the same error as paulm.
  • imagiro
    imagiro about 10 years
    I just wonder if the projects using the pch still compile their own version. It seems to be the case, since the setting for stdafx.cpp still says 'Generate'. I tried simply removing stdafx.cpp, but this causes linker errors: 'LNK2011: precompiled object not linked in; image may not run'. So probably the other projects should link against the created object file for stdafx.cpp?
  • Ramkumar
    Ramkumar about 7 years
    Curious, what happens when you use Edit and Continue with this setup?
  • Nick Papagiorgio
    Nick Papagiorgio about 7 years
    You would have to switch the debug information format which would result in visual studio not being able to compile in parallel which in turn diminishes any performance advantages.
  • Ramkumar
    Ramkumar about 7 years
    Oh whoops. Missed your post of switching to /Z7. Thanks for clarifying.
  • Daniel Laügt
    Daniel Laügt about 7 years
    Works fine even in vs2010
  • spellmansamnesty
    spellmansamnesty over 5 years
    Has anyone been able to do this with CMake? My attempts have failed and since the links no longer work I can't verify that what I'm doing in CMake are translating to VS.
  • Elad Maimoni
    Elad Maimoni over 3 years
    can the precompiled header be reused in executables as well? referencing the common precompiled header in executables given me compiler warnings about mismatched compiler options.