ICE筆記(04):slice2cpp 及編譯、運行

colorado

 

slice2cpp 命令行語法:
<compiler-name> [options] file…

1、通用的命令行選項是:
• -h, --help
顯示幫助信息。
• -v, --version
顯示編譯器版本。
• -DNAME
定義預處理器符號NAME。
• -DNAME=DEF
定義預處理器符號NAME,其值爲DEF。
• -UNAME
解除預處理器符號NAME 的定義。
• -IDIR
在#include 指令的搜索路徑中增加目錄DIR。
• E
在stdout上打印預處理器輸出。
• --output-dir DIR
把生成的文件放進目錄DIR。
• -d, --debug
打印調試信息,顯示Slice分析器的操作。
• --ice
啓用正常情況下保留的標識符前綴Ice。應該只在編譯Ice 運行時的源碼時使用這個選項。

Slice 編譯器允許你編譯不止一個源文件,所以你可以同時編譯若干Slice 定義:
slice2cpp -I. file1.ice file2.ice file3.ice

2、slice2cpp特定命令行選項:
• --header-ext EXT
把生成的頭文件擴展名從缺省的h 變成EXT 所指定的擴展名。
你也可以用全局元數據指令修改頭文件擴展名:
[["cpp:header-ext:hpp"]]
// ...
每個源文件中僅能有一個這種指令。如果既在命令行上指定了頭文件擴展名,又用元數據指令指定了頭文件擴展名,則元數據指令優先。這確保了分別編譯的Slice文件能得到正確的頭文件擴展名(假定Slice文件包含一個相應的元數據指令)。例如:
// File example.ice
#include <Ice/BuiltinSequences.ice>
// ...
以如下命令行編譯本文件
$ slice2cpp --header-ext=hpp -I/opt/Ice/include example.ice
生成example.hpp, 但是該文件中的 #include 指令包含了Ice/BuiltinSequences.h (而不是Ice/BuiltinSequences.hpp),因爲BuiltinSequences.ice包含了元數據指令[[”cpp:header-ext:h”]]。
你通常不需要使用該元數據指令,僅當如下條件時該指令纔是必須的:
• 你 #include 自己Slice文件集中的一個Slice文件。
• 被包含的 Slice文件是你要鏈接的庫的一部分。
• 庫帶有被包含的Slice文件的頭文件。
• 庫頭文件使用了與你自己代碼不同的頭文件擴展名。
例如,如果庫使用.hpp作爲頭文件擴展名,但你自己的代碼使用.h,庫的Slice文件應該包含[[”cpp:header-ext:hpp”]]指令。(如果該指令丟失,你要爲庫的Slice文件加上它。)

• --source-ext EXT
把生成的源文件的文件擴展名從缺省的cpp 變成EXT 所指定的擴展名。

• --add-header HDR[,GUARD]
該選項爲生成的源文件開頭添加包含指定頭文件的指令(先於任何其它包含指令)。如果指定GUARD,包含指令被指定標識符保護。例如: --add-header precompiled.h,__PRECOMPILED_H__
在生成源文件的開始產生上面的指令:
#ifndef __PRECOMPILED_H__
#define __PRECOMPILED_H__
#include <precompiled.h>
#endif
該選項可以爲多個文件重複創建包含指令。如上例所推薦的那樣,該選項主要是以編譯器的預編譯頭機制整合生成的代碼。

• --include-dir DIR
修改源文件中#include指令,爲每個頭文件添加DIR目錄下的路徑名。

• --impl
生成示範性的實現文件,這個選項不會覆蓋已有文件。

• --depend
把makefile依賴信息打印到標準輸出。指定該選項時不產生代碼。輸出在包含進makefile之前通常需要過濾;Ice構建系統爲此使用了腳本config/makedepend.py。

• --dll-export SYMBOL
使用SYMBOL控制DLL輸入、輸出。該選項允許你在生成的代碼中分別輸入、輸出全局符號。例如,用下面的命令編譯Slice定義:
$ slice2cpp --dll-export ENABLE_DLL x.ice
會在x.h中產生如下額外的代碼:
#ifndef ENABLE_DLL
# ifdef ENABLE_DLL_EXPORTS
# define ENABLE_DLL ICE_DECLSPEC_EXPORT
# else
# define ENABLE_DLL ICE_DECLSPEC_IMPORT
# endif
#endif
ICE_DECLSPEC_EXPORT 和 ICE_DECLSPEC_IMPORT 是平臺特定的宏。例如,在Windows平臺上,它們被分別定義爲__declspec(dllexport) 和 __declspec(dllimport);在使用CC 5.5以上版本的Solaris平臺上, ICE_DECLSPEC_EXPORT 被定義爲 __global,ICE_DECLSPEC_IMPORT 是空。

你在命令行指定的,被生成代碼用來輸入、輸出符號的符號名,在生成的編譯單元外面也必須是對代碼可見的。實際效果是,如果你要創建包含x.cpp的DLL,也要在DLL之外的編譯單元中使用生成類型,要使用-DENABLE_DLL_EXPORTS來編譯x.cpp,這樣纔可以輸出相關符號。

• --checksum
爲Slice定義生成檢查和。

• --stream
爲Slice類型生成流助手函數。

3、包含指令
由Slice到C++編譯器生成的#include指令,若這種指令生成的語義沒有被充分理解的話,會是混亂之源。生成的#include指令受命令行選項-I 和 --include-dir的影響;這些選項在下面詳細討論。--output-dir選項指定編譯器將所有生成文件放入一個特定目錄,但是不會影響生成代碼的內容。

在頭文件和源代碼中#inlcude指令使用不同的語義生成。
⑴、頭文件
大多數情況下,編譯器缺省生成適當的#inlcude指令。例如,假定文件A.ice包含B.ice,使用如下的語句:
// A.ice
#include <B.ice>
假定兩個文件都在當前工作目錄下,我們如下運行編譯器:
$ slice2cpp -I. A.ice
生成的文件A.h包含#include指令:
// A.h
#include <B.h>
如果爲C++編譯器指定合適的包含路徑,編譯將會正確進行。
類似地,考慮常見情況,A.ice包含子目錄中的B.ice:
// A.ice
#include <inc/B.ice>
假定兩個文件都在inc子目錄中,我們如下運行編譯器:
$ slice2cpp -I. inc/A.ice
編譯器缺省輸出產生了如下所示A.h中的#inlcude指令:
// A.h
#include <inc/B.h>
強調一下,這裏需要配置C++編譯器,以確保編譯期間能夠找到inc/B.h。

現在,讓我們考慮一個更復雜的例子,我們不想要頭文件中的#include指令匹配Slice文件。當Slice文件的組織結構不匹配應用程序的C++代碼時,這是必須的。這種情況下,用戶可能需要從它們創建的目錄中重新定位生成的文件,且#include指令必須匹配新結構。

例如,讓我們假定B.ice位於子目錄slice/inc:
// A.ice
#include <slice/inc/B.ice>
但是,我們不想要slice子目錄出現在生成的頭文件的#include指令中,因此我們指定額外的編譯選項-Islice:
$ slice2cpp -I. -Islice slice/inc/A.ice
生成的代碼顯示了該額外選項的影響:
// A.h
#include <inc/B.h>
如你所見,生成頭文件中的#inlcude指令受到運行編譯器時指定的包含路徑的影響。特別是,當包含路徑在生成的#inlcude指令中使用了路徑名縮寫時,更是如此。當編譯#include指令時,編譯器比較每個包含路徑和已包含文件的路徑。如果包含路徑匹配已包含文件路徑的前導部分,編譯器就刪除#include路徑的前導部分。如果匹配一個以上的包含路徑,編譯器的選擇是已包含文件中最短的路徑。

例如,假定我們編譯A.ice時使用下面選項:
$ slice2cpp -I. -Islice -Islice/inc slice/inc/A.ice
這種情況下,編譯器對所有包含目錄和已包含的文件slice/inc/B.ice進行比較,生成下面指令:
// A.h
#include <B.h>
選項-Islice/inc產生最短路徑,因此包含文件(slice/inc/B.h)的缺省路徑被替換爲B.h。

通常,-I選項扮演兩種角色:它允許預處理器定位包含的Slice文件,而且它還爲你在生成#include指令時提供一定程度的控制。上面最後一個例子中,預處理器使用由-I.選項指定的包含路徑定位slice/inc/B.ice。餘下的-I選項不能幫助預處理器定位包含文件;它們只是給編譯器某些提示。

最終,我們推薦謹慎使用包含路徑。如果預處理器能夠通過多個包含路徑定位一個包含文件,它總是首先使用能夠成功定位文件的包含路徑。如果你要通過指定額外的-I選項來修改生成的#inlcude指令,你必須確保你包含路徑的提示能夠匹配預處理器選擇的用於定位包含文件的包含路徑。一般來說,你不應該指定預處理器通過多種途徑定位文件的包含路徑。

⑵、源文件
缺省情況下,編譯器在源文件中生成的#include指令,僅使用包含文件的基本名稱。當源文件和頭文件駐留於同一目錄時,該行爲通常是合適的。
例如,假定A.ice包含子目錄中的B.ice,下面列出了A.ice的一段代碼:
// A.ice
#include <inc/B.ice>
我們使用下列命令生成源文件:
$ slice2cpp -I. inc/A.ice
經檢查,我們看到源文件包含下面#include指令:
// A.cpp
#include <B.h>
但是,假定我們希望爲生成的#include指令強制使用一個特定標準,以便它們兼容我們的C++編譯器的現有包含路徑設置。可以使用--include-dir選項修改生成的代碼。例如,考慮如下的編譯命令:
$ slice2cpp --include-dir src -I. inc/A.ice
源文件現在包含下列#include指令:
// A.cpp
#include <src/B.h>
通常包含文件中的任何前導路徑被丟棄,--include-dir選項值被加入。

4、編譯
以$ICE_HOME/demo/book/printer爲例,Linux平臺上編譯運行的過程:
slice2cpp Printer.ice
生成Printer.h,Printer.cpp

編譯服務器:
c++ -I. -I$ICE_HOME/include -c Printer.cpp Server.cpp
c++ -o server Printer.o Server.o -L$ICE_HOME/lib -lIce -lIceUtil

編譯客戶端:
c++ -I. -I$ICE_HOME/include -c Printer.cpp Client.cpp
c++ -o client Printer.o Client.o -L$ICE_HOME/lib -lIce -lIceUtil

在一個控制檯窗口中運行:
./server
在另一個控制檯窗口中運行:
./client

 

在Windows平臺上,過程大體類似,只是可以使用VC++2008 Express的解決方案編譯C++代碼,更方便。

 

發佈了44 篇原創文章 · 獲贊 5 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章