Comeau C++ Export Overview

Copyright © 1992-2013 Comeau Computing, EDG

Exported Templates

Comeau C++ introduced its implementation of export in a beta release during mid-2002. A general released was provided in early 2003. This completes Comeau's support of all core language features. Comeau C++ now supports the core language of C++03 (C++98 plus TC1).

Some more overview information on export can be found by clicking here.

Exported templates are templates declared with the keyword export. Exporting a class template is equivalent to exporting each of its static data members and each of its non-inline member functions. An exported template is special because its definition does not need to be present in a translation unit that uses that template. In other words, the definition of an exported (non-class) template does not need to be explicitly or implicitly included in a translation unit that instantiates that template. For example, the following is a valid C++ program consisting of two separate translation units:

// File 1:
#include <stdio.h>

static void trace() { printf("File 1\n"); }

// declaration only
export template <class T> T const& min(T const&, T const&);

int main() {
  trace();
  return min(2, 3);
}

// File 2:
#include <stdio.h>

static void trace() { printf("File 2\n"); }

//The definition
export template <class T> T const& min(T const &a, T const &b) {
  trace();
  return a<b ? a : b;
}

Template Instantiation with Export

Note that these two files are separate translation units: one is not included in the other. That allows the two functions trace() to coexist (with internal linkage).

Support for exported templates can be enabled using the --export command-line option. Export is enabled by default in strict ANSI mode; that is -A or --strict. With Comeau C++ for MS-Windows you'd use --A. For example, the program above could be built as follows with Comeau C++:

como --export -c file_1.c
como --export -c file_2.c
como file_1.o file_2.o

Of course, other combinations will work too, such as:

como -A file_1.c file_2.c # Use --A under MS-Windows

Finding the exported template definition

The automatic instantiation of exported templates is somewhat similar (from a user's perspective) to that of regular (included) templates. However, an instantiation of an exported template involves at least two translation units: one which requires the instantiation, and one which contains the template definition.

When a file containing definitions of exported templates is compiled, a file with a ". et" suffix is created and some extra information is included in the associated ". ti" file. The ". et" files are used later by the Comeau C++ to find the translation unit that defines a given exported template.

When a file that potentially makes use of exported templates is compiled, Comeau C++ must be told where to look for ". et" files for exported templates used by a given translation unit. By default, the compiler looks in the current directory. Optionally, other directories may be specified with the --template_directory option. Strictly speaking, the ". et" files are only really needed when it comes time to generate an instantiation. This means that code using exported templates can be compiled without having the definitions of those templates available, in the actual source file or header files being compiled. Those definitions must be available by the time Comeau "prelinking" is done (or when explicit instantiation is done).

The ". et" files only inform Comeau C++ about the location of exported template definitions; they do not actually contain those definitions. The sources containing the exported template definitions must therefore be made available at the time of instantiation (usually, when prelinking is done). This is simply done as per the example above. Note that the export facility is not a mechanism for avoiding the publication of template definitions in source form.

As with the .ti files generated by Comeau C++, in many cases you need not be concered about the .et files. In those case where you do care, details are provided below about its structure.

Secondary translation units

An instantiation of an exported template can be triggered by the prelinker, by an explicit instantiation directive, or by the -tused command-line option. In each case, the translation unit that contains the initial point of instantiation will be processed as the primary translation unit. Based on information it finds in the ". et" files, Comeau C++ will then load and parse the translation unit containing the definition of the template to instantiate. This is a secondary translation unit.

The simultaneous processing of the primary and secondary translation units enables Comeau C++ to create instantiations of the the exported templates (which can include entities from both translation units).

This process may reveal the need for additional instantiations of exported templates, which in turn can cause additional secondary translation units to be loaded. As a consequence, using exported templates may require considerably more memory than similar uses of regular (included) templates. This of course is true whenever more instantiations are necessary, even if you are not using exported templates.

When secondary translation units are processed, the declarations they contain are checked for consistency. This process may report errors that would otherwise not be caught. This is an unobvious benefit. Many these errors are so-called "ODR violations" (ODR stands for "one-definition rule"). For example:

// File 3:
struct X {
  int x;
};

export template <class T> T const& min(T const&, T const&);

int main() {
  return min(2, 3);
}

// File 4:
struct X {
  unsigned x; // Error: X::x declared differently in File 3
};

export template <class T> T const& min(T const &a, T const &b) {
  return a<b ? a : b;
}

If there are no errors, the instantiations are generated in the output associated with the primary translation unit (or in separate associated files when in Comeau C++'s "one-instantiation-per-object" mode). Of course, this may also require that entities with internal linkage in secondary translation units be "externalized" so they can be accessed from the instantiations in the primary translation unit. As mentioned above, in many cases you need not be concered about these details.

Libraries with exported templates

Typically a (non-export) library consists of an include directory and a lib directory. The include directory contains the header files required by users of the library, and the lib directory contains the object code libraries that client programs must use when linking programs.

With exported templates, users of the library must also have access to the source code of the exported templates and the information contained in the associated ". et" files, as discussed above. This information, therefore, should be placed in a directory that is distributed along with the include and lib directories: This is the "export directory". It can be specified using the --template_directory option when compiling client programs. If not, by default the current directory is used.

The recommended procedure for a library author to use to build the export directory is as follows:

  1. For each ". et" file in the original source directory, copy the associated SOURCE FILE to the export directory.
  2. Concatenate all of the ". et" files into a single ". et" file (e. g., mylib.et) in the export directory. The individual ". et" files could be copied to the export directory, but having all of the ". et" information in one file will make use of the library more efficient.
  3. Create an export_info file in the export directory. The export_info file specifies the include search paths to be used when recompiling files in the export directory.

The export_info file consists of a series of lines of the form

include=x
or
sys_include=x

where x is a path name to be placed on the include search path. The directories are searched in the order in which they are encountered in the export_info file. The file can also contain blank lines, and comments which begin with a "#". Spaces are ignored but tabs are not currently permitted. For example:

# The include directories to be used for the xyz library

include = /disk1/xyz/include
sys_include = /disk2/abc/include
include=/disk3/jkl/include

The include search path specified for a client program is ignored by Comeau C++ when it processes the source in the export library, except when no export_info file is provided. Command-line macro definitions specified for a client program are also ignored by Comeau C++ when processing a source file from the export libary; the command-line macros specified when the corresponding ". et" file was produced do apply. All other compilation options (other than the include search path and command-line macro definitions) used when recompiling the exported templates will be used to compile the client program.

There is no requirement that the include directory and lib directory need be different, but it is often done for organizational purposes. This same consideration comes into play with the export directory.

When a library is installed on a new system, it is likely that the export_info file will need to be adapted to reflect the location of the required headers on that system.

// the end