Diary #21: Knee deep in templates, long compiles

So CGAL makes pretty use of C++ templates, and the Summer of Code project that I am working on builds a Qt4 visualization of 2D arrangements, one of these CGAL data structures for building collections of 2D curves. I decided to make the individual UI and event handling components templated by the type of arrangement and specialize as needed, and I think it ended up saving me a lot of typing. The problem is the compilation time for the full demo is pretty substantial.

arr_demo_clean_build

A clean actually took 5 minutes using a parallel build on a 4-core system. What’s hard to see is that actually one core gets stuck compiling a certain few files, for example, ArrangementDemoWindow.cpp is a major culprit. This bad boy is responsible for instantiating ArrangementDemoTab, which is templated by currently six different types of arrangements. Each of these tabs instantiate another level of at least six callback components that handle various operations on arrangements. There is a Qt GraphicsItem subclass for visualizing the actual arrangement that is also templated based on the arrangements. Finally, each of the components make use of little utility classes that are templated based on types provided by the arrangement type.

Now, C++ has no choice but to generate code for implicitly instantiated classes on the spot. so it’s probably no surprise that the memory usage spikes up to 4.1 GB when it hits a “fat” class like ArrangementDemoWindow. Sure, ArrangementDemoWindow.cpp is 1200 lines of code, but that shouldn’t cause such a massive effect. Unless you are a compiler that needs to instantiate a wide swath of template classes on demand to do type checking and such. So the silent console fails to convey the chaos that is happening behind the scenes, and the point is that there is a lot of redundant compilation happening.

So, it’s become an absolute pain to try to do any debugging with the full demo. It means that a single line change in a fat class like ArrangementDemoWindow means you have no choice but to sit through the deep compilation of all those templated classes, even if none of them changed at all. I’m fed up with it. Currently, I have to write a smaller UI example that instantiates only one type at a time so that recompilation is not so ridiculous.

But all this really makes me ask, is all this really unavoidable? Couldn’t I explicitly instantiate a certain set of template classes, precompile them once, and save them to a library for linking later on? How can I indicate this to the compiler?

Actually, if we could make use of C++11 features, we can use the extern templates feature to introduce some modularity. For example, suppose you wanted to precompile a vector of ints type. You can put this in your IntVector.h:

    #include <vector>
    extern template class std::vector<int>;
    typedef std::vector<int> IntVector;

and this in your IntVector.cpp:

    #include "IntVector.h"
    // instantiates the entire class from the default template
    template class std::vector<int>;

Then you can include the header file whenever you want to use IntVector. Wherever you use it, the compiler will not generate any code like it normally does, but you will need to compile IntVector.cpp and link its object. Now imagine if you have a lot of templated classes that are tied together with dependent parameter types and collaborate closely. Then this can save a ton of compilation time.

Clang will do it, and I guess g++ should do it if you set it to c++11 mode. But as always, I need to support the older compilers, so that’s right out.