Previous | Contents | Index |
The name-mapping file is supplied by the user and must be named Template.map. The file is in the repository directory and contains information the compiler uses to automatically instantiate templates; it supplements template information found in the source code and in header files.
A name-mapping file consists of the following entries:
name
A simple name to identify the template to the compiler. Qualified names are unnecessary and not allowed. Parentheses, return types, and parameter lists are also not allowed.filename
The path name of the file containing the template definition. Each file listed will be included in the resulting instantiation source file.
DEC C++ permits only one definition entry per template name. Thus, if the same name is used to define three different templates, each within its own file, you must list all three files in a single definition entry for that name.
Example 1
Consider the following template function:
template <class T> void sort( T *p ) {} |
The following is a valid name-mapping file definition entry:
definition sort in "sort_impl.cxx"; |
With this definition, the compiler expects to find the body of function template sort() in the source file sort_impl.cxx.
Example 2
Consider the following template member function:
template <class T> class List { public: void add_item(T new_item); /* ...*/ }; |
The following is a valid name-mapping file definition entry:
definition add_item in "List_funcs.cxx"; |
This definition instructs the compiler to find the body of the member function template add_item() in the source file List_funcs.cxx.
Presumably the source file List_funcs.cxx contains the following code:
#include "List.h" template <class T> void List<T>::add_item(T new_item){} |
Automatic instantiation makes including List.h more than once a possibility. To guard against this happening, you should enclose the code in include guards, as in the following example:
#ifndef List_H #define List_H ...// code for List.h #endif |
Example 3
Consider the following overloaded template member function:
//List.h #ifndef List_H #define List_H template <class T> class List { Public: List(); List(const List& l); /* ...*/ }; #endif //List.cxx #include "List.h" template <class T> List<T>::List(){} //List_copy.cxx #include "List.h" template <class T> List<T>::List(const List& l){} |
The following is a valid name-mapping file definition entry:
definition List in "List.cxx", "List_copy.cxx"; |
By default, DEC C++ creates one instantiation source file for each function template instantiation request, and one for each class template instantiation request. The instantiation source file includes all the headers needed to correctly instantiate a template. The order of inclusion is as follows (no file is included more than once):
For example, consider the following name-mapping file:
# Stack Implementation definition Stack in "Stack_Impl.cxx"; |
With an external unresolved symbol, Stack<C>::push(C), where class C is defined in the header file Cdef.h, the result would be the following instantiation source file:
#include "Cdef.h" #include "Stack.h" #include "Stack_Impl.cxx" typedef Stack<C> __dummy_; |
DEC C++ matches each instantiation request with the corresponding template definition file to create the instantiation source file. The name of this source file must be similar to that of the template declaration file. DEC C++ uses the following lookup order:
When a program makes a template instantiation request, DEC C++ avoids creating and compiling a new instantiation source file if existing source and object files can be reused.
For each instantiation request, when DEC C++ finds a corresponding instantiation source file or object file in the writeable repository, the following checks are performed:
When you build libraries and applications using manual instantiation, you face the tedious tasks of ensuring that all necessary templates are instantiated and of determining where each template instantiation is generated to avoid duplicates. The advantage of this method is that you have complete control over template instantiations; however using this approach can be time-consuming.
Automatic template instantiation performs these manual tasks for you if your build procedure and sources are properly set up. The procedure for building libraries and applications using automatic template instantiation differs somewhat from the procedure for manual instantiation. This section discusses the basic issues when using automatic template instantiation; it also provides suggestions and examples for resolving these issues.
See Section 3.4 for suggestions on organizing your sources.
5.2.9.1 Building a Standalone Library
Library vendors obviously need to provide a standalone library to their customers. With respect to templates, standalone means that the library contains:
In addition to library vendors, developers of large applications may
want to divide their application into one or more standalone libraries
to facilitate building. Creating a single library is straightforward.
However, creating multiple libraries is more difficult if the libraries
use the same template instantiations.
5.2.9.1.1 Creating a Single Library
Before DEC C++ added support for automatic template instantiation, a
typical build procedure would compile all the library sources and place
the resulting object files into an object library. Template
instantiations were generated through the use of the -define_templates option or explicit
instantiation or #pragma define_template
statements within the sources.
When you use automatic template instantiation, the basic method is the same: you want to compile all the library sources and place the resulting object files into an object library. However you first need to examine your sources and determine whether or not you need the explicit instantiation statements. Also you need to change your build procedure to specify different options on the cxx command line. See the following paragraphs for details.
Your Library Sources
An important similarity between manual and automatic template instantiation is that only the requested templates are instantiated. A requested template is one that is either of the following:
Therefore, when you examine your library sources, consider the following:
Building Your Library Sources
As you compile each library source, you must include the following options on your cxx command line:
Do not specify the -define_templates option on your cxx command.
If you intend to create a shareable library from these sources and you plan to let your customers preempt the symbols in your shareable library, you must also specify the -preempt_symbol option on your cxx command line.
A Sample Build Procedure
Suppose you want to create a standalone library of window routines and your build directories look like the following:
windows_library | ------------------------------------- | | | src build include w1.cxx | template1.hxx w2.cxx repository template1.cxx ...... |
Your build procedure, build_libwindows.sh, would be as follows:
lroot=pathname/windows_library lbuild=$lroot/build # Compile each source separately using -Hf # # -Hf option ensures that both the source and template instantiations # are compiled; do not use the -c option because that prevents # compilation of the template instantiations # # -ptr option causes all template instantiation files and objects to be # placed in the build/repository directory; you must specify the same # repository for each cxx command # # -o option causes the source object files to be placed in the build # directory cxx $lroot/src/w1.cxx -I $lroot/include -ptr $lbuild/repository \ -o $lbuild/w1.o -Hf cxx $lroot/src/w2.cxx -I $lroot/include -ptr $lbuild/repository \ -o $lbuild/w2.o -Hf # ... and so on for all library source files # And now place all the source objects and template instantiation objects # into the object library ar r $lbuild/libwindows.a $lbuild/*.o $lbuild/repository/*.o |
If you are a library provider, you may wish to create a shareable
library from the resulting object library and provide one or both
libraries to your customers. As noted in Section 3.4, you must also
provide the template declaration and template definition files for any
templates that your customers may use directly. You do not need to
provide template declaration and definition files for templates that
are solely used by your library sources.
5.2.9.1.2 Creating Multiple Libraries
If there are no common template instantiations among the libraries,
then you can follow the directions in Section 5.2.9.1.1 to build each
library.
If the libraries do share template instantiations, you must avoid creating the same instantiations in multiple libraries. Otherwise, any applications that link against your libraries will encounter multiply defined symbols. To solve this problem, you need to create another library that will contain the common instantiations.
No automated way exists to determine the set of common instantiations
needed by your libraries. One method is to first build each library as
described in Section 5.2.9.1.1, then compare the list of object files from
each library's repository and select the duplicates to place in your
common instantiation library. Another method is to build each library
and then link them together using the -all option on your ld command. The resulting multiply defined
symbols should be placed in your common instantiation library. For
details on building this common instantiation library, see
Section 5.2.9.3.
These messages can be a useful debugging tool when you are trying to
determine which template instantiations are reused, created, or not
found. You may see Unable to access file
messages. Remember that during the prelink phase, DEC C++ searches the
repositories for corresponding files for every unresolved
symbol and displays the access message for any file that is not found.
Thus, instead of watching for these access messages, Digital recommends
that you examine the results of the final link or final partial link to
determine whether you have unresolved symbols.
Typically, unresolved symbols indicate that an external library or
object file is missing from your cxx
command. Unresolved symbols are also caused when a source file or
instantiation source file cannot be compiled, so examine your build
results for compilation errors. If you cannot determine the cause of an
unresolved symbol, refer to Section 3.4 for an explanation of how to
organize your code to ensure that the symbol is generated.
Whether you have a large or small application, whether you have one or
multiple source directories, remember to use the same repository for
all components that are accumulated into any one executable. This is
important because it ensures that no duplicate instantiations are
created or accumulated into the executable, and it provides the best
build performance.
If you previously relied on manual instantiation to build your
application, you should no longer use the -define_templates option on your cxx command nor make explicit instantiation
requests within your sources. The automatic instantiation process
guarantees that all needed template instantiations will be generated.
Otherwise, unless you maintain the manual instantiation requests, they
may generate unnecessary instantiations as your sources change.
This basic method applies when you are using automatic template
instantiation, but you have the added concern of ensuring that template
instantiations are generated and linked into the final executable.
Building Your Application Sources
Because you will be performing a final link of your sources, you can
delay the prelink phase until the final link. Therefore, you can
continue to compile your application sources using the -c option and do not need to specify the -Hf option as described in Section 5.2.9.1.
However you must include the following options on your cxx commands:
5.2.9.1.3 Using the -ptv Option
When you specify the -ptv option during
compilation, DEC C++ displays informational messages about the
repository or repositories being used. When you specify the -ptv option during the prelink or link phase,
DEC C++ displays informational messages about the repositories as well
as each unresolved symbol, each instantiation object file found, and
each compilation of an instantiation source file.
5.2.9.2 Building an Application
5.2.9.2.1 Building from Multiple Source Directories
Large applications are often divided into multiple components because
building each component individually is easier to manage than building
the whole. Typically each component is built by compiling all the
component's source files, and then once all the components are built,
the resulting object files are linked together to create the final
executable.
Because
you will be delaying the compilation of template instantiations until
the final link, you must specify full
pathname for all include directories listed in your
cxx command. Otherwise the compilation of
template instantiations may fail due to missing include files.
You must
specify the same repository for each source file across all components,
and on your final link command as well.
A Sample Build Procedure
Suppose you have a spreadsheet application that is separated into three major components: user interface, reporting, and computing. These components are built individually and then accumulated along with the main program into a single executable.
Your build directories look like the following, where each component has its own subdirectory for sources, includes, and building in addition to the final build directory:
spreadsheet_proj | ---------------------------------------------------------- | | | | | ui rpt comp main final_build | | | | | ---------------- -------------- ... main.cxx repository | | | | | | src build include src build include |
You would have one build procedure for each component as well as a final build procedure. What is important is that each build procedure, including the final build, uses the same -ptr option. The ui build procedure, build_ui.sh, would look like the following, and the other component procedures would be similar:
sroot=pathname/spreadsheet_proj uiroot=$sroot/ui uibuild=$uiroot/build fibuild=$sroot/final_build # Compile each source separately using -c # # -ptr option causes all template instantiation files to be placed # in the final_build/repository directory; you must specify the same # repository for each cxx command # # -I option specifies the full pathname so that later compilation of # the template instantiations will succeed # # -o option causes the source object files to be placed in the ui/build # directory cxx $uiroot/src/ui1.cxx -I$uiroot/include -ptr $fibuild/repository \ -o $uibuild/ui.o -c # ... and so on for each source in this component |
Your final build procedure, build_spreadsheet.sh, would look like the following:
sroot=pathname/spreadsheet_proj uiroot=$sroot/ui uibuild=$uiroot/build comproot=$sroot/comp compbuild=$comproot/build rptroot=$sroot/rpt rptbuild=$rptroot/build fibuild=$sroot/final_build # Compile the main program and create the final executable # # -ptr option must specify the same repository used by the component builds # # all objects from component builds are included in the final executable; # the template instantiation objects are created during the prelink phase # and are included in the final executable cxx $sroot/main/main.cxx $uibuild/*.o $rptbuild/*.o $compbuild/*.o \ -I$uiroot/include -I$comproot/include -I$rptroot/include \ -ptr $fibuild/repository -o $fibuild/spreadsheet |
Previous | Next | Contents | Index |