The Developer’s Cry

Yet another blog by a hobbyist programmer

Putting the fun back in C with unity builds

In last month’s post I mentioned that in my opinion, the holy grail of programming is C with classes. There is something incredibly fun about programming in C that other languages just don’t have, but I will admit that what it is missing are classes. You can work around this by using structs and function pointers, but it’s just … not the same.
There is of course C++, the one true successor to C that adds classes. We are now dealing with instances, references, namespaces and what not. Writing clean C++ code is often an exercise in what I call “keeping the compiler happy.” So Brian (pictured on the right) and me decided to start using it in a more hackish way, if only to put the fun back in C.

So, I’m working on this project, and the codebase quickly grew to a couple of thousand lines of code. Nothing special there, as even hobby projects are easily 10k LoC or 50k LoC or more. My aging computer is taking longer and longer to build the code, up to the point where I just wish I had a C++ interpreter rather than a compiler.

“My code is compiling.”

The idea of C/C++ is that you write multiple translation units and compile those into object files. The header files just have declarations, the C source files contain the implementation. The linker will combine the object files to create the final executable. Rebuilding a project should be fast because only those objects for which you changed code need recompilation. In practice, it takes quite some work to get the job done. On top of that, in C++ the headers contain lots of code because of templated classes. All those headers need to be parsed and compiled over and again. Building becomes a chore, even if you only include what you truly need.

Enter the “unity build” system. Also known as a major hack, unity builds bring compile times back from minutes to near instant at best, and seconds at worst. How is this possible? That endless stream of C++ headers, we are only going to build that once. Even on my aging computer, the compiler is surprisingly fast at doing stuff only once.

How to setup a unity build system

For a unity build, we are not going to write any traditional header files. Writing header files is just a chore, and considered a waste of time as they don’t serve any real purpose in a unity build system. Instead, if you need a struct or class, just put it in the top of the .c or .cpp source file. Any typedefs global to the project may go into a single header named types.h, but unlike traditional C, these headers are never included in every source file. No need to worry about any standard includes either; just write straight C code into the unit. Each unit is included into a master file for the project. That master file is the only file that is fed to the compiler, and it will build surprisingly fast.

// master.c

#include <stdlib.h>
#include <stdio.h>

#include "types.h"

#include "debug.c"
#include "mycode.c"
#include "main.c"

// end

The easiest way of using a unity build system is for new projects. Converting existing codes can be tricky. A reason for this is that the order of includes is more important than ever, and there are no include guards. Another reason is that all static symbols now appear in a single flattened namespace. You can’t use static at the unit level in a unity build system. Choose your (static) symbol names wisely; prefix them with the unit name, for instance.

The unity build system doesn’t help in creating reusable code. It is for this reason that schooled C programmers say it’s a total hack job. That may be so, but it is a complete joy to bang in make and instantly see the shell prompt return—ready to run that code and take it for a test drive. It gives a spin to C, nearly turning it into a scripting language.

It puts the fun back in C. Maybe we’re not supposed to do it this way, but maybe that’s why it’s so much fun.