Compile Times of Single-Translation-Unit-Builds

Making a single-translation-unit-build (STUB) is a method of speeding up compile times in C and C++ programs. This article explains how to implement this method, provides examples of regular build times and STUB times, and analyzes the differences.

Translation Units

However, computers have changed a lot since the introduction of C. Fitting an entire program into memory isn’t much of an issue, and CPUs have become unbelievably faster. The traditional wisdom could use some re-evaluation. While changing a source file can be relatively fast, changing a header file requires recompiling every source file that includes it.

Build Times

Reducing compile times is important in software engineering: your time is valuable, and time spent waiting for compilation means less time for writing code and testing the code. Programmers have a variety of ways to cut down on their build times:

  • Changing header files as little as possible is probably the most common strategy. It already works well with the principle of encapsulation (keep your interfaces consistent), but in practice, improving a class can often require a change to some part of a header. Even just changing a comment will tell build systems to recompile all source files that include the header.
  • Relatedly, a surefire way to reduce your build times is to #include fewer headers. The fewer source files you have that include a header, the fewer will have to be recompiled when that header changes. Headers are still code and have to be parsed just like source files.
  • Templates are a huge source of long build times in C++. Cutting down on your use of templated classes is one way to reduce build times.
  • Some programmers jumped ship and went back to C. It’s faster to parse since it’s a simpler language, and using C guarantees that no one will use slow language features like templates.
  • Jonathan Blow is creating his own language and compiler that compiles 33,000 lines of code in less than half a second (demo on youtube). Unfortunately, the language is not released at time of writing, and making your own language is probably even less productive than waiting for Visual Studio to compile a project built on Boost.
  • A method that’s been gaining popularity is “single translation unit builds” (STUB) or “unity builds,” where all .cpp files are compiled to a single translation unit. Each header file only has to be parsed once (include guards will stop duplicates when pre-processing) and the linker has much less work to do. The major downside is that this method requires a full rebuild of your program for any change at all. This is the method we’ll be looking at in detail. Are the time savings of a STUB worth a full rebuild every time?

Measuring Build Times

My 7-year-old workstation laptop has an Intel Core i5-M560 (2.67 GHz, dual core) and reports 3.86 GB of usable RAM. I’m using 64-bit Windows 7 and Visual Studio 2013. It does have an SSD, but file caching probably makes that irrelevant for the size of programs I tested. When building in release mode, the compiler spends a lot of time on optimizing, so I built the programs in debug mode. I did a full rebuild of each configuration five times to get average times.

Not-Even Hello World

int main()
{
return 0;
}

On my machine, it takes Visual Studio on average 0.359 seconds to compile this C++ program. That’s about a third of a second to compile pretty much nothing.

Making a STUB for an Existing Project

Normal full build times:

To convert this project to a STUB, I made a new build configuration in Visual Studio so that the normal build wouldn’t be changed, and I added a new file called SingleTranslationUnitBuild.cpp. The STUB file simply includes every other source file:

#include “AxisControl.cpp”
#include “AxisWidget.cpp”
#include “ButtonControl.cpp”
#include “ButtonWidget.cpp”
#include “commons.cpp”
#include “FileDialog.cpp”
#include “FileManager.cpp”
#include “Joystick.cpp”
#include “MainWindow.cpp”
#include “UIWidgets.cpp”
#include “main.cpp”

If you compiled now, every function would have multiple definitions, since there are 2 copies of each .cpp being compiled and linked. To fix this, select every .cpp except the STUB in Visual Studio and go to Project > Properties. In Configuration Properties > General, set “Excluded From Build” to “Yes.” Now only the STUB file will be built. In your normal build, just exclude the STUB file.

STUB times:

This is about 2.6 seconds longer than it takes to compile the simplest C++ program. Considering the power of modern computers, 2.957 seconds seems kind of long for such a small program. Will it scale well to larger projects? For comparison, how much time does it take a normal build to recompile main.cpp (which is 40 lines of code) after changing a comment?

Normal build times when changing a comment in a source file:

This is only about 0.7 seconds faster than compiling all of the code in the program. The thing to keep in mind is that source files include headers, which have to be parsed. Parsing main.cpp means parsing Windows headers, SDL headers, and parts of the C++ standard library. The quantity of this code dwarfs my own code and accounts for a lot of the build time. What’s more, the same header files may have to be re-parsed for every translation unit that includes them. Reducing the amount of headers #included in your .cpp files, directly or by a chain of #includes, is probably the best way to speed up your build times if you’re not doing a STUB.

You also don’t need to have only one translation unit. If you’re doing a lot of work to a header, you could combine compilation of only the source files that #include that header. You could also partition major components of a project into their own translation units.

Do Static Functions Affect Build Times?

The C++ keyword “static” before a function means each translation unit will get its own copy. Since that makes less work for the linker, does it speed up build times at all? To find out, I prefixed most functions in my code with FUNCTION_DEF, which can be #defined to be “static” or just nothing.

STUB times with non-static functions:

STUB times with static functions:

There’s not much of a difference between the two. Maybe in a larger project a difference would be more visible, but it doesn’t look like it’s worth the time investment of adjusting all of your functions.

Pitfalls of STUBS

About Me

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store