Alcatel-Lucent nmake Product Builder
Why No Recompile Using Implicit C++ Templates?
Many C++ compilers support two ways to organize template declaration and definition files, definitions-included and definitions-separate. In definitions-included organization, template definitions are explicitly provided to the compiler, typically by #include'ing the definitions file at the bottom of the template declarations header file. In the definitions-separate approach, template definitions are not explicitly provided to the compiler, and the compiler is given permission to go looking for a file containing the needed definitions, typically by searching the #include path for a file with the same basename as the template declaration file, and a file extension of .c, .C, .cpp, .cc, or .cpp.
The definitions-separate approach leads to a problem when used in combination with nmake and C++ compilation systems which perform compile-time instantiation. Since the nmake scanning rules rely upon #include statements to infer implicit file prerequisites, under definitions-separate organization, template declaration files will not be inferred as an implicit prerequisites of a primary object, and updating a template definition will not cause rebuilding of any dependent template instantiations.
Here is an example, using the Sun 4.2 C++ compiler definitions-separate feature. Note that nmake fails to recompile/reinstantiate when the implicitly-included template definitions file is touched.
$ cat Makefile
CC = CC
myprog :: myprog.C
$ cat myprog.C
#include <iostream.h>
#include "mytemplate.h"
int
main()
{
mytemplate<5> myt;
cout << myt.get_x() << endl;
return 0;
}
$ cat mytemplate.h
#ifndef MYTEMPLATE_H
#define MYTEMPLATE_H
template <int T> class mytemplate {
public:
mytemplate();
int get_x();
private:
int x;
};
#endif
$ cat mytemplate.C
template <int T>
mytemplate<T>::mytemplate()
: x(T)
{
}
template <class T>
int
mytemplate<T>::get_x()
{
return x;
}
$ nmake
+ ppcc -i -l /tools/nmake/sparc5/v3.1.2/lib/cpp CC -O -I-D/tools/nmake/
sparc5/v3.1.2/lib/probe/C/pp/58D7E9152binCC -I. -I- -c myprog.C
+ ppcc -i -l /tools/nmake/sparc5/v3.1.2/lib/cpp CC -O -I-D/tools/nmake/
sparc5/v3.1.2/lib/probe/C/pp/58D7E9152binCC -I. -I- -I. -o myprog mypro
g.o
$ touch mytemplate.h
$ sleep 1
$ nmake
+ ppcc -i -l /tools/nmake/sparc5/v3.1.2/lib/cpp CC -O -I-D/tools/nmake/
sparc5/v3.1.2/lib/probe/C/pp/58D7E9152binCC -I. -I- -c myprog.C
+ ppcc -i -l /tools/nmake/sparc5/v3.1.2/lib/cpp CC -O -I-D/tools/nmake/
sparc5/v3.1.2/lib/probe/C/pp/58D7E9152binCC -I. -I- -I. -o myprog mypro
g.o
$ touch mytemplate.C
$ sleep 1
$ nmake
To get the desired behaviour, it is necessary to explicitly #include the definitions file in the template .h file. To ensure that you don't inadvertently leave out the definitions file #include and possibly trigger implicit inclusion, you may wish to rename the definitions file so it no longer has the same basename as the corresponding .h file:
$ cat mytemplate.h
#ifndef MYTEMPLATE_H
#define MYTEMPLATE_H
template <int T> class mytemplate {
public:
mytemplate();
int get_x();
private:
int x;
};
#include "mytemplateDEF.C"
#endif