I stumbled on an idea for speeding up C++ builds the other day and it’s not something that I’ve considered before and it really does offer a considerable speed up so I think it may be worth considering in some situations. It has downsides which make it harder to use with my default style of code structuring but the increase in build speed is tempting…
The idea is that of “Unity builds” which I discovered from an answer by Christoph Heindl on Stack Overflow about how to speed up Visual Studio builds. Christoph refers to this blog entry; The Magic of Unity Builds which explains that due to disk accesses it’s more efficient for a compiler to compile a single .cpp file that includes all of your other .cpp files and that this has a major effect on compilation time. Others suggest that this also results in better optimisation due to the fact that all of the code is visible to the optimiser at the same time, but this may not make that much difference to you if you have link time code generation and whole program optimisation turned on.
Anyway, I gave this a go for one of my libraries and it does indeed dramatically improve compile and link times when rebuilding the library. Of course that’s the problem though, it always results in a complete rebuild. Because of this I don’t see that it’s especially suitable for day to day development where my “no precompiled headers” build configuration means that I only ever have to rebuild the code that has changed. However the Unity Build is faster than my complete rebuild with precompiled headers enabled so it might be useful for the integration builds on my build servers. Since my build servers also test that all of the normal build configurations work, and since I don’t see me ever moving away from a standard build, I would only be able to use this technique for the integration builds for all compilers and platforms during the development process and I’d have to use my current method of compilation for the final test builds before release.
The problem with Unity Builds is that you end up with a single C++ “translation unit” rather than a series of translation units (one per source code file). Translation units are important in C++ compilation and there are some practices that rely on each file being a separate translation unit. In The Magic of Unity Builds, OJ refers to the problems that arise from merging translation units as being due to dodgy coding practices. I disagree here. The main problem that I’ve come across so far is that static variables and functions are, of course, local to the translation unit in which they’re defined. With the single translation unit “unity build” approach you effectively lose the ability to declare static variables and functions. This is quite a big issue for me as I like to limit visibility as much as possible so functions that are used internally by a class and that do not need to be member functions are often implemented as file level static functions. Sure they could be implemented as class level, private, static functions but this exposes them to the header file and thus causes more code to require compiling if they’re changed. Likewise file level static variables are sometimes useful. Rarely as variables but often as constants. The unity build approach means that you need to be careful with naming to avoid name clashes from your static functions. This may be a big enough issue for me that I wont use Unity Builds no matter how much they improve the speed of my integration test builds.
Another issue with Unity Builds is the additional build configurations required. To be of value to me during integration testing I would need to be able to build a Unity Build of each of my 4 standard build configurations (Debug, Unicode Debug, Release, Unicode Release). That means 8 more configurations to manage (4 for x86 and 4 for x64). Because of this, and because I expect that I’d want to strip the Unity Build from my released source code distribution, I expect that I’d place all of the Unity Builds in their own project file. So now each library would have two project files per compiler and an additional solution file that pulls them all together. These could be automatically generated from the standard project and solution files.
Finally there’s the maintenance of the “Unity” file itself. Again this could be automatically generated, but it’s likely to be more complex than simply creating a file that includes every .cpp file in the project. I’m sure that some of my libraries will have enough code that they will blow some internal compiler limits when compiled as a Unity Build. This means that I’ll need some way of splitting the Unity file into several files to get around compiler limits - supporting 5 versions of Visual Studio is likely to make this more complex.
The maintenance of the Unity build can be automated but the problems of using a single translation unit could well mean that I don’t use Unity Builds for my library source code. Unfortunately the single translation unit issues also mean that the approach is also less likely to work in arbitrary client projects which desperately need to have their compilation times reduced - I’m sure there are lots of dubious coding practices that will make single translation unit builds impossible without code changes. That said it’s a potentially useful technique and one that I hadn’t heard of before. Certainly something to spend a bit more time exploring…