這個題目一看就很欠扁,既然用C++又不想依賴stdlibc++標準庫這不是有病嗎?其意義究竟
何在?這實際上就是我最近被賦予的光榮使命,神奇的是原來真的可以做到!!!與標準庫
斗于編譯器斗,其樂無窮~~~收獲也不是沒有,對C++,對編譯器的認識又更近了一步,雖然
本來就沒有什么認識。
故事是這樣開始的,我們為公司的某產品開發了一個模塊,其實就是兩動態庫。本來這東西
也不是我們開發的,我們只是負責移植到公司的12個平臺上。本來一切都很順利,不幸的事
是在test快要結束的時候發生的,某平臺是build機器上與test機器上stdlibc++.so版本不
一致,我們的so竟然不能load,這不是再正常不過的事情么,裝一個需要的版本就一了百了
了,但是。。但是可惡的印度人懶得裝不說,還指責是我們的問題,說引入了新的依賴,不
行不行就是不行,我的奇妙旅行就此開始了。(這個問題也可以通過靜態鏈接stdlibc++解
決,貌似他們沒搞定,我也沒有深入研究)
總的來說C++對stdlibc++.so的依賴主要由以下幾個部分產生:
1. 對C++標準庫的依賴
簡單的看就是 include C++的頭文件(不以.h結尾)
如果你大量使用的STL...請回吧,不送了。還好我們只使用到了vector和dqueue,簡
單實現了一個,湊合著用了
2. new 和 delete 操作符
這兩個操作符實際上完成了兩部分工作,首先是分配內存,其次是調用相應的構造/析構
方法。而對于gcc來說,分配內存的工作是在stdlibc++.so中完成的,所以會造成依賴,
幸運的是重載這兩個操作符就是重載分配內存的部分,所以我們只需要用malloc/free簡
單的重載這兩個操作符就ok了
3. 純虛函數
使用繼承和虛函數都是沒問題的(竟然沒有依賴rtti,需要繼續研究),但純虛函數是
不行的,這個估計跟實現有關。最簡單的方法就是將所用的純虛函數改為虛函數再添加
默認實現。
4. exception
這是最麻煩的部分,如果exception用的不多,直接將exception作為返回值返回了結
(原來有返回值的放到輸出參數里),每次調用check一下,根據原來代碼中的邏輯要么
返回exception(沒有catch住該exception),要么做catch中的事。理論上是沒問題的
就是麻煩點,代碼ugly點,可能再用點goto也沒啥大問題。
這里要介紹的是另一種方法,通過使用setjmp和longjmp實現exception機制,再利用宏
替換原來代碼中的try throw catch,詳細的就不寫了,我也是從網上看到的參見:
Exception Handling in C without C++
cexcept:sourceforge上的開源項目
看了就能明白,但要實現完整的exception機制還是有難度的,包括try catch的嵌
套,exception的繼承,多catch等。我們現在也沒能實現多catch,宏的能力還是有限啊。
5. rtti
這是C++特用的東西,嚴重依賴于stdlibc++.so,凡是動態的類型判斷都是要禁止
的,catch為了判斷exception的類型就會使用到rtti,dynmaic_cast也會有同樣的問
題,typeid之類的東西更是永不得的。
6. 編譯參數
當你完全完成了上面的工作,基本上就大功告成了,不過現代的編譯器那是相當的聰明,在
背后為我們默默無聞的做了很多事情,比如對于c++的代碼會默認幫你生成處理
exception的代碼,所以需要用 -fno-exceptions 來防止這樣的事情發生,然而這還不
夠,-fno-exceptions 和 -fno-rtti 必須是要同時使用的,只使用 -fno-exceptions只
能得到個半吊子的結果:依然會有rtti的代碼生成(不知道gcc那幫人是怎么想的)。
你以為終于可以結束了嗎?
if (your_gcc_version < 3.4.6) {
goHome();
happyEnding();
} else {
聽我慢慢道來();
}
在gcc 3.4.6 以上版本會為local static生成保證線程安全的代碼,不幸的是這些代碼
是依賴于stdlibc++.so的,所以我們要禁止他們!!!請使用
-fno-threadsafe-statics,并確保這些static代碼是線程安全的
終于寫完了,估計沒有人會再有這樣奇怪的需求了,寫在這里留作紀念。
另外提一下模板是可以使用的,因為只是在編譯時生成代碼,不關標準庫的事。
posted on 2008-07-31 00:05
JBahamut 閱讀(1059)
評論(0) 編輯 收藏