1. 程式人生 > >[轉帖] 在Tornado下的C++開發

[轉帖] 在Tornado下的C++開發


5.2 在Tornado下的C++開發
基本的C++支援被捆綁在Tornado開發環境裡。VxWorks提供了包含對所有程式的C++安全宣告的標頭檔案和必須的run-time support.標準的Tornado互動式開發工具如偵錯程式(debugger),shell,和新增的載入器(loader)都包含了對C++的支援。


5.2.1 工具支援

WindSh
Tornado支援C和C++開發語言.WindSh能夠解釋簡單的C++表示式。為了練習在C表示式解釋程式(C-expression interpreter)中缺少的C++功能,你可以編譯並下載按專門的C++語法封裝的程式。參見《Tornado

 User's Guide:Tornado Tools Reference》或者WindSh C++的線上參考。

Demangling
當C++函式被編譯時,類的成員數(如果有)和函式引數的型別、個數被封裝到函式的連線程式名(linkage name)中。這成為name mangling或者mangling。在WindSh中的除錯和系統資訊能夠按demangled或者mangled顯示的方式打印出C++函式名。
預設的顯示是gnu.另外arm和none(no demangling)是可選項。為了選擇另外的模式,改變Tcl變數shDemangleStyle.
舉例:
-> ?set shDemangleStyle none
過載的函式名
當你呼叫一個過載函式時,Windsh打印出匹配的函式的符號並提示你輸入想要得函式。更多的關於WindSh如何處理過載函式名,包括例子的資訊參見《Tornado

 User's Guide: Shell》

偵錯程式
Tornado偵錯程式能夠除錯C++成員函式,包括在建構函式和模板中的單步除錯。關於細節,參見《Tornado User'sGuide: Tornado Tools Reference and Debugging with GDB》.

5.2.2 程式設計問題(Programming Issues)

使C++入口點在C程式碼中可用
如果想從C程式碼中引用一個(非過載的,全域性的)C++物件(symbols),則必須通過使用extern "C"進行原型說明使得C連線程式知道它:
#ifdef __cplusplus
extern "C" void myEntryPoint();
#else
void myEntryPoint();
#endif
也可使用這種語法來實現在C++程式碼中呼叫C物件(symbols)。VxWorks中的C物件在C++中是可被呼叫的,因為VxWorks標頭檔案對其宣告使用了這種機制。

5.2.3 編譯C++應用程式
Tornado專案工具(project tool)完全支援C++.配置和編譯C++程式推薦使用專案工具。下面的資訊對於理解C++環境是有用的。除非有特殊原因而使用人工方法,否則應該使用在《Tornado User's Guide: Projects》中說明的方法。
關於GNU編譯器和相關工具的細節,參見《GNU ToolKit User's Guide》。
當使用GNU編譯編譯C++模組時,在每個帶有C++字尾(如.cpp)的原始檔上呼叫ccarch(正像對C原始碼).在VxWorks環境中編譯C++程式包括如下步驟:
1.每個C++原始碼檔案被編譯成目的碼,就像C程式一樣。舉例編譯一個68K目標:
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
2.目的碼被munch(參見Munching C++ Application Modules).在我們的例子中:
nm68k foo.o bar.o | wtxtcl $WIND_BASE/host/src/hutils/munch.tcl \ 
-asm 68k > ctdt.c 
cc68k -c ctdt.c
3.目的碼和已編譯的munch輸出連線在一起。(對於可下載的應用程式,它們可使用引數-r區域性的(partially)連線在一起;對於可啟動的應用程式,它們可靜態的與VxWorks BSP連線在一起。)如果使用GNU工具,如下可從編譯器驅動中呼叫聯結器:
cc68k -r ctdt.o foo.o bar.o -o linkedObjs.o
這裡連線兩個目標模組,foo.o和bar.o,生成可下載的目的碼,linkedObjs.o。如果使用選項-frepo,則使用ccarch而不是ldarch來例項化模板。(參見5.2.7 Template Instantiation)

注意:如果使用Wind River System makefile來構造應用程式,munching是通過make來執行。

小心:在連線步驟中,-r用來制定區域性連線。一個區域性的連線檔案仍然是可重定位的,也適合使用VxWorks模組載入器來下載和連線。《GNU ToolKit User's Guide: Using ld》中描述的選項-Ur是為了解析涉及到的C++建構函式。這個選項用於本地開發(native development),而不是交叉開發(cross-development).VxWorks的C++模組不使用選項-Ur。

5.2.4 配置常量
通常VxWorks核心包括C++ run-time, 基本Iostream和對STL的支援.通過包含如下的巨集來增/刪C++組成:

INCLUDE_CPLUS 
包括所有的基本C++ run-time support.這就可以下載和執行已編譯的,munched C++模組.這不會配置任何Wind基類庫進入VxWorks.

INCLUDE_CPLUS_STL
包括對STL的支援.

INCLUDE_CPLUS_STRING
包括字串型別庫的基本元件.

INCLUDE_CPLUS_IOSTREAMS
包括Iostream庫的基本元件.

INCLUDE_CPLUS_COMPLEX
包括複數(complex)型別庫的基本元件.

INCLUDE_CPLUS_IOSTREAMS_FULL
包括完全的Iostream庫;這意味著也定義了INCLUDE_CPLUS_IOSTREAMS.

INCLUDE_CPLUS_STRING_IO
包括字串的輸入/輸出函式;這意味著也定義了INCLUDE_CPLUS_STRING和INCLUDE_CPLUS_IOSTREAMS.

INCLUDE_CPLUS_COMPLEX_IO
包括對複數物件的輸入/輸出;這意味著也定義了INCLUDE_CPLUS_IOSTREAMS和INCLUDE_CPLUS_COMPLEX.

為了包括一個或多個Wind基類,包括一個或多個如下的常量:

INCLUDE_CPLUS_VXW
包括VxWorks Wrapper類庫.

INCLUDE_CPLUS_TOOLS
包括Rogue Wave的Tools.h++類庫.

關於配置VxWorks的更多資訊,參見《Tornado User's Guide: Projects》.

5.2.5 Munching C++應用程式模組
用C++寫的模組在下載到VxWorks目標機之前必須經歷額外的主機程序步驟。這個額外的步驟(稱作munching)初始化靜態物件並保證當該模組被下載到VxWorks時,C++的run-time support對所有的靜態物件能按照恰當的順序呼叫正確建構函式和解構函式。
如下的命令編譯hello.cpp,然後munch hello.o,結果在已munch的檔案hello.out,它可通過Tornado模組載入器載入:

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

注意:可用實際的路徑名或者$WIND_BASE(UNIX)或%WIND_BASE%(Windows)來替換installDir。

小心:《GNU ToolKit User's Guide: Using ld》描述選項-Ur來解析涉及到的C++建構函式. 這個選項用於本地開發 (native development),而不是交叉開發(cross-development).VxWorks的C++模組不使用選項-Ur。

5.2.6 靜態建構函式和解構函式
在munching,下載和連線後,必須呼叫靜態建構函式和解構函式。

呼叫靜態建構函式和解構函式的方法
VxWorks提供了兩種方法來呼叫靜態建構函式和解構函式:[這兩種方法是互補的(interactively)]
自動:呼叫靜態建構函式認為是下載的side effect;呼叫靜態的解構函式認為是解除安裝的side effect。
人工:通過呼叫cplusCtors()和cplusDtors()來呼叫靜態建構函式和解構函式。
呼叫cplusXtorSet()來改變方法;在windsh參考的條目中檢視它的細節。呼叫cplusStratShow()來顯示當前方法.
在自動方法下,它是預設的,靜態建構函式在成功下載後被立即呼叫。如果在模組下載前設定為自動方法,模組的靜態建構函式在模組裝載器返回到它的呼叫者之前就被呼叫。在自動方法下,模組解除安裝器在實際解除安裝模組前呼叫模組的靜態解構函式。
人工方法引起呼叫靜態建構函式是作為呼叫cplusCtors()的結果.在windsh參考中可找到關於函式cplusCtors()和cplusDtors()的更多細節。為了呼叫當前載入的靜態建構函式和解構函式,使用人工模式時不帶引數。人工模式也能在模組上逐一呼叫靜態建構函式和解構函式。

在系統開始和結束時建構函式和解構函式
當你建立可啟動的VxWorks應用程式時,在系統初始化期間呼叫靜態建構函式。更改在usrConfig.c中的函式usrRoot()使它包括對cplusCtorsLink()的呼叫.這就呼叫了所有的已連線到系統的靜態建構函式。
為了修改usrConfig.c來呼叫cplusCtorsLink(),查詢C++初始化部分:
#ifdef INCLUDE_CPLUS /* C++ product */ 
cplusLibInit (); 
#endif 

#ifdef INCLUDE_CPLUS_MIN /* C++ product */ 
cplusLibMinInit (); 
#endif
接下來,增加cplusCtorsLink()到一個或兩個部分,這取決於系統需求.在如下的例子中,僅當配置了最小C++時才呼叫cplusCtorsLink():
#ifdef INCLUDE_CPLUS_MIN /* C++ product */ 
cplusLibMinInit (); 
cplusCtorsLink (); 
#endif
注意:靜態物件不會被初始化除非呼叫了cplusCtorsLink().因而,如果應用程式在usrRoot()中使用了靜態物件,那麼應該在使用它們之前呼叫cplusCtorsLink()。
為了使得cplusCtorsLink()正確執行,必須在完全連線的VxWorks映像上而不是單個的模組上執行munch操作。

相應地函式cplusDtorsLink()用來呼叫所有的靜態解構函式。這個函式在需要依序解除安裝程序的系統中是有用的。
在程式碼中,在適合呼叫所有靜態解構函式的地方包含對cplusDtorsLink()的呼叫,這些靜態解構函式是最初連線到系統中的。
函式cplusCtorsLink()和cplusDtorsLink()不會呼叫在系統初始化完後下載的模組的靜態建構函式和解構函式。如果系統使用了模組下載器,以下的過程在<呼叫靜態建構函式和解構函式的方法>中描述。

5.2.7 模板例項化
C++工具箱(toolchain)支援三種不同的模板例項化方法。最簡單的(這也是在VxWorks的makefiles裡預設使用的方法)是隱式例項化(imlicit instantiation).在這種方法下,每個模板的程式碼在每個需要它的模組中展開。為了使之工作,模板的實現部分必須在每個使用它的模組中可見。這通常通過在標頭檔案中包含模板功能實現部分以及它們的
宣告來實現。隱式例項化的缺點是它會導致程式碼複製和應用程式過大。
第二種方法是使用在例5-1中的語法來顯示例項化所需要的任何模板。在這種方法下,編譯時應使用選項-fno-implicit-templates。這種設計允許你對在何處例項化模板有最大的控制,並避免程式碼膨脹。

-frepo
手動例項化模板的方法把隱式例項化的簡單和獲得的更小的覆蓋面(footprint)結合在一起。通過操作每個模組的模板例項資料庫來工作。
編譯器將產生副檔名為.rpo的檔案;這些檔案列舉了所有的模板例項,這些模板例項在那兒能夠被例項化的相應的目標檔案中使用。編譯器連線wrapper collect2,然後更新.rpo檔案告訴編譯器何處安放這些例項並重新構造任何受到影響的目標檔案。在同一個檔案中當編譯器繼續安置例項時,連線時的開銷(link-time overhead)在第一次通過時是可忽略的。

過程(procedure)
模板標頭檔案必須包含模板實現部分。通常如果模板實現部分儲存在.cpp檔案中,#include theTemplate.cpp必須新增到模板標頭檔案中。
帶有選項=frepo的完全構造必須建立.rpo檔案,該檔案告訴編譯器哪個模板例項化。應該由ccarch而不是ldarch來啟動連線步驟。
隨後單獨模組如平常一樣被編譯(但是帶有選項-frepo沒有其他模板引數)。
當有新的模板例項時,專案的相關部分必須重新構建來更新.rpo檔案。
載入順序
Tornado工具的動態連線能力要求模組在引用被下載的物件(symbol)前包含對該物件的定義。舉個例子,在下面的例子中,應該在下載PairB.o前下載PairA.o。(也應該預先連線它們和下載已連線的目標)

例子
這個例子使用標準的VxWorks BSP makefile(為了具體化,假定一個68K目標).

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>:air (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 (); 
}