5.2   C++ Development Under Tornado

Basic C++ support is bundled with the Tornado development environment. VxWorks provides header files containing C++ safe declarations for all routines and the necessary run-time support. The standard Tornado interactive development tools such as the debugger, the shell, and the incremental loader include C++ support.

5.2.1   Tools Support

WindSh

Tornado supports both C and C++ as development languages. WindSh can interpret simple C++ expressions. To exercise C++ facilities that are missing from the C-expression interpreter, you can compile and download routines that encapsulate the special C++ syntax. See the Tornado User's Guide: Tornado Tools Reference or the HTML online reference for WindSh C++ options.

Demangling

When C++ functions are compiled, the class membership (if any) and the type and number of the function's arguments are encoded in the function's linkage name. This is called name mangling or mangling. The debugging and system information routines in WindSh can print C++ function names in demangled or mangled representations.

The default representation is gnu. In addition, arm and none (no demangling) are available options. To select an alternate mode, modify the Tcl variable shDemangleStyle. For instance:

-> ?set shDemangleStyle none
Overloaded Function Names

When you invoke an overloaded function, WindSh prints the matching functions' signatures and prompts you for the desired function. For more information on how WindSh handles overloaded function names, including an example, see the Tornado User's Guide: Shell.

Debugger

The Tornado debugger supports debugging of C++ class member functions including stepping through constructors and templates. For details, see the Tornado User's Guide: Tornado Tools Reference and Debugging with GDB.

5.2.2   Programming Issues

Making C++ Entry Points Accessible to C Code

If you want to reference a (non-overloaded, global) C++ symbol from your C code you will need to give it C linkage by prototyping it using extern "C":

#ifdef __cplusplus 
extern "C" void myEntryPoint (); 
#else 
void myEntryPoint (); 
#endif

You can also use this syntax to make C symbols accessible to C++ code. VxWorks C symbols are automatically available to C++ because the VxWorks header files use this mechanism for declarations.

5.2.3   Compiling C++ Applications

The Tornado project tool fully supports C++. The recommended way to configure and compile C++ applications is to use the project tool. The information below may be useful for understanding the C++ environment but unless you have a particular reason to use manual methods, you should use the methods explained in the Tornado User's Guide: Projects.

For details on the GNU compiler and on the associated tools, see the GNU ToolKit User's Guide.

When compiling C++ modules with the GNU compiler, invoke ccarch (just as for C source) on any source file with a C++ suffix (such as .cpp). Compiling C++ applications in the VxWorks environment involves the following steps:

  1. Each C++ source file is compiled into object code for your target architecture, just as for C applications. For example, to compile for a 68K target:

cc68k -fno-builtin -I$WIND_BASE/target/h -nostdinc -O2 \ 
    -DCPU=MC68040 -c foo.cpp 
cc68k -fno-builtin -I$WIND_BASE/target/h -nostdinc -O2 \ 
    -DCPU=MC68040 -c bar.cpp

  1. The objects are munched (see 5.2.5 Munching C++ Application Modules). In our example:

nm68k foo.o bar.o | wtxtcl $WIND_BASE/host/src/hutils/munch.tcl \ 
    -asm 68k > ctdt.c 
cc68k -c ctdt.c

  1. The objects are linked with the compiled munch output. (They may be partially linked using -r for downloadable applications or statically linked with a VxWorks BSP for bootable applications.) If you are using the GNU tools, invoke the linker from the compiler driver as follows:

cc68k -r ctdt.o foo.o bar.o -o linkedObjs.o
Here we have linked two objects modules, foo.o and bar.o, to give a downloadable object, linkedObjs.o. Using ccarch rather than ldarch performs template instantiation if you use the -frepo option. (see 5.2.7 Template Instantiation).


*

NOTE: If you use a Wind River Systems makefile to build your application, munching is handled by make.


*

WARNING: In the linking step, -r is used to specify partial linking. A partially linked file is still relocatable, and is suitable for downloading and linking using the VxWorks module loader. The GNU ToolKit User's Guide: Using ld describes a -Ur option for resolving references to C++ constructors. That option is for native development, not for cross-development. Do not use -Ur with C++ modules for VxWorks.

5.2.4   Configuration Constants

By default VxWorks kernels contain the C++ run-time, basic Iostream functionality and support for the Standard Template Library. You may add/remove C++ components by including any of the following macros:

INCLUDE_CPLUS
Includes all basic C++ run-time support in VxWorks. This enables you to download and run compiled and munched C++ modules. It does not configure any of the Wind Foundation Class libraries into VxWorks.

INCLUDE_CPLUS_STL
Includes support for the standard template library.

INCLUDE_CPLUS_STRING
Includes the basic components of the string type library.

INCLUDE_CPLUS_IOSTREAMS
Includes the basic components of the Iostream library.

INCLUDE_CPLUS_COMPLEX
Includes the basic components of the complex type library.

INCLUDE_CPLUS_IOSTREAMS_FULL
Includes the full Iostream library; this implies INCLUDE_CPLUS_IOSTREAMS.

INCLUDE_CPLUS_STRING_IO
Includes string I/O function; this implies INCLUDE_CPLUS_STRING and INCLUDE_CPLUS_IOSTREAMS.

INCLUDE_CPLUS_COMPLEX_IO
Includes I/O for complex number objects; this implies INCLUDE_CPLUS_IOSTREAMS and INCLUDE_CPLUS_COMPLEX.

To include one or more of the Wind Foundation Classes, include one or more of the following constants:

INCLUDE_CPLUS_VXW
Includes the VxWorks Wrapper Class library.

INCLUDE_CPLUS_TOOLS
Includes Rogue Wave's Tools.h++ class library.

For more information on configuring VxWorks, see the Tornado User's Guide: Projects.

5.2.5   Munching C++ Application Modules

Modules written in C++ must undergo an additional host processing step before being downloaded to a VxWorks target. This extra step (called munching, by convention) initializes support for static objects and ensures that when the module is downloaded to VxWorks, the C++ run-time support is able to call the correct constructors and destructors in the correct order for all static objects.

The following commands will compile hello.cpp, then munch hello.o, resulting in the munched file hello.out suitable for loading by the Tornado module loader:

cc68k -IinstallDir/target/h -DCPU=MC68020 -nostdinc -fno-builtin \ 
        -c hello.cpp 
nm68k hello.o | wtxtcl installDir/host/src/hutils/munch.tcl \ 
        -asm 68k > ctdt.c 
cc68k -c ctdt.c 
ld68k -r -o hello.out hello.o ctdt.o


*

NOTE: You can substitute the actual name of your installDir or use $WIND_BASE (UNIX) or %WIND_BASE% (Windows).


*

CAUTION: The GNU ToolKit User's Guide: Using ld describes a -Ur option for resolving references to C++ constructors. That option is for native development, not for cross-development. Do not use -Ur with C++ modules for VxWorks.

5.2.6   Static Constructors and Destructors

After munching, downloading, and linking, the static constructors and destructors must be called.

Calling Static Constructors and Destructors Interactively

VxWorks provides two strategies for calling static constructors and destructors interactively:

automatic
Static constructors are called as a side effect of downloading. Static destructors are called as a side effect of unloading.

manual
Static constructors and destructors are called indirectly by invoking cplusCtors( ) and cplusDtors( ).

Use cplusXtorSet( ) to change the strategy; see its entry in the windsh reference entry for details. To report on the current strategy, call cplusStratShow( ).

Under the automatic strategy, which is the default, static constructors are called immediately after a successful download. If the automatic strategy is set before a module is downloaded, that module's static constructors are called before the module loader returns to its caller. Under the automatic strategy, the module unloader calls a module's static destructors before actually unloading the module.

The manual strategy causes static constructors to be called as a result of invoking cplusCtors( ). Refer to the entries for cplusCtors( ) and cplusDtors( ) in the windsh reference for more information. To invoke all currently-loaded static constructors or destructors, manual mode can be used with no argument. Manual mode can also be used to call static constructors and destructors explicitly on a module-by-module basis.

Constructors and Destructors in System Startup and Shutdown

When you create bootable VxWorks applications, call static constructors during system initialization. Modify the usrRoot( ) routine in usrConfig.c to include a call to cplusCtorsLink( ). This calls all static constructors linked with your system.

To modify usrConfig.c to call cplusCtorsLink( ), locate the C++ initialization sections:

#ifdef INCLUDE_CPLUS           /* C++ product */ 
    cplusLibInit (); 
#endif 
 
#ifdef INCLUDE_CPLUS_MIN       /* C++ product */ 
    cplusLibMinInit (); 
#endif

Next, add cplusCtorsLink( ) to one or both sections, depending on your system requirements. In the following example, cplusCtorsLink( ) is called only when minimal C++ is configured:

#ifdef INCLUDE_CPLUS_MIN       /* C++ product */ 
    cplusLibMinInit (); 
    cplusCtorsLink (); 
#endif


*

CAUTION: Static objects are not initialized until the call to cplusCtorsLink( ). Thus, if your application uses static objects in usrRoot( ), call cplusCtorsLink( ) before using them.

For cplusCtorsLink( ) to work correctly, you must perform the munch operation on the fully-linked VxWorks image rather than on individual modules.

A corresponding routine, cplusDtorsLink( ), is provided to call all static destructors. This routine is useful in systems that have orderly shutdown procedures. Include a call to cplusDtorsLink( ) at the point in your code where it is appropriate to call all static destructors that were initially linked with your system.

The cplusCtorsLink( ) and cplusDtorsLink( ) routines do not call static constructors and destructors for modules that are downloaded after system initialization. If your system uses the module downloader, follow the procedures described in Calling Static Constructors and Destructors Interactively.

5.2.7   Template Instantiation

Our C++ toolchain supports three distinct template instantiation strategies. The simplest (and the one that is used by default in VxWorks makefiles) is implicit instantiation. In this case code for each template gets emitted in every module that needs it. For this to work the body of a template must be available in each module that uses it. Typically this is done by including template function bodies along with their declarations in a header file. The disadvantage of implicit instantiation is that it may lead to code duplication and larger application size.

The second approach is to explicitly instantiate any templates you require using the syntax found in Example 5-1. In this case you should compile with -fno-implicit-templates. This scheme allows you the most control over where templates get instantiated and avoids code bloat.

-frepo

This approach combines the simplicity of implicit instantiation with the smaller footprint obtained by instantiating templates by hand. It works by manipulating a database of template instances for each module.

The compiler will generate files with the extension .rpo; these files list all the template instantiations used in the corresponding object files which could be instantiated there. The link wrapper collect2 then updates the .rpo files to tell the compiler where to place those instantiations and rebuilds any affected object files. The link-time overhead is negligible after the first pass, as the compiler continues to place the instantiations in the same files.

Procedure

The header file for a template must contain the template body. If template bodies are currently stored in .cpp files, the line #include theTemplate.cpp must be added to theTemplate.h.

A full build with the -frepo option is required to create the .rpo files that tell the compiler which templates to instantiate. The link step should be driven from ccarch rather than ldarch.

Subsequently individual modules can be compiled as usual (but with the -frepo option and no other template flags).

When a new template instance is required the relevant part of the project must be rebuilt to update the .rpo files.

Loading Order

The Tornado tools' dynamic linking ability requires that the module containing a symbol definition be downloaded before a module that references it. For instance, in the example below you should download PairA.o before downloading PairB.o. (You could also prelink them and download the linked object).

Example

This example uses a standard VxWorks BSP makefile (for concreteness, we assume a 68K target).

Example 5-1:  Sample Makefile

make PairA.o PairB.o ADDED_C++FLAGS=-frepo  
 
/* dummy link step to instantiate templates */ 
cc68k -r -o Pair PairA.o PairB.o 
 
/* In this case the template Pair<int>::Sum(void)  
 * will be instantiated in PairA.o.  
 */ 
 
//Pair.h 
 
template <class T> class Pair 
{ 
public: 
    Pair (T _x, T _y); 
    T Sum (); 
 
protected: 
    T x, y; 
}; 
 
template <class T> 
Pair<T>::Pair (T _x, T _y) : x (_x), y(_y) 
{ 
} 
 
template <class T> 
T Pair<T>::Sum () 
{ 
    return x + y; 
}  
// PairA.cpp 
#include "Pair.h" 
 
int Add (int x, int y) 
{ 
    Pair <int> Two (x, y); 
    return Two.Sum (); 
} 
 
// PairB.cpp 
#include "Pair.h" 
 
int Double (int x) 
{ 
Pair <int> Two (x, x); 
return Two.Sum (); 
}