Git makes working with many different branches in the same local repository easy and efficient.
In a C/C++ project, the code must be re-compiled after switching into another branch.
If the branches only differ minimally, running make
will only re-compile the parts that are
actually different, and after that re-link them. That won’t take too long, though especially
link times can be annoying.
However, if there are differences in central header files that are included from every file,
then make
has no option but to re-compile everything. This can take significant amounts of
time (and coffee).
I just realized that there is a solution to speed up re-compilation in this situation: ccache!
Why ccache can help
ccache is a wrapper for the actual compiler command. It will call the compiler with the specified arguments, and capture the compiler output. When called again with the same arguments, it will look in its internal cache for a ready-to-serve result. If one is present, it will return it without invoking the compiler again. Otherwise, or if it detects some changes that forbid serving outdated results from the cache, it will transparently invoke the compiler.
When switching back to another branch that you had already compiled before, running make
may re-build everything due to changes in headers. But it is not unlikely that you had built
the branch before already. If so, and ccache was involved in the previous build, it may still
have all the info required for re-compilation in its cache.
And everyone will be happy: make
will run its full rebuild, but most operations won’t be handed
to the compiler because ccache is sitting in between, serving results from its cache.
And you as a developer won’t lose that much time.
Some figures
Following are some figures demonstrating its potential when running a make
in the devel branch
after having returned from a different branch with significant changes.
With ccache, but cache empty
1 2 3 |
|
With ccache, everything in cache
1 2 3 |
|
That’s a build time reduction of more than 90 %!
This is already the optimal result, as everything was already present in the cache. However, the situation was not unrealistic. I often switch into another branch, try something out or commit a small change, and the return to the original branch. I already started having many separate directories for the different branches to avoid frequent recompilation. ccache can be relief here.
By the way, timing results are from my laptop. I did not bother to run make
with parallel
jobs as this has limited effect on my laptop, though on more decent hardware it may be beneficial
both with and without ccache, though I guess, with many parallel jobs and a full cache, linking
will become the most expensive part.
How to use ccache
For Ubuntu, ccache is available in package ccache
. You can easily install it with:
1
|
|
The most convenient way to use ccache in your build is to change your CC
and CXX
environment variables as follows:
1 2 |
|
I suggest putting that into .bashrc
so the variables will be set in every session and not
just once. After that, running configure
will write a Makefile
that will use ccache for
building object files.
Note: that will change these environment variables globally, so ccache may be used for other projects, too.
What ccache cannot do
I already forgot about ccache because when working in a single branch it does not provide that
many benefits. When making changes to your code, you can be pretty sure the new code won’t be
in the cache yet. Running make
then will invoke ccache, but this will result in a cache miss.
It cannot help here, because the new code was never compiled before and thus in no cache.
Additionally, make
is smart enough on its own to only re-build the parts of the program that
have actually changed or depend on the changes you made.