This chapter contains the following sections:
Introduction
C++ Language Extension Keywords
C++ Dialect Accepted
New Language Features Accepted
New Language Features Not Accepted
Anachronisms Accepted
Extensions Accepted in Normal C++ Mode
Extensions Accepted in Cfront 2.1 Compatibility Mode
Extensions Accepted in Cfront 2.1 and 3.0 Compatibility Mode
Namespace Support
Template Instantiation
Automatic Instantiation
Instantiation Modes
Instantiation #pragma Directives
Implicit Inclusion
Predefined Macros
Precompiled Headers
Automatic Precompiled Header Processing
Manual Precompiled Header Processing
Other Ways to Control Precompiled Headers
Performance Issues
The TASKING C++ compiler ( cp563) offers a new approach to high-level language programming for the DSP56xxx family. The C++ compiler accepts the C++ language as defined by the ISO/IEC 14882:1998 standard, with the exceptions listed in section 3.3 . It also accepts the language extensions of the C compiler.
This chapter describes the C++ language extensions and some specific features.
The C++ compiler supports the same language extension keywords as the C compiler. These language extensions are enabled by default (--embedded), but you can disable them by specifying the --no_embedded command line option. When -A is used, the extensions will be disabled.
The following language extensions are supported:
In addition to the standard data types, cp563 supports the fractional type (_fract), long fractional type (long _fract), enumerated type (enum) and complex data type (_complex).
You can specify a variable to be at an absolute address.
You can specify a variable to wrap around instead of going into saturation during calculations.
Apart from a memory category (extern, static, ...) you can specify a storage specifier in each declaration. This way you obtain a memory model-independent addressing of variables in several address ranges (_X, _Y, _L, _P, _near, _internal, _external). The _near, _internal and _external modifiers can also be used on functions to force them in a specific memory region.
In the mixed model (DSP5600x only) you can selectively define functions as reentrant (_reentrant keyword). Reentrant functions can be invoked recursively. Interrupt programs can also call reentrant functions.
You can specify interrupt functions directly through interrupt vectors in the C language (_fast_interrupt, _long_interrupt keyword).
You can specify to inline a function body instead of calling the function by using the _inline keyword.
With the _compatible keyword you can specify that a function must have the same calling convention as the Motorola C compiler. The _callee_save keyword can be used to indicate that a function must save all registers, instead of leaving this to the caller.
cp563 supports the type modifier _circ for circular data structures and pointers.
A number of pre-declared functions can be used to generate inline assembly code at the location of the intrinsic (built-in) function call. This avoids the overhead which is normally used to do parameter passing and context saving before executing the called function.
The C++ compiler supports the same pragmas as the C compiler. Pragmas give directions to the code generator of the compiler.
All of the language extensions mentioned above are described in detail in the C Cross-Compiler User's Guide.
The C++ compiler accepts the C++ language as defined by the ISO/IEC 14882:1998 standard, with the exceptions listed below.
The C++ compiler also has a cfront compatibility mode, which duplicates a number of features and bugs of cfront 2.1 and 3.0.x. Complete compatibility is not guaranteed or intended; the mode is there to allow programmers who have unwittingly used cfront features to continue to compile their existing code. In particular, if a program gets an error when compiled by cfront, the C++ compiler may produce a different error or no error at all.
Command line options are also available to enable and disable anachronisms and strict standard-conformance checking.
The following features not in traditional C++ (the C++ language of "The Annotated C++ Reference Manual" by Ellis and Stroustrup (ARM)) but in the standard are implemented:
The following features of the C++ standard are not implemented yet:
The following anachronisms are accepted when anachronisms are enabled (with --anachronisms):
int f(int); int f(x) char x; { return x; }
struct A { A(int); A operator=(A&); A operator+(const A&); }; main () { A b(1); b = A(1) + A(2); // Allowed as anachronism }
The following extensions are accepted in all modes (except when strict ANSI violations are diagnosed as errors):
class A { friend B; // Should be "friend class B" };
class A { const int size = 10; int a[size]; };
struct A { int A::f(); // Should be int f(); };
struct A { }; struct B : public A { B& operator=(A&); };
extern "C" void f(); // f's type has extern "C" linkage void (*pf)() // pf points to an extern "C++" function = &f; // error unless implicit conversion is // allowed
char *p = x ? "abc" : "def";
The following extensions are accepted in cfront 2.1 compatibility mode in addition to the extensions listed in the 2.1/3.0 section following (i.e., these are things that were corrected in the 3.0 release of cfront):
- A member in a base class must have the same name as an identifier at the global scope. The member may be a function, static data member, or non-static data member. Member type names do not apply because a nested type will be promoted to the global scope by cfront which disallows a later declaration of a type with the same name at the global scope.
- The declaration of the global scope name must occur between the declaration of the derived class and the declaration of an out-of-line constructor or destructor. The global scope name must be a type name.
- No other member function definition, even one for an unrelated class, may appear between the destructor and the offending reference. This has the effect that the nonstandard lookup applies to only one class at any given point in time. For example:
struct B { void func(const char*); };
struct D : public B { public: D(); void Init(const char* ); }; struct func { func( const char* msg); }; D::D() void D::Init(const char* t) { //Should call B::func -- calls func::func instead. new func(t); }
int a1; int e1; void f1(); class A { int a1; void f1(); friend void f() { int i1 = a1; // cfront uses global a1 f1(); // cfront uses global f1 } };
int a1; int b1; struct A { static int a1; class B { static int b1; friend void f() { int i1 = a1; // cfront uses A::a1 int j1 = b1; // cfront uses global b1 } }; };
class A { A() const; // No error in cfront 2.1 mode };
The following extensions are accepted in both cfront 2.1 and cfront 3.0 compatibility mode (i.e., these are features or problems that exist in both cfront 2.1 and 3.0):
struct A { void f() const; }; void (A::*fp)() = &A::f;
struct A { friend B; };
int *p; const int *&r = p; // No temporary used
struct S { void S::f(); };
struct A { void f(int); static void sf(int); typedef void A::T3(int); // nonstd typedef decl typedef void T2(int); // std typedef }; typedef void A::T(int); // nonstd typedef decl T* pmf = &A::f; // nonstd ptr-to-member decl A::T2* pf = A::sf; // std ptr to static mem decl A::T3* pmf2 = &A::f; // nonstd ptr-to-member decl
void (A::* pmf)(int) = &A::f;
class B { protected: int i; }; class D : public B { void mf(); }; void D::mf() { int B::* pmi1 = &B::i; // error, OK in cfront mode int D::* pmi2 = &D::i; // OK }
Protected member access checking for other operations
(i.e., everything except taking a pointer-to-member address) is done in the normal manner.
class A { ~A(); }; class B : public A { ~B(); }; B::~B(){} // Error except in cfront mode
class A { A(); }; double d; A x(int(d)); A(x2);
int xyz(int());
typedef class A T; class T *pa; // No error in cfront mode
short short int i; // No warning in cfront mode
struct A { virtual void f() {} A() {} ~A() {} }; struct B : public A { B() {} ~B() {f();} // Should call A::f according to // ARM 12.7 }; struct C : public B { void f() {} } c;
f(1, 2, );
struct A {int f();}; main () { int (*p)(); p = (int (*)())A::f; // Okay, with warning }
typedef struct { int i, j; } S; struct S x; // No error in cfront mode
class A { void f(int) const; static void f(int); // No error in cfront mode };
int f(int i) { for (int j = 0; j < i; ++j) { /* ... */ } return j; // No error in cfront mode }
typedef void (*PF)(); extern "C" typedef void (*PCF)(); void f(PF); void f(PCF);
struct A { virtual void f(); int i; }; const A a;
typedef int I; struct S { I(); // Accepted in Cfront mode (declares "int S::I()") I(int); // Not accepted };
Namespaces are enabled by default except in the cfront modes. You can use the command-line options --namespaces and --no_namespaces to enable or disable the features.
Name lookup during template instantiations now does something that approximates the two-phase lookup rule of the standard. When a name is looked up as part of a template instantiation but is not found in the local context of the instantiation, it is looked up in a synthesized instantiation context. The C++ compiler follows the new instantiation lookup rules for namespaces as closely as possible in the absence of a complete implementation of the new template name binding rules. Here is an example:
namespace N { int g(int); int x = 0; template <class T> struct A { T f(T t) { return g(t); } T f() { return x; } }; }
namespace M { int x = 99; double g(double); N::A<int> ai; int i = ai.f(0); // N::A<int>::f(int) calls // N::g(int) int i2 = ai.f(); // N::A<int>::f() returns // 0 (= N::x) N::A<double> ad; double d = ad.f(0); // N::A<double>::f(double) // calls M::g(double) double d2 = ad.f(); // N::A<double>::f() also // returns 0 (= N::x) }
The lookup of names in template instantiations does not conform to the rules in the standard in the following respects:
The lookup rules for overloaded operators are implemented as specified by the standard, which means that the operator functions in the global scope overload with the operator functions declared extern inside a function, instead of being hidden by them. The old operator function lookup rules are used when namespaces are turned off. This means a program can have different behavior, depending on whether it is compiled with namespace support enabled or disabled:
struct A { }; A operator+(A, double); void f() { A a1; A operator+(A, int); a1 + 1.0; // calls operator+(A, double) // with namespaces enabled but } // otherwise calls operator+(A, int);
The C++ language includes the concept of templates. A template is a description of a class or function that is a model for a family of related classes or functions.1
1 Since templates are descriptions of entities (typically, classes) that are parameterizable according to the types they operate upon, they are sometimes called parameterized types. ))> For example, one can write a template for a Stack class, and then use a stack of integers, a stack of floats, and a stack of some user-defined type. In the source, these might be written Stack<int>, Stack<float>, and Stack<X>. From a single source description of the template for a stack, the compiler can create instantiations of the template for each of the types required.
The instantiation of a class template is always done as soon as it is needed in a compilation. However, the instantiations of template functions, member functions of template classes, and static data members of template classes (hereafter referred to as template entities) are not necessarily done immediately, for several reasons:
(It should be noted that certain template entities are always instantiated when used, e.g., inline functions.)
From these requirements, one can see that if the compiler is responsible for doing all the instantiations automatically, it can only do so on a program-wide basis. That is, the compiler cannot make decisions about instantiation of template entities until it has seen all the source files that make up a complete program.
This C++ compiler provides an instantiation mechanism that does automatic instantiation at link time. For cases where you want more explicit control over instantiation, the C++ compiler also provides instantiation modes and instantiation pragmas, which can be used to exert fine-grained control over the instantiation process.
The goal of an automatic instantiation mode is to provide painless instantiation. You should be able to compile source files to object code, then link them and run the resulting program, and never have to worry about how the necessary instantiations get done.
In practice, this is hard for a compiler to do, and different compilers use different automatic instantiation schemes with different strengths and weaknesses:
2 The actual implementation allows for several different suffixes and provides a command-line option to change the suffixes sought. ))>
Our approach is a little different. It requires that, for each instantiation required, there is some (normal, top-level, explicitly-compiled) source file that contains the definition of the template entity, a reference that causes the instantiation, and the declarations of any types required for the instantiation.3
3 Isn't this always the case? No. Suppose that file A contains a definition of class X and a reference to Stack<X>::push, and that file B contains the definition for the member function push. There would be no file containing both the definition of push and the definition of X. ))> This requirement can be met in various ways:
Our compiler's automatic instantiation method works as follows:
1. The first time the source files of a program are compiled, no template entities are instantiated. However, the generated object files contain information about things that could have been instantiated in each compilation. For any source file that makes use of a template instantiation an associated .ii file is created if one does not already exist (e.g., the compilation of abc.cc would result in the creation of abc.ii).
2. When the object files are linked together, a program called the prelinker, prelk563 for the DSP563xx/DSP566xx (prelk56 for the DSP5600x), is run. It examines the object files, looking for references and definitions of template entities, and for the added information about entities that could be instantiated.
3. If the prelinker finds a reference to a template entity for which there is no definition anywhere in the set of object files, it looks for a file that indicates that it could instantiate that template entity. When it finds such a file, it assigns the instantiation to it. The set of instantiations assigned to a given file is recorded in the associated instantiation request file (with, by default, a .ii suffix).
4. The prelinker then executes the compiler again to recompile each file for which the .ii file was changed. The original compilation command-line options (saved in the template information file) are used for the recompilation.
5. When the compiler compiles a file, it reads the .ii file for that file and obeys the instantiation requests therein. It produces a new object file containing the requested template entities (and all the other things that were already in the object file).
6. The prelinker repeats steps 3-5 until there are no more instantiations to be adjusted.
7. The object files are linked together.
Once the program has been linked correctly, the .ii files contain a complete set of instantiation assignments. From then on, whenever source files are recompiled, the compiler will consult the .ii files and do the indicated instantiations as it does the normal compilations. That means that, except in cases where the set of required instantiations changes, the prelink step from then on will find that all the necessary instantiations are present in the object files and no instantiation assignment adjustments need be done. That's true even if the entire program is recompiled.
If you provide a specialization of a template entity somewhere in the program, the specialization will be seen as a definition by the prelinker. Since that definition satisfies whatever references there might be to that entity, the prelinker will see no need to request an instantiation of the entity. If you add a specialization to a program that has previously been compiled, the prelinker will notice that too and remove the assignment of the instantiation from the proper .ii file.
The .ii files should not, in general, require any manual intervention. One exception: if a definition is changed in such a way that some instantiation no longer compiles (it gets errors), and at the same time a specialization is added in another file, and the first file is being recompiled before the specialization file and is getting errors, the .ii file for the file getting the errors must be deleted manually to allow the prelinker to regenerate it.
If you supplied the -v option to the control program cc563, and the prelinker changes an instantiation assignment, t he prelinker will issue messages like:
C++ prelinker: A<int>::f() assigned to file test.o C++ prelinker: executing: cc563 -c test.cc
The automatic instantiation scheme can coexist with partial explicit control of instantiation by you through the use of pragmas or command-line specification of the instantiation mode. See the following sections.
Instantiations are normally generated as part of the object file of the translation unit in which the instantiations are performed. But when "one instantiation per object" mode is specified, each instantiation is placed in its own object file. One-instantiation-per-object mode is useful when generating libraries that need to include copies of the instances referenced from the library. If each instance is not placed in its own object file, it may be impossible to link the library with another library containing some of the same instances. Without this feature it is necessary to create each individual instantiation object file using the manual instantiation mechanism.
The automatic instantiation mode is enabled by default. It can be turned off by the command-line option --no_auto_instantiation. If automatic instantiation is turned off, the extra information about template entities that could be instantiated in a file is not put into the object file.
Normally, when a file is compiled, no template entities are instantiated (except those assigned to the file by automatic instantiation). The overall instantiation mode can, however, be changed by a command line option:
--instantiate none
Do not automatically create instantiations
of any template entities. This is the default. It is also the usually appropriate mode when automatic instantiation is done.
--instantiate used
Instantiate those template entities
that were used in the compilation. This will include all static data members for which there are template definitions.
--instantiate all
Instantiate all template entities
declared or referenced in the compilation unit. For each fully instantiated template class, all of its member functions and static data members will be instantiated whether or not they were used. Non-member template functions will be instantiated even if the only reference was a declaration.
--instantiate local
Similar to --
instantiate used except that the functions are given internal linkage. This is intended to provide a very simple mechanism for those getting started with templates. The compiler will instantiate the functions that are used in each compilation unit as local functions, and the program will link and run correctly (barring problems due to multiple copies of local static variables.) However, one may end up with many copies of the instantiated functions, so this is not suitable for production use. --instantiate
local can not be used in conjunction with automatic template instantiation. If automatic instantiation --instantiate
local option. If automatic instantiation is not enabled by default, use of --instantiate local and --auto_instantiation is an error.
In the case where the cc563 command is given a single file to compile and link, e.g.,
cc563 test.cc
the compiler knows that all instantiations will have to be done in the single source file. Therefore, it uses the --instantiate used mode and suppresses automatic instantiation.
Instantiation pragmas can be used to control the instantiation of specific template entities or sets of template entities. There are three instantiation pragmas:
The argument to the instantiation pragma may be:
A pragma in which the argument is a template class name (e.g., A<int> or class A<int>) is equivalent to repeating the pragma for each member function and static data member declared in the class. When instantiating an entire class a given member function or static data member may be excluded using the do_not_instantiate pragma. For example,
#pragma instantiate A<int> #pragma do_not_instantiate A<int>::f
The template definition of a template entity must be present in the compilation for an instantiation to occur. If an instantiation is explicitly requested by use of the instantiate pragma and no template definition is available or a specific definition is provided, an error is issued.
template <class T> void f1(T); // No body provided template <class T> void g1(T); // No body provided
void f1(int) {} // Specific definition void main() { int i; double d; f1(i); f1(d); g1(i); g1(d); }
#pragma instantiate void f1(int) // error - specific // definition #pragma instantiate void g1(int) // error - no body // provided
f1(double) and g1(double) will not be instantiated (because no bodies were supplied) but no errors will be produced during the compilation (if no bodies are supplied at link time, a linker error will be produced).
A member function name (e.g., A<int>::f) can only be used as a pragma argument if it refers to a single user defined member function (i.e., not an overloaded function). Compiler-generated functions are not considered, so a name may refer to a user defined constructor even if a compiler-generated copy constructor of the same name exists. Overloaded member functions can be instantiated by providing the complete member function declaration, as in
#pragma instantiate char* A<int>::f(int, char*)
The argument to an instantiation pragma may not be a compiler-generated function, an inline function, or a pure virtual function.
When implicit inclusion is enabled, the C++ compiler is given permission to assume that if it needs a definition to instantiate a template entity declared in a .h file it can implicitly include the corresponding .cc file to get the source code for the definition. For example, if a template entity ABC::f is declared in file xyz.h, and an instantiation of ABC::f is required in a compilation but no definition of ABC::f appears in the source code processed by the compilation, the compiler will look to see if a file xyz.cc exists, and if so it will process it as if it were included at the end of the main source file.
To find the template definition file for a given template entity the C++ compiler needs to know the full path name of the file in which the template was declared and whether the file was included using the system include syntax (e.g., #include <file.h>). This information is not available for preprocessed source containing #line directives. Consequently, the C++ compiler will not attempt implicit inclusion for source code containing #line directives.
By default, the list of definition-file suffixes tried is .cc, .cpp, and .cxx. If -c++ is supplied to the control program cc563, .c is also used as C++ file.
Implicit inclusion works well alongside automatic instantiation, but the two are independent. They can be enabled or disabled independently, and implicit inclusion is still useful when automatic instantiation is not done.
The implicit inclusion mode can be turned on by the command-line option --implicit_include--implicit_include.
Implicit inclusions are only performed during the normal compilation of a file, (i.e., not when doing only preprocessing). A common means of investigating certain kinds of problems is to produce a preprocessed source file that can be inspected. When using implicit inclusion it is sometimes desirable for the preprocessed source file to include any implicitly included files. This may be done using the --no_preproc_only command line option. This causes the preprocessed output to be generated as part of a normal compilation. When implicit inclusion is being used, the implicitly included files will appear as part of the preprocessed output in the precise location at which they were included in the compilation.
The C++ compiler defines a number of preprocessing macros. Many of them are only defined under certain circumstances. This section describes the macros that are provided and the circumstances under which they are defined.
All C predefined macros are also defined.
__STDC__ Defined in ANSI C mode and in C++ mode. In C++ mode the value may be redefined. Not defined when embedded C++ is used.
__FILE__ "current source filename"
__LINE__ current source line number (int type)
__TIME__ "hh:mm:ss"
__DATE__ "Mmm dd yyyy"
_MODEL identifies for which memory model the module is compiled.
_DEFMEM identifies the default data memory.
_STKMEM identifies the data memory used for the stack; this is either default data memory, or L memory.
__cplusplus Defined in C++ mode.
c_plusplus Defined in default C++ mode, but not in strict mode.
__STDC_VERSION__
Defined in ANSI C mode with the value 199409L. The name of this macro, and its value, are specified in Normative Addendum 1 of the ISO C Standard.
__SIGNED_CHARS__
Defined when plain char is signed. This is used in the <limits.h>
header file to get the proper definitions of CHAR_MAX and
CHAR_MIN.
_WCHAR_T Defined in C++ mode when wchar_t is a keyword.
_BOOL Defined in C++ mode when bool is a keyword.
__ARRAY_OPERATORS
Defined in C++ mode when array new and delete are enabled.
__EXCEPTIONS
Defined in C++ mode when exception handling is enabled.
__RTTI Defined in C++ mode when RTTI is enabled.
__PLACEMENT_DELETE
Defined in C++ mode when placement delete is enabled.
__NAMESPACES
Defined in C++ mode when namespaces are supported (--namespaces).
__TSW_RUNTIME_USES_NAMESPACES
__TSW_IMPLICIT_USING_STD
__TSW_CPP__
Always defined.
__TSW_CPP_VERSION__
Defined to an integral value that represents the version number of the C++ front end. For example, version 2.37 is represented as 237.
__embedded_cplusplus
Defined as 1 in Embedded C++ mode.
It is often desirable to avoid recompiling a set of header files, especially when they introduce many lines of code and the primary source files that #include them are relatively small. The C++ compiler provides a mechanism for, in effect, taking a snapshot of the state of the compilation at a particular point and writing it to a disk file before completing the compilation; then, when recompiling the same source file or compiling another file with the same set of header files, it can recognize the "snapshot point", verify that the corresponding precompiled header (PCH) file is reusable, and read it back in. Under the right circumstances, this can produce a dramatic improvement in compilation time; the trade-off is that PCH files can take a lot of disk space.
When --pch appears on the command line, automatic precompiled header processing is enabled. This means the C++ compiler will automatically look for a qualifying precompiled header file to read in and/or will create one for use on a subsequent compilation.
The PCH file will contain a snapshot of all the code preceding the "header stop" point. The header stop point is typically the first token in the primary source file that does not belong to a preprocessing directive, but it can also be specified directly by #pragma hdrstop (see below) if that comes first. For example:
#include "xxx.h" #include "yyy.h" int i;
The header stop point is int (the first non-preprocessor token) and the PCH file will contain a snapshot reflecting the inclusion of xxx.h and yyy.h. If the first non-preprocessor token or the #pragma hdrstop appears within a #if block, the header stop point is the outermost enclosing #if. To illustrate, heres a more complicated example:
#include "xxx.h" #ifndef YYY_H #define YYY_H 1 #include "yyy.h" #endif #if TEST int i; #endif
Here, the first token that does not belong to a preprocessing directive is again int, but the header stop point is the start of the #if block containing it. The PCH file will reflect the inclusion of xxx.h and conditionally the definition of YYY_H and inclusion of yyy.h; it will not contain the state produced by #if TEST.
A PCH file will be produced only if the header stop point and the code preceding it (mainly, the header files themselves) meet certain requirements:
// xxx.h class A {
// xxx.C #include "xxx.h" int i; };
// yyy.h static
// yyy.C #include "yyy.h" int i;
When the host system does not support memory mapping, so that everything to be saved in the precompiled header file is assigned to preallocated memory (MS-Windows), two additional restrictions apply:
When a precompiled header file is produced, it contains, in addition to the snapshot of the compiler state, some information that can be checked to determine under what circumstances it can be reused. This includes:
This information comprises the PCH prefix. The prefix information of a given source file can be compared to the prefix information of a PCH file to determine whether the latter is applicable to the current compilation.
As an illustration, consider two source files:
// a.cc #include "xxx.h" ... // Start of code // b.cc #include "xxx.h" ... // Start of code
When a.cc is compiled with --pch, a precompiled header file named a.pch is created. Then, when b.cc is compiled (or when a.cc is recompiled), the prefix section of a.pch is read in for comparison with the current source file. If the command line options are identical, if xxx.h has not been modified, and so forth, then, instead of opening xxx.h and processing it line by line, the C++ compiler reads in the rest of a.pch and thereby establishes the state for the rest of the compilation.
It may be that more than one PCH file is applicable to a given compilation. If so, the largest (i.e., the one representing the most preprocessing directives from the primary source file) is used. For instance, consider a primary source file that begins with
#include "xxx.h" #include "yyy.h" #include "zzz.h"
If there is one PCH file for xxx.h and a second for xxx.h and yyy.h, the latter will be selected (assuming both are applicable to the current compilation). Moreover, after the PCH file for the first two headers is read in and the third is compiled, a new PCH file for all three headers may be created.
When a precompiled header file is created, it takes the name of the primary source file, with the suffix replaced by an implementation-specified suffix (pch by default). Unless --pch_dir is specified (see below), it is created in the directory of the primary source file.
When a precompiled header file is created or used, a message such as
"test.cc": creating precompiled header file "test.pch"
is issued. The user may suppress the message by using the command-line option --no_pch_messages.
When the --pch_verbose option is used the C++ compiler will display a message for each precompiled header file that is considered that cannot be used giving the reason that it cannot be used.
In automatic mode (i.e., when --pch is used) the C++ compiler will deem a precompiled header file obsolete and delete it under the following circumstances:
This handles some common cases; other PCH file clean-up must be dealt with by other means (e.g., by the user).
Support for precompiled header processing is not available when multiple source files are specified in a single compilation: an error will be issued and the compilation aborted if the command line includes a request for precompiled header processing and specifies more than one primary source file.
Command-line option --create_pch file-name specifies that a precompiled header file of the specified name should be created.
Command-line option -- use_pch file-name specifies that the indicated precompiled header file should be used for this compilation; if it is invalid (i.e., if its prefix does not match the prefix for the current primary source file), a warning will be issued and the PCH file will not be used.
When either of these options is used in conjunction with --pch_dir, the indicated file name (which may be a path name) is tacked on to the directory name, unless the file name is an absolute path name.
The --create_pch, -- use_pch, and --pch options may not be used together. If more than one of these options is specified, only the last one will apply. Nevertheless, most of the description of automatic PCH processing applies to one or the other of these modes -- header stop points are determined the same way, PCH file applicability is determined the same way, and so forth.
There are several ways in which the user can control and/or tune how precompiled headers are created and used.
#include "xxx.h" #include "yyy.h" #pragma hdrstop #include "zzz.h"
Moreover, when the host system does not support memory mapping and preallocated memory is used instead, then one of the command-line options --pch, --create_pch, or --use_pch, if it appears at all, must be the first option on the command line.
The relative overhead incurred in writing out and reading back in a precompiled header file is quite small for reasonably large header files.
In general, it does not cost much to write a precompiled header file out even if it does not end up being used, and if it is used it almost always produces a significant speedup in compilation. The problem is that the precompiled header files can be quite large (from a minimum of about 250K bytes to several megabytes or more), and so one probably does not want many of them sitting around.
Thus, despite the faster recompilations, precompiled header processing is not likely to be justified for an arbitrary set of files with nonuniform initial sequences of preprocessing directives. Rather, the greatest benefit occurs when a number of source files can share the same PCH file. The more sharing, the less disk space is consumed. With sharing, the disadvantage of large precompiled header files can be minimized, without giving up the advantage of a significant speedup in compilation times.
Consequently, to take full advantage of header file precompilation, users should expect to reorder the #include sections of their source files and/or to group #include directives within a commonly used header file.
Below is an example of how this can be done. A common idiom is this:
#include "comnfile.h" #pragma hdrstop #include ...
where comnfile.h pulls in, directly and indirectly, a few dozen header files; the #pragma hdrstop is inserted to get better sharing with fewer PCH files. The PCH file produced for comnfile.h can be a bit over a megabyte in size. Another idiom, used by the source files involved in declaration processing, is this:
#include "comnfile.h" #include "decl_hdrs.h" #pragma hdrstop #include ...
decl_hdrs.h pulls in another dozen header files, and a second, somewhat larger, PCH file is created. In all, the source files of a particular program can share just a few precompiled header files. If disk space were at a premium, you could decide to make comnfile.h pull in all the header files used -- then, a single PCH file could be used in building the program.
Different environments and different projects will have different needs, but in general, users should be aware that making the best use of the precompiled header support will require some experimentation and probably some minor changes to source code.