I\'ve got a bunch of legacy code that I need to write unit tests for. It uses pre-compiled headers everywhere so almost all .cpp files have a dependecy on stdafx.h which is
Precompiled headers can save a lot of time when rebuilding a project, but if a precompiled header changes, every source file depending on the header will be recompiled, whether the change affects it or not. Fortunately, precompiled headers are used to compile, not link; every source file doesn't have to use the same pre-compiled header.
pch1.h:
#include <bigHeader1.h>
#include ...
pch1.cpp:
#include "pch1.h"
source1.cpp:
#include "pch1.h"
[code]
pch2.h:
#include <bigHeader2.h>
#include ...
pch2.cpp:
#include "pch2.h"
source2.cpp
#include "pch2.h"
[code]
Select pch1.cpp, right click, Properties, Configuration Properties, C/C++, Precompiled Headers.
Precompiled Header : Create(/Yc)
Precompiled Header File: pch1.h
Precompiled Header Output File: $(intDir)pch1.pch
Select source1.cpp
Precompiled Header : Use(/Yu)
Precompiled Header File: pch1.h
Precompiled Header Output File: $(intDir)pch1.pch (I don't think this matters for /Yu)
Do the same thing for pch2.cpp and source2.cpp, except set the Header File and Header Output File to pch2.h and pch2.pch. That works for me.
Yes, there is a better way.
The problem, IMHO, with the 'wizard style' of precompiled headers is that they encourage unrequired coupling and make reusing code harder than it should be. Also, code that's been written with the 'just stick everything in stdafx.h' style is prone to be a pain to maintain as changing anything in any header file is likely to cause the whole codebase to recompile every time. This can make simple refactoring take forever as each change and recompile cycle takes far longer than it should.
A better way, again IMHO, is to use #pragma hdrstop and /Yc and /Yu. This enables you to easily set up build configurations that DO use precompiled headers and also build configurations that do not use precompiled headers. The files that use precompiled headers don't have a direct dependency on the precompiled header itself in the source file which enables them to be build with or without the precompiled header. The project file determines what source file builds the precompiled header and the #pragma hdrstop line in each source file determines which includes are taken from the precompiled header (if used) and which are taken directly from the source file... This means that when doing maintenance you would use the configuration that doesn't use precompiled headers and only the code that you need to rebuild after a header file change will rebuild. When doing full builds you can use the precompiled header configurations to speed up the compilation process. Another good thing about having the non-precompiled header build option is that it makes sure that your cpp files only include what they need and include everything that they need (something that is hard if you use the 'wizard style' of precompiled header.
I've written a bit about how this works here: http://www.lenholgate.com/blog/2004/07/fi-stlport-precompiled-headers-warning-level-4-and-pragma-hdrstop.html (ignore the stuff about /FI) and I have some example projects that build with the #pragma hdrstop and /Yc /Yu method here: http://www.lenholgate.com/blog/2008/04/practical-testing-16---fixing-a-timeout-bug.html .
Of course, getting from the 'wizard style' precompiled header usage to a more controlled style is often non-trivial...
No. pre-compiled headers relies on a single header included by all sources compiled this way. you can specify for a single source (or all) not to use pre-compiled headers at all, but that's not what you want.
In the past, Borland C++ compiler did pre-compilation without a specific header. however, if two sources files included the same headers but at different order, they were compiled separately, since, indeed, the order of header files in C++ can matter...
Thus it means that the borland pre-compiled headers did save time only if you very rigidly included sources in the same order, or had a single include file included (first) by all other files... - sounds familiar ?!?!
When you normally use precompiled headers, "stdafx.h" serves 2 purposes. It defines a set of stable, common include files. Also in each .cpp file, it serves as a marker as where the precompiled headers end.
Sounds like what you want to do is:
So now you have the minimal set of dependancies, and you still are using precompiled headers. The loss is that you are not precompiling your common set of headers only once. This would be a big hit for a full rebuild. For development mode, where you are only recompiling a few files at a time, it would be less of a hit.
Yes. The "stdafx.h/stdafx.pch" name is just convention. You can give each .cpp its own precompiled header. This would probably be easiest to achieve by a small script to edit the XML in your .vcproj. Downside: you end up with a large stack of precompiled headers, and they're not shared between TU's.
Possible, but smart? I can't say for sure.
I only use pre-compiled headers for the code that needs to include the afx___ stuff - usually just UI, which I don't unit-test. UI code handles UI and calls functions that do have unit-tests (though most don't currently due to the app being legacy).
For the bulk of the code I don't use pre-compiled headers.
G.