Nokia Networks Home

Nokia nmake Product Builder

Quick Links

Related Products

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
Last Update: Friday,12-Aug-2016 10:46:00 EDT