views:

52

answers:

2

I have some template classes I've written that are dependencies for several other classes I need to compile. I have a few options as to how I can do this in my Makefile:

  1. Each class that requires a template lists its template requirements. This has the drawback of needing to recreate the dependency tree every time I want to add a new class.

  2. Make the templates into target somehow. Either by compiling them, or by making some shadow dependency tree that does not compile anything, but simply forces a recompilation in the event of one of the templates becoming modified.

Any suggestions are welcome.

+1  A: 

On option 2, you can compile a template instantiation using g++. For example, suppose you had:

// my_class.hpp
template <typename T1, class Container, typename Compare>
class my_class {
    // ...
};

and in your code you used my_class<long, std::vector<long>, std::greater<long> >. With g++ you can compile the instantiation of my_class<long, std::vector<long>, std::greater<long> > into an object file:

// my_class_long_long_vector_greater_instantiation.cpp
#include "my_class.hpp"

template class my_class<long, std::vector<long>, std::greater<long> >;

Then, in your Makefile near the bottom you add:

my_class_long_long_vector_greater_instantiation.o: my_class.hpp

If any target depends on my_class_long_long_vector_greater_instantiation.o, and the declaration of template my_class has changed (the my_class.hpp file was changed), then GNU make will re-compile my_class_long_long_vector_greater_instantiation.cpp, hence re-instantiate my_class<long, std::vector<long>, std::greater<long> >.

See also: Where's the Template?

Daniel Trebbien
I like it. I think this works.
Alex
+1  A: 

As Neil Butterworth mentioned in a comment, make deals with files. Say you have a foo.cpp and a bar.h. The latter contains your template. And the former might do, for example:

#include "bar.h"
class Foo : public Bar<Widget> { [...] };

While your Foo class inherits and thus depends on your Bar template class, you are also already declaring your file dependencies with your #includes.

It's those same file dependencies that you specify in your Makefile:

foo.o: foo.cpp bar.h
        g++ -I. -o foo.o foo.cpp

For this rule, make expects that the commands you specify create foo.o, based on the foo.cpp and bar.h files. If you've already built foo.o once, and those dependencies haven't changed, make knows it can skip the rule altogether.

It may seem tedious to specify file dependencies twice, but luckily dependencies in your Makefile can be automatically generated from #includes in your source code by GCC using the -M command-line parameter. You can read about this in the gcc(1) manpage. Simply take GCC's output, save it somewhere, typically foo.d, and include that in your Makefile.

With some wizardry, you can automate the generation of *.d dependency files in the same Makefile that builds your application.

Shtééf