Introduction
Microsoft Visual C++ can compile code very quickly if it is setup properly. There are few basic things to look at:
- Precompiled headers
- Pragma once
- File level parallel building
- Project level parallel building
Build Statistics
Before we go into the details of each of these items, let's see how we can enable some build time statistics. Please note that all my examples and notes are related to Visual Studio 2008 Professional Edition.
Measuring the Build Time
In VC++, you can get build time by going into Tools > Options > Projects and Solutions > VC++ Project Settings > Build Timing. Set this value to true. This will print the complete build time to the output window. Enable this before you try to improve the build time, then you will be able to measure the performance correctly.
Getting the List of Files Included into Each Compilation Unit
In VC++, you can get the list of files included into each compilation unit (CPP) by enabling "Show Includes" in the project properties by going into C/C++ > Advanced > Show Includes. Set this value to true. This will print the included files with the compiler output.
Precompiled Headers
It is often desirable to avoid recompiling a set of header files, especially when they introduce many lines of code and the primary source files that #include
them are relatively small. The C++ compiler provides a mechanism for, in effect, taking a snapshot of the state of the compilation at a particular point and writing it to a disk file before completing the compilation; then, when recompiling the same source file or compiling another file with the same set of header files, it can recognize the snapshot point, verify that the corresponding precompiled header (PCH) file is reusable, and read it back in. Under the right circumstances, this can produce a dramatic improvement in compilation time; the trade-off is that PCH files can take a lot of disk space.
Enabling Precompiled Headers
The precompiled-header options are /Yc (Create Precompiled Header File) and /Yu (Use Precompiled Header File). Use /Yc to create a precompiled header. Select /Yu to use an existing precompiled header in the existing compilation. These settings can be changed by going into Project Properties > Configuration Properties > Precompiled Headers.
The idea here is to use one CPP file as the source for creating the pre compiled header and the rest of the CPP files are use the created header file. First, you need a header file that every source file in your project will include. In VC++ this is typically called as "stdafx.h". If you do not have one, create it and also the corresponding CPP file which contains a single line to include the "stdafx.h". Change the rest of the CPP files in your project to include the "stdafx.h" file. This include has to be the first include statement (as the first non-comment thing that they do). If you forget to include your precompiled header file, then you will get the following error message:
fatal error C1010: unexpected end of file while looking for precompiled header directive
Now, change the project properties to generate / use pre compiled headers. Make sure you select "All Configurations" so that your fixes will affect both debug and release builds of your project. Select the project properties, go to the C/C++ tab, precompiled headers category. Select "Use precompiled header file" and type in the name of your precompiled header file (stdafx.h). Select "stdafx.cpp" properties, go to the C/C++ tab, precompiled headers category. With "All Configurations" selected, and select "Create precompiled header file", and type in the name of your precompiled header file.
What Should be in the stdafx.h?
The precompiled header file should include the big header files which slow down your builds. Possible candidates are STL header files.
The rule of thumb is not to include any header files from your project, since if you modify those header files, the whole project will be rebuilt.
Build with Precompiled Headers
All set now. Try out the build and gather the build statistic and compare with the original.
#pragma Once
In the C and C++ programming languages, #pragma
once is a non-standard but widely supported preprocessor directive designed to cause the current source file to be included only once in a single compilation. Using #pragma once
instead of include guards will typically increase compilation speed since it is a higher-level mechanism; the compiler itself can compare filenames without having to invoke the C preprocessor to scan the header for #ifndef
and #endif
.
If the header contains only a guard, when compiling the included file (CPP) the included file has to be fully loaded to scan for #ifdef
and #endif
statements. To improve the time and to support all compilers, it is recommended to use both header guards and #pragma once
statements in the header files.
For an example, take a header file that you use / include many times form your project. Remove the pragma once
from it (if it exists) and compile the project by enabling "Show Includes" discussed previously. Check the number of times the included file gets loaded when the project gets compiled.
File Level Parallel Building
Visual Studio 2008 can take advantage of systems that have multiple processors, or multiple-core processors. A separate build process is created for each available processor. The /MP option can reduce the total time to compile the source files on the command line. The /MP option causes the compiler to create one or more copies of itself, each in a separate process. Then these copies simultaneously compile the source files. Consequently, the total time to build the source files can be significantly reduced. The /MP option can be given to the project settings in the IDE by going into project properties C/C++ > Command Line > Additional Options. The option takes an optional argument to specify the number of processors / cores. If you omit this argument, the compiler retrieves the number of effective processors on your computer from the operating system, and creates a process for each processor. This option does not work with if you have used /Yc (Create Precompiled Header File) or Show Includes. The compiler will warn you, but you can simply ignore it. Otherwise omit the /MP option for /Yc enabled source files (stdafx.cpp) and disable Show Includes option after figuring out the include file fiasco.
With this option along if you are running your compiler on a quad core system, you can gain 3 - 4 times compile time improvement.
Project Level Parallel Building
The number of projects that can build concurrently in the IDE is equal to the value of the Maximum number of parallel project builds property. For example, if you build a solution that comprises several projects while this property is set to 2
, then up to two projects will build concurrently at a time. To enable this, you need to go into Tools > Options > Projects and Solutions > Build and Run. Set the "maximum number of parallel project to build" to number of processors / cores.
This option only allows you to build non-dependent projects in parallel.
Points of Interest
By doing all of these, we were able to improve the build time of a project by 10 times. Hope this article will help you too.