I'm working on a VC++ project in VS 2012 that takes about 8-10 minutes for a full compile. I know PCH can speedup compile times by upto 10x. I have currently disabled PCH in my project and I'm including header files where they are needed. How do I get started with PCH? I've looked everywhere for "how to" guides but all I got is the docs.
I'm assuming I'll have to :
Configure my project for PCH, creating a blank PCH header file
Collect headers from every .cpp file and place it into the PCH header file
Modify every file removing all header imports
Recompile and hope that nothing goes wrong ;)
How do I get started with this (specifically #1)? Have you modified a project to use PCH and what are the stumbling blocks or common problems/issues therein? Can PCH cause any problems or is it just the same compile-time/runtime behaviour as normal includes? Is there a tool to automate the process or do I have to go thru 500 .cpp files by hand and modify it to use PCH?
And last but not least, what is the compilation time speedup I can expect with PCH? Is it 2x-10x? Or would it just go like 30% faster? (which does not justify the time involved)
After configuring my project to use PCH, full-compile times were down to half, and incremental builds occurred almost instantly. PCH is a very effective way to speedup compile times, and I highly recommend it.
Althouh dsharlet mentions many important points, he skips some crucial steps that I had to eventually figure out. So here is the complete guide to configuring your project to use PCH:
Getting started with PCH in a VC++ project
Backup your src dir and any other directories that contain source code ... (you'll need this in case anything goes wrong)
Create 2 files in your project, Globals.cpp and Globals.h .. (choose any name but stick to it)
Right click Globals.cpp and open Properties, choose Configuration > All configurations
Go to C/C++ | Precompiled Header, and fill these in:
Precompiled Header : Create (/Yc)
Precompiled Header File : Globals.h
Open Globals.cpp and add this one line in, and nothing more: #include "Globals.h"
Right click your VC++ project and open Properties, choose Configuration > All configurations
Go to C/C++ | Precompiled Header, and fill these in:
Precompiled Header : Use (/Yu)
Precompiled Header File : Globals.h
Open all the .h and .cpp files in your project, and add this at the very top: #include "Globals.h". If you DONOT want to include every file manually, you can use the Force Include /FI[name].
Open Globals.h and add the following in: (its very important you have #pragma once at the top)
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <memory>
#include <string.h>
#include <limits.h>
#include <float.h>
#include <time.h>
#include <ctype.h>
#include <wchar.h>
#include <wctype.h>
#include <malloc.h>
#include <locale.h>
#include <math.h>
// Windows SDK
#define _WIN32_WINNT 0x0501 // _WIN32_WINNT_WINXP
#include <SDKDDKVer.h>
// Windows API
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
These includes are typical candidates for your PCH file
Remove the includes that you're not using
Go through your project and collect any more header files that do not change often
Using find and replace, search for each of the #include's in your PCH file, and remove them from all the .h and .cpp files in your project.
Do a full compile and ensure everything is working okay. Here are some solutions for common problems you'll encounter:
PCH file includes itself:
Your PCH file is including a header that includes the PCH header file again, creating a kind of circular dependency. Double click the error to take you to the offending file, and simply remove the line that says #include "Globals.h"
Undefined symbol X
Although all your project files can include the PCH header, the files included inside the PCH header cannot include the PCH header! (as stated above) so you'll need to add back any imports that were previously in the file. (diff the file with the backup version)
Cannot find symbol logf
Sometimes the global PCH file does not behave as expected, and breaks compiling with crazy errors that are impossible to solve. You can then turn off PCH for individual source code files.
Right click your .cpp file and open Properties, choose Configuration > All configurations
Go to C/C++ | Precompiled Header, and fill these in:
Precompiled Header : Not Using Precompiled Headers
Remove the line #include "Globals.h" in your .cpp file
Add back whatever imports the file originally had. (diff the file with the backup version)
Here's how I use PCH with decent results:
Go to the project properties, C/C++|PCH set Precompiled Header option to 'Use'. Set Precompiled Header File to something you want.
Go to the properties of a cpp file you want to be the PCH, and set the Precompiled Header option to 'Create' (it will have defaulted to 'Use' from the project property setting).
Include the pch header in all your cpp files in the project (basically, the ones that have 'Use' set for the Precompiled Header option). I suppose you could turn off 'Use' for some cpp files in the project instead of add the include for the PCH, but I've never tried that...
At this point, the project should still build and behave exactly as it used to, but there may not be any real improvement in compile time. Now, you'll need to move some of your #include "...h" to the PCH header file (and delete the includes of those files from elsewhere in the project). The includes that you should move to the PCH header should be headers that are included in many files, but change infrequently. Examples: STL headers, windows.h, core functionality headers from your project, etc.
Once PCH is set up, it should be transparent. It's basically just helping the compiler cache some intermediate compilation data. In other words, if you turned off PCH in your project, everything should still build exactly as it would have with PCH turned on (except slower!)
The speedup entirely depends on how much code is moved into the PCH (how much included code from headers is moved from arbitrary cpp files to the PCH header). I've seen multiple times improvement, but haven't benchmarked it precisely. I definitely felt like it was worth doing when I've gone through the trouble to use PCH on a big project.
Related
I have a simple VS C++ project that consists of a few headers and one source file that houses main(). I am using VS's default method of using precompiled headers with stdafx.h. So my one main.cpp has:
#include "stdafx.h"
at the top. For this configuration, everything compiles and runs fine.
However, I needed to add some C src and header files to my project that has data and function calls that I need to use. So I added these (3 .c files and 1 .h file) using the usual method: Add > Existing Item > choose file. But when I tried to compile I get
Error C101: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?
So I went back to my new .c src files and added #include "stdafx.h" to the top, but VS is throwing
E1696 Error: cannot open source file "stdafx.h"
Does VS's precompiler work with C files in a C++ project or do I need to reconfigure it somehow?
EDIT: The reason I chose to go with the default method of using precompiled headers is because although my code isn't very large, I am using large header libraries like Boost and Eigen.
I have a solution which contains several projects. My projects (but not all of them) use precompiled headers. I decided to use protobuf and I've met a problem. After generetaing *.pb.h from *.proto by protoc.exe I'm trying to include the header and get the error - precompiled header wasn't included into *.pb.h.
How I can solve this problem? I have an idea (but I don't like it at all) - after protoc generates *.pb.h I can run some script, which'll include my precompiled header into the *.pb.h. But I don't like it because some projects may not use PCH, and PCH file name can be different.
I understand that I can just remove PCH from my projects, but I don't like that idea too.
Dont add the generated myproto.pb.cc to your project. Instead, create a myproto.cpp with
#include "pch.h"
#include "myproto.pb.cc"
I resolved my problem by creating a static library called proto-objects (without PCH) and including all my *pb.h(cpp) files there. After it I link that library to every project where I need my protobuf objects. Profit!
You can disable the pre-compiled header option on a file-by-file basis.
Given that the pch option is intended to speed up compilation, you can turn it off for the whole project, and no further changes should be necessary.
The choice of name of the header file, and the pch file are also selectable per file in the project
Update
The idea behind Microsoft's Pre-compilation PCH system is to
Speed up compilation
Make it easy to use
The header file system in C/C++ is problematic, as it is really a textual replacement.
That means that
#include "localdefs.h"
#include <windows.h>
#include "project.h"
#include "support.h"
Is in no way similar to
#include <windows.h>
#include "project.h"
#include "support.h"
That is because localdefs.h can redefine the behavior of all of the other includes.
Further to this the costs of walking through the complexities of the windows.h header files, is time consuming.
The PCH system tries to solve this by the observation that most projects have a fixed set of include files which are included by most/all of the CPP files.
Defining this set in stdafx.h allows the textual result of that parsing to be pasted in the cpp file and save a lot of work.
If most of the includes in the project are different, then there is no need to use it.
So if you are including the same qt header files in lots of places - add them to a pre-compiled header file. The more of the common includes added to this file, the better the compile speed improvements will be.
Any non-standard cpp file can be excluded by being specifically disabled - examples are "generated files". Where the template generator does not understand the MSVC system.
If all the files are different, then only limited performance benefit will be gained - as each compile would probably also include a pch recompile.
I got a comprehension issue about precompiled headers, and the usage of the #include directive.
So I got my "stdafx.h" here and include there for example vector, iostream and string. The associated "stdafx.cpp" only includes the "stdafx.h", that's clear.
So if I design my own header file that uses for example "code" that's in vector or iostream, I have to include the header file because the compiler doesn't know the declarations at that time. So why are some posts here (include stdafx.h in header or source file?) saying, it's not good to include the "stdafx.h" in other header files even if this file includes the needed declarations of e.g. vectors? So basically it wouldn't matter to include directly a vector or the precompiled header file, both do the same thing.
I know of course, that I don't have to include a header file in another header file if the associated source file includes the needed header file, because the declarations are known at that time. Well, that only works if the header file is included somewhere.
So my question is: Should I avoid including the precompiled header file in any source file and why? And I am a bit confused, because I'm reading contradictory expressions on the web that I shouldn't include anything in header files anyway, or is it O.K. to include in header files?
So what's right now?
This will be a bit of a blanket statement with intent. The typical setup for PCH in a Visual Studio project follows this general design, and is worth reviewing. That said:
Design your header files as if there is no PCH master-header.
Never build include-order dependencies in your headers that you expect the including source files will fulfill prior to your headers.
The PCH master-header notwithstanding (I'll get to that in a moment), always include your custom headers before standard headers in your source files. This makes your custom header is more likely to be properly defined and not reliant on the including source file's previous inclusion of some standard header file.
Always set up appropriate include guards or pragmas to avoid multiple inclusion. They're critical for this to work correctly.
The PCH master-header is not to be included in your header files. When designing your headers, do so with the intent that everything needed (and only that which is needed) by the header to compile is included. If an including source file needs additional includes for its implementation, it can pull them in as needed after your header.
The following is an example of how I would setup a project that uses multiple standard headers in both the .h and .cpp files.
myobject.h
#ifndef MYAPP_MYOBJECT_H
#define MYAPP_MYOBJECT_H
// we're using std::map and std::string here, so..
#include <map>
#include <string>
class MyObject
{
// some code
private:
std::map<std::string, unsigned int> mymap;
};
#endif
Note the above header should compile in whatever .cpp it is included, with or without PCH being used. On to the source file...
myobject.cpp
// apart from myobject.h, we also need some other standard stuff...
#include "myobject.h"
#include <iostream>
#include <fstream>
#include <algorithm>
#include <numeric>
// code, etc...
Note myobject.h does not expect you to include something it relies on. It isn't using <iostream> or <algorithm>, etc. in the header; we're using it here.
That is a typical setup with no PCH. Now we add the PCH master
Adding the PCH Master Header
So how do we set up the PCH master-header to turbo-charge this thing? For the sake of this answer, I'm only dealing with pulling in standard headers and 3rd-party library headers that will not undergo change with the project development. You're not going to be editing <map> or <iostream> (and if you are, get your head examined). Anyway...
See this answer for how a PCH is typically configured in Visual Studio. It shows how one file (usually stdafx.cpp) is responsible for generating the PCH, the rest of your source files then use said-PCH by including stdafx.h.
Decide what goes in the PCH. As a general rule, that is how your PCH should be configured. Put non-volatile stuff in there, and leave the rest for the regular source includes. We're using a number of system headers, and those are going to be our choices for our PCH master.
Ensure each source file participating in the PCH turbo-mode is including the PCH master-header first, as described in the linked answer from (1).
So, first, the PCH master header:
stdafx.h
#ifndef MYAPP_STDAFX_H
#define MYAPP_STDAFX_H
// MS has other stuff here. keep what is needed
#include <algorithm>
#include <numeric>
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#endif
Finally, the source files configured to use this then do this. The minimal change needed is:
UPDATED: myobject.cpp
#include "stdafx.h" // <=== only addition
#include "myobject.h"
#include <iostream>
#include <fstream>
#include <algorithm>
#include <numeric>
// code, etc...
Note I said minimal. In reality, none of those standard headers need appear in the .cpp anymore, as the PCH master is pulling them in. In other words, you can do this:
UPDATED: myobject.cpp
#include "stdafx.h"
#include "myobject.h"
// code, etc...
Whether you choose to or not is up to you. I prefer to keep them. Yes, it can lengthen the preprocessor phase for the source file as it pulls in the headers, runs into the include-guards, and throws everything away until the final #endif. If your platform supports #pragma once (and VS does) that becomes a near no-op.
But make no mistake: The most important part of all of this is the header myobject.h was not changed at all, and does not include, or know about, the PCH master header. It shouldn't have to, and should not be built so it has to.
Precompiled headers are a method to shorten the build time. The idea is that the compiler could "precompile" declarations and definitions in the header and not have to parse them again.
With the speed of todays computers, the precompilation is only significant for huge projects. These are projects with a minimum of over 50k lines of code. The definition of "signification" is usually tens of minutes to build.
There are many issues surrounding Microsoft's stdafx.h. In my experience, the effort and time spent with discovering and resolving the issues, makes this feature more of a hassle for smaller project sizes. I have my build set up so most of the time, I am compiling only a few files; the files that don't change are not compiled. Thus, I don't see any huge impact or benefit to the precompiled header.
When using the precompiled header feature, every .cpp file must begin by including the stdafx.h header. If it does not, a compiler error results. So there is no point in putting the include in some header file. That header file cannot be included unless the stdafx.h has already been included first.
I encountered this problem, Usually you all are going to ask me the why, so I'll explain first so you can just answer me, I'm working on a source with at least 500.000lines but now one of my source (.cpp) files I just created must NOT add the precompiled header which is "StdAfx.h" in this case, I must NOT edit the project precompiled header settings, obviously if I try to compile my the project without including stdafx in the new file i'll be smashed with a C1010, what I've tried is this
StdAfx.h:
#ifndef __ABC123
//do all your includes
#endif
MyFile.cpp:
#define __ABC123
#include "StdAfx.h"
#undef __ABC123
Althought, this doesn't works, stdafx.h is still including the files. Why I can't have stdafx.h includes on this .cpp file is because some includes on stdafx have tons of conflicts with the includes of this cpp. I can't modify the stdafx includes because thousands of other files use it, how to deal with this?
Impossible. You have painted yourself in to a corner here. Let me 'splain.
PCHs are intended to be used across an entire project. Every translation unit is expected to include the PCH.
This behavior can be overridden, but only via the project settings for the translation unit in question. You have already said that you must not edit the project settings, hence eliminating your only avenue of escape.
If you really need this and there's no way out, I would consider taking such drastic steps as moving the non-PCH code in to its own project.
I've inherited some code that did something like this,
Header: HeaderFile.h
#ifndef HEADERFILE_H
#define HEADERFILE_H
#ifndef HEADERFILE_PCH_H
#include<LibStuff>
#include<LibStuff2>
#include<LibStuff3>
#include<LibStuff4>
#include<LibStuff5>
#endif
#include "FilesInProject"
Class A
{
//Code
};
#endif
Cpp: HeaderFile.cpp
#include "HeaderFile_pch.h" //(1)
#include "HeaderFile.h"
//More code
I understand what a precompiled header is for and what the code is doing here (sort of). When I copy these files into my project, this is so I can update deprecated code but not effect the original project, VS2010 chocks on line (1). VS2010 Saying it can't find that file.
I've gone between the two projects and I can't find any differences in settings.
What am I missing and why is it okay to imbed PCH's in headers like this instead of actually moving them to a file called HeaderFile_pch.h. Is this some kind of macro hack?
For starters, there is no such file as Headerfile_pch.h either in the samples you provided above nor likely on your local fs.
Visual C++ allows you to define several ways of setting up precompiled header files. The most common is to enable it for ALL source files at the project configuration level, Under Configuration Properties/C++/Precompiled Headers, setting "Precompiled Header", select "Use". The same location, setting "Precompiled Header File", is usually "stdafx.h" but can be anything you choose. All files will get this setting (thus the configuration at the project level) EXCEPT....
One file is responsible for generating the PCH file. That file is typically the stdafx.cpp file in your project, but again, it can be whatever single source you desire. Most just setup a dummy cpp file that has one thing in it: #include "myheader.h" (duh).. Configuring Precompiled Headers for THAT ONE FILE, switch from "Use" to "Create". This ensures that if the prime-header for PCH gets out of synch that source file is recompiled first to regenerate the PCH data file before the others are kicked off.
The one attribute of this that is absolutely mandatory: that include header (myheader.h or whatever you're calling it) must be the first include in any source file you're compiling that is participating in using pch including (hopefully obviously) the file you specified as the "generator" (the one marked as "Create" in the prior paragraph).
Lastly, you can disable pch on a file-by-file basis if this is a problem due to unusual conditions in your build environment (i.e. 3rd party headers that do stupid things).
There are other ways of configuring PCH setting in Visual Studio, but this is by far the most common.