我是C++語言的忠實擁躉,由于在上學時經歷了資源匱乏的DOS時代,對C/C++這種更加接近硬件的語言由衷的喜愛。一直以來也是已C++作為工作的語言,對別的語言那是不屑一顧。在java火爆流行的時候,沒有去深入了解過。現在看其實是一種損失,若非如此這篇博文或許能早幾年就寫出來了。然后由于工作的關系學了一點C#,在看到關于元數據的時候,萌生了在C++中實現類似功能的念頭。后來接觸過一些腳本語言,發現借助元數據是實現C++和腳本語言混合編程的好辦法。
最初的時候,我嘗試使用模板來實現這樣的功能。經過一段時間的實踐后,發現有些問題不易解決,而且用起來也不太方便,寫了一半就放棄了。后來聯想到微軟使用idl這種接口描述語言來定義COM接口,決定使用類似的方法。大體就是定義一種接口描述語言,通過相應的編譯器生成對應的C++頭文件以及元數據描述代碼,同時提供一個運行時庫作為使用這些元數據的基礎。這個編譯器就是idlcpp,意為用接口描述語言生成C++代碼,當然此處的idl不是微軟的idl,只不過因意義相似,也用了同樣的英文簡寫。
此idl語言到目前為止支持如下概念:命名空間,類和結構,數據成員,屬性,方法,靜態成員,虛函數,函數重載,運算符重載,多重繼承,枚舉,模板等。其中關鍵字大部分照抄的C++,所以乍看起來比較像C++代碼。
除了idlcpp這個編譯器外,還有一個基礎的運行時庫,以及針對不同的腳本語言相應的插件(目前只有lua和python),使用的開發工具是Visual Studio 2015,對非MS平臺不太熟悉,所以暫時編譯器只支持Windows平臺(用到了一些Windows特有的函數)。不過運行時庫沒有用到特定平臺的功能,較易移植到其他平臺。此外還寫了一些示例代碼。上述所有代碼托管在github上:https://github.com/fdyjfd/idlcpp/,另外還建了一個網站:http://idlcpp.org/ 目前網站還沒什么內容,以后慢慢去豐富。
下面進入正題,先從工具的使用開始。
Idlcpp命令行工具
Idlcpp可以從github上下載代碼編譯得到,另外我也在網上放了一份已經編譯好的執行文件,可以從 https://files.cnblogs.com/files/fdyjfd/idlcpp.zip 下載直接使用。若要自己編譯idlcpp,請先從github上獲取源代碼。源代碼結構如下:

其中idlcpp目錄下是idlcpp的源代碼。paf目錄下是基礎運行時庫與腳本插件的代碼。tutorials下是一些示例教程。目錄bin是用來放置編譯生成的dll及exe文件的,示例的lua和python腳本也放在這里。
編譯idlcpp要用到第三方工具flex和bison。這兩個工具可以從 https://sourceforge.net/projects/gnuwin32/ 下載。安裝這兩個工具后將其所在目錄設置到環境變量Path中,以便編譯時可以找到它們。編譯成功后會在bin目錄下生成idlcpp.exe。也可以下載我上傳的以編譯好的zip壓縮包,將其解壓到bin目錄下,然后將bin目錄也設置到環境變量Path中;或者將其解壓到windows目錄下供后面使用。
idlcpp通過編譯接口描述文件(默認擴展名為.i),生成4個C++代碼文件,分別是:
1. 相應的頭文件(默認擴展名為.h)。
2. 內置函數的實現文件(默認擴展名為.ic)。
3. 元數據包裝類的頭文件(默認擴展名為.mh)。
4. 元數據包裝類的實現文件(默認擴展名為.mc)。
運行cmd,進入idlcpp所在目錄,運行命令idlcpp –h,結果如下圖所示:

各選項含義為:
-h 顯示幫助信息。
-ld 在生成的頭文件中加入 #line 指令,用于編譯器發現錯誤時正確定位到 .i文件中的對應位置。
-pc 指定運行時庫pafcore頭文件所在的路徑。
-mp 元數據包裝類的名字是根據對應類型的名字以及所在的命名空間生成的,此選項用于指定生成的元數據包裝類型名的后綴,默認值為”_Type”。
-sp 用于生成子類代理類名字的后綴,默認值為”_Proxy”。子類代理類用于模擬腳本繼承C++類型進而重寫虛函數的功能。
-ic 指定內置函數的實現文件名的后綴,默認為”.ic”。
-mh 指定元數據頭文件的后綴,默認為”.mh”。
-mc 指定元數據實現文件的后綴,默認為”.mc”。
-em 在Visual C++中,需用__declspec(dllexport)和__declspec(dllimport)處理dll中導出函數的情形,一般情況下用一個宏定義上述兩者,在生成的元數據代碼中也需要導出一些函數到dll中,此時idlcpp把此處定義的宏插到相應的代碼處。
-I 將指定路徑加入#import命令的搜索路徑中。
編譯paf
用Visual Studio 2015打開解決方案文件paf\build\vs2015\paf.sln

paf 中有3個工程,分別為:
1. pafcore,這是基礎的運行時庫,提供了元數據的實現。相當于.Net中的System.Reflection或者java中的java.lang.reflect。
2. paflua,這是lua的插件,用于pafcore和lua之間的交互,使用lua語言可以通過這個插件訪問用戶導出的各種功能。
3. pafpython,這是python的插件,用于pafcore和python之間的交互,使用python語言可以通過這個插件訪問用戶導出的各種功能。
在pafcore工程中除了C++代碼文件之外,還有許多idl的代碼文件(擴展名為.i),如下圖:

這些文件都是需要用idlcpp編譯的。此處通過Custom Build Tool設置編譯命令和選項,查看任意一個.i文件的屬性,入下圖所示:

在Visual Studio中可以通過屬性文件簡化Custom Build Tool的設置,pafcore所使用的屬性文件在paf\build\vs2015\pafcore\pafcore.props。
設定好idlcpp.exe的路徑以便系統可以找到它(比如設置環境變量Path或將其復制到Windows目錄下)后即可編譯pafcore工程。
工程paflua依賴lua,先從lua官網下載源文件編譯后,再設置合適的頭文件以及庫文件路徑,即可編譯。
工程pafpython依賴python,先從python官網下載源文件編譯后,再設置合適的頭文件以及庫文件路徑,即可編譯。
以上三個工程都會編譯為Dll文件,默認放置在bin目錄下。若是release版,文件名分別為pafcore.dll, paflua.dll和pafpython.dll。若是debug版,文件名分別為pafcore_d.dll, paflua_d.dll和pafpython_d.dll。
到現在為止,準備工作已經完成,下次開始介紹 tutorials 下的各個例子程序。
Lua語言的例子從這 C++混合編程之idlcpp教程Lua篇(2) 開始
Python語言的例子從這 C++混合編程之idlcpp教程Python篇(2) 開始
浙公網安備 33010602011771號