Speeding up C++ builds

| 8 Comments

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...

8 Comments

Have more than one machine? Try IncrediBuild.
Also SparkBuild may help speed up your builds a bit.

Rik,

Yes, I currently have 3 build servers but each of them is building things slightly differently. One builds VS2002, 2003 and 2005 for x86 and targets Win2k and XP with one version of the Platform SDK. One builds VS2008 and 2010RC for x86 and x64 and targets Vista and Win7 with the latest version of the Platform SDK and the third builds just for VS2008 for x86 and x64 and Win7 using STLPort rather than the default STL that ships with VS.

In addition each server could be building and testing either my libraries (around 35 static libs that are layered in such a way that they many of them depend on others) or my example servers (40-50 server projects that build on a selection of the library projects).

A distributed build system does appeal (as does a build system that doesn't use Cruise Control .Net) but right now I don't have the time to look into them. Suggestions or links welcome!

Len,

here are a couple of random thoughts on your post.

Maintenance of unities:
We use Unity Builds mostly for automated builds of software developed at the company that I'm associated with. Solutions tend to get huge (up to a 100 projects consisting of libraries, tests and examples). For maintenance we use CMake driven extended by our own functions/macros (functions similar to what I've shown at my post). We integrated Unity Builds as a feature to our CMake pipeline, which requires no end-user maintenance overhead at all.

Single translation unit:
There is not restriction to use just one single unity per project. In my posting I provide the tools to generate unities for groups of source files, so you can fine-tune your unities. Fine-tuning unities also cuts down compilation time.

Best regards,
Christoph

Christoph,

All good points. I expect I'd integrate them into my build system so that the required files were auto generated which would deal with the maintenance issue. Then I'm left with the single translation unit issues; until I've worked through a few of my library and test harness projects I wont know how much of an issue it will be. I agree I could split files that would be an issue merging out into separate unity builds and with the auto generation that wouldn't be too much of a pain. We'll see. It's certainly an interesting concept and one that could improve turn around on my build servers during test builds.

Good luck with your integration.

One side note: there is a second article in the series which deals with precompiled headers and automating developer builds (not test builds). you can find it at

http://cheind.wordpress.com/2010/02/21/reducing-compilation-time-precompiled-header/

- Christoph

Christoph

I'd seen that and I'm already very happy with my 'one true way' of using precompiled headers on VS; but thanks for the link.

Have you considered using namespaces to limit visibility instead of static functions? Or even anonymous namespaces.

Bryan,

Anonymous namespaces wouldn't help as once all of the cpp files are included into one translation unit all of the anonymous namespaces would be merged into one.

Per cpp file namespaces would work but would look unusual and the names within them would need to always be fully qualified at point of use to avoid the names clashing within the single combined translation unit.

It's something I need to look into though as it does have quite an effect on build times.

Leave a comment