Compilation speed improvements include guards vs. precompiled headers - c++

I want to reduce compile time on a large project. Our primary compiler is Visual Studio 2010 but some of the code gets compiled in gcc. We are currently planning to ensure that all our .h files have both include guards as well as #pragma once, this will allow both Visual Studio and gcc to improve compile speed. Previously we had put more headers in the stdafx but we saw disadvantages that if one of those headers was changed, and you compiled a cpp without recompiling the precompiled header that the changes didn't take effect. This often caused us confusion. The current plan is to use precompiled headers for all stable headers or headers out of our control (they won't change) and for everything else use the include guards and #pragma once to help on compilation speed. Is there a reason why this path is poorly planned? Is there a benefit for compilation speed of include guards/#pragma once vs precompiled header or vise-versa that I am missing?

The approach that you are taking is sound, but if changes in one of the headers did not trigger recompilation of the precompiled headers you should check the dependencies in the project.
There are other things that can help in reducing compilation times, like avoiding the includes altogether. That is, use forward declarations in the headers and only include in the cpp files. That will reduce the compile time dependencies and speed up compilation.
I am not a fan of precompiled headers, so I usually just ensure that I include everything that needs including and don't include anything that doesn't.

Related

Include guards in system headers and effect on compile speed

I'm currently speeding up compilation of a large C++ project (there is some C code too). Initially I'm
removing unnecessary system includes; and
introducing precompiled headers for common system includes such as stddef.h or vector. But not for includes like stdio.h or iostream which shouldn't be commonly used.
I'd thought that system headers would have include guards and thus would be covered by gcc's multiple include optimization. However it seems that not all headers follow this guideline. For example stdlib.h has #ifndef STDLIB_H at the start, and stddef.h follows the same pattern. But assert.h doesn't have a standard include guard, and nor does cstddef or cstdlib.
I've been using the -H option in gcc to track and subsequently analyse include dependencies in this project. What I've observed is that for a small sub-project with only 6 files, stdlib.h and stddef.h, which follow the include guards pattern, show up 6 times in the output, whereas the files that don't can show up 10s or 100s of times. I'm a little concerned that as some of these files may be on a remote network drive, compilation may be slower.
When I initially got precompiled headers working in the project, only including C++ headers such as vector, and headers from some internal libraries, I was a little surprised to only get a 20% performance increase. When I've done similar in Visual C++ I've seen greater increases. (Possibly related GCC build time doesn't benefit much from precompiled headers.)
I'm relatively new to gcc, so I may have missed something. My questions are:
Why do some headers have standard include guards, and some not?
Should I be concerned about the effect on compilation speed?
If so, how to address? I wouldn't mind adding assert to the precompiled headers, but I wouldn't want to add cstdlib, for example.

stdafx.h cross platform without issues?

Hey i've been following learncpp.com tuts for the last couple days, they say to comment out "#include "stdafx.h" from .cpp files for Code::Blocks.
Is that a must, to remove the include line? What happens if you had hundreds of files and changed from Visual Studio on Win7 to Code::Blocks on Linux or hand it off to someone else with a mac?
stdafx.h is the idiomatic name used for precompiled headers in the Visual Studio ecosystem. In a nutshell, it's a regular header, but the contents of this file will be compiled once and reused for all cpp files in the project.
That is useful since in most projects, a large number of headers (standard library, system header, shared project-wide definitions) are used by virtually all translation units (cpps), so using PCH is a huge performance benefit during compilation
(Actually, PCH is a hack to workaround C++' inefficient compilation and linkage model and it's a shame that we need to maintain it by hand … oups, blasphemy.)
But this also means that - as long as the contents of your stdafx.h are gcc-compatible - compilation with CodeBlocks should still work, but without the immediate performance benefit.
The stdafx.h generated by VS' app wizards doesn't work out of the box on other platforms - it typically includes Windows.h. So to make it work, guard the Windows-specific definitions with appropriate #ifdef/#endif pairs and vice versa for Linux or Mac-specific stuff.
No, that tutorial advice does not make any sense. stdafx.h does not break anything at all. The system of pre-compiled headers in Visual Studio compiler is intentionally designed that way.
If your compiler supports pre-compiled headers (and follows the same pre-compilation approach as Visual Studio), it can use stdafx.h for pre-compiling.
If your compiler does not support pre-compiled headers (or used a different pre-compilation approach), then stdafx.h is interpreted as an ordinary header file, no different from any other header file and processed the same way as any other header file.
It is possible that what is meant by that tutorial is that stdafx.h often includes some Windows-specific headers, not present on other platform. While it is possible, it really has nothing to do with stdafx.h itself at all. Obviously, if you are compiling your program on some other platform you should not attempt to include any Windows headers, regardless of how you are doing it: through stdafx.h or somewhere else.
As far as I'm aware stdafx.h is a Windows-only file (for precompiled headers): Your code will just fail to compile if you don't comment it out.
If you are not actually using a precompiled header (PCH), I advise going into Visual Studio's Options/Preferences->Precompiled Header and turning them off. If you try to remove them and still use Visual Studio, you will get a ton of errors.
The only thing to actually do is to include the path containing the stdafx.h (or precompiled header) in the default include path list. This is needed because the MS compiler actually replaces the #include "stdafx.h" with the precompiled data without really looking for the header.
Other compilers will usually want to pull in the data. But it should rather not be commented out. Usually you'll be able to tune your compiler to also make use of the precompiled header features to boost up compilation. With gcc that would be done with the -pch option. With Code Blocks I could find this wiki. Precompiled headers are not evil, on the contrary they will save you precious time if understood and used adequately.

Precompiled headers: do's and don'ts?

I know precompiled headers are used for speeding up compilations, but are there any do's and don'ts to what files I should include in them? For example, I have a project that uses a lot of boost libs so I just include the boost header files in stdafx.h (I'm using VS2008). Should I include every standard header file in them, too? Will this increase the size of my executeable even if I, for example, include <vector> but never use std::vector? Is it a bad idea to include my own project's header files in stdafx.h?
Generally speaking, every header file that you use across the application and that doesn't change often should go into the precompiled header file. This will speed up compilation because the precompiled header file gets compiled only once.
If you add a header file which changes often, you'll miss the point of the precompiled header file, because this often-changing header file will cause your whole project to recompile, possibly unnecessarily.
Specifically, defines a template class, so if you won't use std::vector, the overhead will not be big. However, I would advise against adding header files - however standard and generic - if you don't really need them. There IS some overhead to the compilation time, the binary size, and it could cause conflicts later in the project, so why add something if you don't really need it?
Pre-compiled headers don't affect the size of your executable, only the compilation speed. Since they are pre-compiled, they don't have to be re-compiled all the time. Windows.h is the primary beneficiary of this feature.
It's a good idea to include the c++ standard header-files and the boost library headers and any other headers from third party libraries that you frequently use. This will not affect the size of your executable.
However, you should not include headers from your own project, since the whole project needs to be rebuild whenever you make changes in these headers.

Pre-Compiled Header Design Question

I have code that uses a pre-compiled header. (previously done by someone else)
In it, they are including several .h files.
If I have classes that use common .h files that are not currently in the existing pre-compiled header, would tossing them in there be of any real benefit? Maybe compilation speed, but I was thinking it would clean up the classes/headers a bit too?
What are do's and don't with pre-compiled headers?
DO NOT rely on headers being included by your precompiled header for "code cleanup" by removing those headers from your other source files. This creates a nightmare if you ever want to stop using PCH. You always want your dependencies to be explicit in every source file. Just include them in both places -- there is no harm in it (assuming you have appropriate include guards in place).
A header file that is included by multiple source files is a good candidate for inclusion in the PCH (particularly if it is lengthy). I find that I don't take the advice too seriously to only put headers that rarely change into the PCH. But, this depends on your overall project structure. If you frequently do full builds, definitely avoid this advice. If you want to minimize the work in incremental rebuilds, then it's a consideration. In my experience, rebuilding the PCH is relatively fast, and the cost of this is far outweighed by the overall speedup of compilation in general (in most cases). I'm not sure if all PCH systems are smart enough to figure out that every source file does not need to be rebuilt when a header included in the PCH changes (VC++ is), but explictly #includeing everything you need in every translation unit will surely facilitate this (another reason you should not rely on what is included by your PCH)
If your compiler supports an option to show the #include tree for each file during compilation, this can be a great help to identify headers that should be included in the PCH (the ones that show up the most). I recently went through this on a project I'm working on (which was already using PCH, but not optimally) and sped up the build of 750K lines of C++ from roughly 1.5 hours to 15 minutes.
Put non-changing system includes into the precompiled header. That will speed up compilation. Don't put any of your own header files that you might change into the precompiled header, because each time you change them you will have to rebuild the entire precompiled header.
It is a trade-off: system/library headers definitely go in the PCH, for ones in your project it depends.
Our project has a large amount of generated code that is changed much less frequently that other parts of the project. These headers go in the PCH because they take a lot of time to process in each individual file. If you change them it is expensive, but you have to weigh that cost against the more frequent smaller savings of having them in the file.

Are there cross-platform precompiled header frameworks/methods in C++?

I'm wondering what others have experienced implementing cross-platform (linux and windows) precompiled headers in C++. I'm thinking of what Visual Studio lets you do with stdafx.h files that can drastically improve compile times for large amounts of C++ code by precompiling the common headers used across the board (std/boost/etc headers). Is there a way to make this happen cross platform with some kind of framework or something?
What kind of experience have you had trying to do this?
Edit
I don't really mean sharing the actual resulting pch, I'm more interested in frameworks that can generate pch and whatever the equivelant would be for, say, gcc, when compiled on that specific platform.
gcc will automatically precompile headers if you pass a header file instead of an implementation file. Simply add the -x switch if it tries to produce object code. GCC will always look for the .gch file before the header, so it's simple enough to use. This page has more info. Add it to your Makefile to automate the process.
The visual studio precompiled headers are based on a header file including all that should be precompiled, typically commonly included rarely changed header files such as standard library stuff. It's connected to a stdafx.cpp which is set to "generate precompiled header" in the settings, it only includes stdafx.h.
Visual studio then forces all files to include stdafx.h as its first preprocessor definition to avoid problems with headers included before it or changed #define macros that affects the parsing of stdafx.h.
I think the easiest way of mapping this behaviour to g++ is to make it precompile only stdafx.h and include other headers normally. It will be similar to what you do in visual c++. You can also rename stdafx to something less stupid like "precompiled_.h or something. It's easy to setup visual studio to use this file instead.
I have implemented this kind of system with using make files for g++ and it gave some performance, but I didn't manage to get the same kind of performance boost as I get from precompiled headers in visual studio. This was some time ago and g++ might have improved since then. I've managed to get CMake to generate visual studio projects with precompiled headers, I haven't tried it for their Makefile generation yet but it should be no problem.
Visual Studio has some other tricks to improve compilation speed. One is compiling many cpp-files with the same settings in one batch. This could be done manually using what's usually called a unity build system where you include multiple cpp-files into one file and build it in one go, saving you header parsing and disk io.
If you mean porting the precompiled header database (.pch or whatever) between platforms, then this is not possible as the headers will have different contents on the different platforms.