42

How do YOU reduce compile time, and linking time for VC++ projects (native C++)?

Please specify if each suggestion applies to debug, release, or both.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
  • 4
    I wish this was two question, one for linking and one for compiling (he said while waiting for a link to complete) – David Norman Dec 12 '08 at 21:57
  • 1
    Probably some answers though will apply equally to both – Brian R. Bondy Dec 12 '08 at 22:04
  • you can read my post in this thread. [here](http://stackoverflow.com/questions/143808/how-to-improve-link-performance-for-a-large-c-application-in-vs2005/9733242#9733242) – Kaleidos Mar 16 '12 at 07:11

12 Answers12

48

It may sound obvious to you, but we try to use forward declarations as much as possible, even if it requires to write out long namespace names the type(s) is/are in:

// Forward declaration stuff
namespace plotter { namespace logic { class Plotter; } }

// Real stuff
namespace plotter {
    namespace samples {
        class Window {
            logic::Plotter * mPlotter;
            // ...
        };
    }
}

It greatly reduces the time for compiling also on others compilers. Indeed it applies to all configurations :)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • You beat me to it =). I try to minimize as much as possible the headers which include other headers by using forward references wherever possible. – Adam Rosenfield Dec 12 '08 at 21:55
  • 1
    The corollary is to also try to move includes from header files to implementation files when possible. – Boojum Dec 12 '08 at 23:01
  • @Boojum: yeah this speeds things up at the cost of maintainability & readability. I'd go with forward declaration headers instead. – oz10 Dec 13 '08 at 00:32
  • ceretullis, yeah i think that is what he meant. place forward declarations into the header file, and then include header files needed into the implementation file. – Johannes Schaub - litb Dec 13 '08 at 00:54
  • @ceretullis: I don't get your point there. If you need some header due to some implementation detail and whatever is defined there (class/funcions) don't take part of your interface you should move that header to the implementation file. Else you will increase coupling and dependencies. – David Rodríguez - dribeas Dec 13 '08 at 00:55
  • 1
    or do you mean to put forward declarations itself into separate headers like the standard header? i'm not sure about that, would only make sense to put a limited set of forward declarations then imho. – Johannes Schaub - litb Dec 13 '08 at 00:57
  • 2
    Like . I use one such file per lib (typically the same as one per 'top-level' namespace) and find it costs nothing to have forward declarations that are not needed. This then makes it trivial for the next developer to include one or two forward declaration files and get everything they need. – Zero Nov 28 '12 at 04:51
  • Forward-declaring types in your header file is brittle - if the library provider changes anything at all about the type (even a compatible change), you'll get errors. Prefer to include the library's forwarding header, e.g. iosfwd – JBRWilkinson Jan 23 '17 at 11:14
21

Use the Handle/Body pattern (also sometimes known as "pimpl", "adapter", "decorator", "bridge" or "wrapper"). By isolating the implementation of your classes into your .cpp files, they need only be compiled once. Most changes do not require changes to the header file so it means you can make fairly extensive changes while only requiring one file to be recompiled. This also encourages refactoring and writing of comments and unit tests since compile time is decreased. Additionally, you automatically separate the concerns of interface and implementation so the interface of your code is simplified.

1800 INFORMATION
  • 131,367
  • 29
  • 160
  • 239
  • 1
    Most of these suggestions are going to decrease readability & maintainability of the code... so keep the trade offs in mind if you are only implementing the pimpl idiom to speed compilation. – oz10 Dec 13 '08 at 00:43
  • 6
    Using this pattern greatly increases the readability and maintainability of the code, for the reasons I already gave – 1800 INFORMATION Dec 13 '08 at 05:25
14

If you have large complex headers that must be included by most of the .cpp files in your build process, and which are not changed very often, you can precompile them. In a Visual C++ project with a typical configuration, this is simply a matter of including them in stdafx.h. This feature has its detractors, but libraries that make full use of templates tend to have a lot of stuff in headers, and precompiled headers are the simplest way to speed up builds in that case.

Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
  • PCH files are fantastic for speeding up large builds, but it's not always so obvious how to set them up -- I wrote a previous answer on this: http://stackoverflow.com/questions/11722944/what-is-the-difference-between-create-precompiled-header-yc-and-use-precom/11724752#11724752 – the_mandrill Apr 28 '14 at 12:00
8

These solutions apply to both debug and release, and are focused on a codebase that is already large and cumbersome.

Forward declarations are a common solution.

Distributed building, such as with Incredibuild is a win.

Pushing code from headers down into source files can work. Small classes, constants, enums and so on might start off in a header file simply because it could have been used in multiple compilation units, but in reality they are only used in one, and could be moved to the cpp file.

A solution I haven't read about but have used is to split large headers. If you have a handful of very large headers, take a look at them. They may contain related information, and may also depend on a lot of other headers. Take the elements that have no dependencies on other files...simple structs, constants, enums and forward declarations and move them from the_world.h to the_world_defs.h. You may now find that a lot of your source files can now include only the_world_defs.h and avoid including all that overhead.

Visual Studio also has a "Show Includes" option that can give you a sense of which source files include many headers and which header files are most frequently included.

For very common includes, consider putting them in a pre-compiled header.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
  • can you describe some techniques you use to move enums from headers into source files? This is [a link to my question on that subject](http://stackoverflow.com/questions/33655770/enum-in-header-causes-excessive-recompilations?noredirect=1#comment55088326_33655770) – Grim Fandango Nov 13 '15 at 12:50
8

I use Unity Builds (Screencast located here).

OJ.
  • 28,944
  • 5
  • 56
  • 71
7

We use Xoreax's Incredibuild to run compilation in parallel across multiple machines.

crashmstr
  • 28,043
  • 9
  • 61
  • 79
7

The compile speed question is interesting enough that Stroustrup has it in his FAQ.

David Norman
  • 19,396
  • 12
  • 64
  • 54
5

Also an interesting article from Ned Batchelder: http://nedbatchelder.com/blog/200401/speeding_c_links.html (about C++ on Windows).

Paweł Hajdan
  • 18,074
  • 9
  • 49
  • 65
4

Our development machines are all quad-core and we use Visual Studio 2008 supports parallel compiling. I am uncertain as to whether all editions of VS can do this.

We have a solution file with approximately 168 individual projects, and compile this way takes about 25 minutes on our quad-core machines, compared to about 90 minutes on the single core laptops we give to summer students. Not exactly comparable machines but you get the idea :)

2

With Visual C++, there is a method, some refer to as Unity, that improves link time significantly by reducing the number of object modules.

This involves concatenating the C++ code, usually in groups by library. This of course makes editing the code much more difficult, and you will run into namespace collisions unless you use them well. It keeps you from using "using namespace foo";

Several teams at our company have elaborate systems to take the normal C++ files and concatenate them at compile time as a build step. The reduction in link times can be enormous.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matt Shaw
  • 69
  • 1
  • 1
    At the cost of compiling time: if you change just one line of your library you will have to compile it completely. – David Rodríguez - dribeas Dec 13 '08 at 00:58
  • 1
    But it's possible that by concatenating in groups of 2, say, you almost halve the worst-case build time, and increase the best-non-trivial-case build time by only a few percent, because all the compilation time is being spent on code in headers, not code in cpp files. So choose 2 <= n <= everything. – Steve Jessop Dec 13 '08 at 01:47
1

Another useful technique is blobbing. I think it is something similar to what was described by Matt Shaw.

Simply put, you just create one cpp file in which you include other cpp files. You may have two different project configurations, one ordinary and one blob. Of course, blobbing puts some constrains on your code, e.g. class names in unnamed namespaces may clash.

One technique to avoid recompiling the whole code in a blob (as David Rodríguez mentioned) when you change one cpp file - is to have your "working" blob which is created from files modified recently and other ordinary blobs.

We use blobbing at work most of the time, and it reduces project build time, especially link time.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
alariq
  • 496
  • 3
  • 10
  • 2
    The common name for this is a 'Unity Build' - see http://stackoverflow.com/questions/543697/include-all-cpp-files-into-a-single-compilation-unit for more details. It's not necessarily a great idea. – JBRWilkinson Jan 23 '17 at 11:16
  • We also use blobbing at work, with a working blob based on the files currently checkout out in the VCS (if you've regenerated the project since). Note that it may also hide some errors such as making symbols available even if the corresponding files are not included. If a developer forgot to include a file that is in the same blob, the compile error will only pop up in the no-blob (standard) compilation (done in CI), at which point the developer will have to add missing includes. – hsandt Jul 24 '18 at 10:32
0

Compile Time:
If you have IncrediBuild, compile time won't be a problem. If you don't have a IncrediBuild, try the "unity build" method. It combine multiple cpp files to a single cpp file so the whole compile time is reduced.
Link Time:
The "unity build" method also contribute to reduce the link time but not much. How ever, you can check if the "Whole global optimization" and "LTCG" are enabled, while these flags make the program fast, they DO make the link SLOW.
Try turning off the "Whole Global Optimization" and set LTCG to "Default" the link time might be reduced by 5/6.
(LTCG stands for Link Time Code Generation)

Jeff Jiang
  • 11
  • 4