天天看點

靜态連結庫 —— 類工廠的杯具

今天又碰到一個極其BT的問題,從想不通到詫異,從詫異到無奈。隻想溫柔的說一聲:靠!

其實這個故事,以前在做Linux的時候就發現過,沒有深入研究,今天經不起真相的誘惑,為了故事的連貫性,我從今天的故事開始。

故事的前奏:

我在設計我的字型系統,場景管理的Node系統,Enity系統的時候大量使用了Factory模式,通過一個String的id就可以建立出一個類來。 比如

ISceneNode* pActorNode = xSceneNodeManager::singleton()->createInstance(L"xActorNode", m_pSceneGraph);

這是一個非常美好的設計。将來我要擴充的時候,隻要寫一個xXXXXSceneNodeFactory。并寫一個全局的factory對象,在對象構造函 數或者用其他方法注冊到xSceneNodeManager中。ISceneNode的擴充是0耦合!!這就是我想要的。

這個美化的故事在我一直使用大塊頭的dll引擎的時候一直都這樣美好着。

故事的發展:

前兩天我已經順利把引擎插入到ATL ActiveX控件中,為了進一步減少體積,考慮到我的dll為了避免安裝vc運作庫的額外開銷,都是采用靜态連結CRT的模式,是以我決定,将引擎的所 有插件代碼都編譯到static lib中,并将lib連結到ocx中,這樣體積能小很多。

經過一番折騰,我終于将ocx編譯出來,整個系統隻有一個ocx,又是一個美好的故事啊。。。我開始陶醉:從5個dll,7M大小,直線減少到1.3M。 很成功。

但是,美化的時光很短暫,我很快發現,我的ocx根本沒法運作!!。

故事的高潮:

經過一番調試,我發現,我的Font系統的類工廠,一個都沒有注冊過。

神奇!!!!

開始我懷疑我的類工廠有問題,将static改成extern ,去掉static。甚至還試過這樣的方法:

class xFT2FontFactory : public IFontFactory

{

int type();

};

xFT2FontFactory g_FT2Fct;

const int xFT2FontFactoryInitV = g_FT2Fct.type();

不管用啥方法,我的類工廠就是不肯自動注冊。

無語中...

當我的引擎編譯成靜态庫的時候,在連結的過程中,vc隻連結了那些我用到的符号表。那些子產品中的符号表,如果在别的子產品裡沒用到,那麼壓根就不會代碼整合過來

舉例:

我的靜态庫:

xEvol3D_Release_Static.lib (  xFontRender.obj , xFontManager.obj , xFT2Font.obj , xBmpFont.obj )

我将在 xEvol3D_WebControl.ocx中使用 xEvol3D_Release_Static.lib

當然,由于我“優秀的”設計模式,在 xEvol3D_WebControl.ocx 中我顯然不會直接去使用xFT2Font.obj和xBmpFont.obj中的對象。但是xFT2Font.obj中的靜态變量會自動注冊類工廠到 xFontManager.obj的類中,然後 xEvol3D_WebControl.ocx 通過xFontManager的接口建立出xFontRender對象來使用。

這個時候,因為 xEvol3D_WebControl.ocx 沒有引用到 xFT2Font.obj 的符号,其他子產品也沒有引用xFT2Font.obj。于是“聰明”的連接配接器就把我的xFT2Font.obj給扔了。。。

無奈的結果:

我找了好多資料,還挨個看了看VC的編譯設定,暫時沒有發現任何地方可以“Full link all  module in static lib"的選項。極其杯具。

無奈,我隻能改成動态連結庫。不同的時候,把插件的代碼整合到一起。

後記:

1. 測試過我找到的那篇文章的方法,在其他地方強行引用 xFT2Font.obj中的符号,那麼這個子產品就進來了。代碼也對了。但是顯然我不會這樣做。我這樣的類太多。不現實。

2. 想起<Unix程式設計藝術>裡的一個條款:越是花哨的東西越是容易出問題。看來真是報應啊。

3. 從7M減少1.3M也是個幻覺。好多代碼都沒進去。當然小了。sigh!

4. Linux也有同樣的問題。我用gcc的時候,也發現過類似的問題。

繼續閱讀