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.
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.
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
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.
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:
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
nm68k foo.o bar.o | wtxtcl $WIND_BASE/host/src/hutils/munch.tcl \ -asm 68k > ctdt.c cc68k -c ctdt.c
cc68k -r ctdt.o foo.o bar.o -o linkedObjs.o
|
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.
|
||||||||||||||||||
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:
To include one or more of the Wind Foundation Classes, include one or more of the following constants:
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.
|
||||||||||||||||||
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.
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.
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.
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.
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.
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).
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 (); }