很多人從C語言學習過來的人都知道,在編寫程序時用到的像printf這樣的函數,是作為該語言標准庫函數提供的,這也是C語言標准中規定的內容。因此,操作系統必須對其保持一定程度上的透明,也就是說,作為一個生態系統提供商,這里以Windows為例,如果提供C語言作為開發語言,那么應該盡量提高透明度,減少開發者學習成本。然而據我這幾天的研究,微軟的態度可能不太明朗。
兩個CRT
熟悉Visual C++的朋友很容易發現,每次新的Visual Studio版本發布總會附加一個新的CRT庫,這也是導致在高版本上編寫的C程序通常無法在比較舊的平台上運行,必須安裝相應版本的可在發行組件包才行。幾大版本的Visual C++附帶的C庫如下表所示:
Version | C Runtime Library | C++ Runtime Library |
Visual C++ 2005 | msvcr80.dll | msvcp80.dll |
Visual C++ 2008 | msvcr90.dll | msvcp90.dll |
Visual C++ 2010 | msvcr100.dll | msvcp100.dll |
Visual C++ 2012 | msvcr110.dll | msvcp110.dll |
Visual C++ 2013 | msvcr120.dll | msvcp120.dll |
(注:msvc*80.dll和msvc*90.dll還存在多個相同名稱的版本,但從VC2010開始就不存在這種情況,這里牽涉到Side-by-side assembly技術,這比較坑,不展開說明)
同時如果足夠細心,會發現在system32目錄下存在着msvcrt.dll文件,這樣的名稱足足讓人產生懷疑,notepad等程序正是依賴這個文件運行,
另外,該文件的詳細信息中也表明這是一個CRT
如果細究其導出函數,也可以發現基本也是差不多的,更能說明其用途。
存在的問題
一個系統存在兩套同樣功能的程序庫,這顯然不太符合常識。在估測微軟為什么做如此設計的原因之前,需要關注下目前Windows平台下CRT各版本的兼容性問題及其技術背景。
一個系統的好壞、特別是軟件系統是由其提供的向前兼容性高低決定的。也就是說,理想情況下,新版本的程序庫A替換舊版本的A不會出現問題。在實踐上程序庫的編寫者為了達到以上目的對程序代碼制訂了一些規范,如調用約定、函數簽名等(可參看Application binary interface),很多實例證明,這樣的約束對C語言編寫的程序庫苛刻程度比較低,相對於C++而言(可以參考KDE C++ Compatibility Issues),Linux平台下各種C編寫的庫均持有良好的兼容規范。
這里可以用Glibc作為對比,Glibc文件名形如x.y.z,是x為主版本號、y為次版本號、z為發布版本號,其中主版本號不要求兼容性,及此項不提供向后兼容性;此版本號要求兼容性;而發布版本號是bugfix,不改變原版本的兼容性。這一描述摘自於GNU的官方描述,從中我們可以知道,獲取一定程度上的向后兼容在技術上還是可以實現的。
然而Windows平台下CRT版本兼容性卻令人摸不着頭腦,這樣的問題特別集中在VS2005和VS2008發布的CRT版本上。這兩個大版本的CRT在小版本之間也是不兼容,比如使用VS2005發布的C程序與VS2005 SP1發布的兩者無法兼容,就像上面提到的,微軟甚至開發WinSxS技術來維持這種不兼容性,實在令人費解。
這樣帶來的麻煩也是顯而易見的,對於開發者而言,由於最終用戶端不定的環境,需要更多的考慮發布程序上的事宜,分散關注應用本身的精力;更致命的是,或者說有可能打擊到開發者的開發興趣的是,軟件應用開發過程中需要的各種依賴於CRT的程序庫由於上述的兼容性問題,必須與應用軟件本身一起統一到同一個版本上來,而這樣做會使得開發軟件的成本進一步提高,MSDN中也提到該問題。這里可以舉一個例子,比如A軟件應用,依賴B、C兩個程序庫,假設開發團隊計划基於VS2010開發A,然而提供B的軟件公司最高只提供VS2008編譯版本,這時不得不把A的開發平台也降至VS2008下,不僅如此,往后的對A的開發平台的升級更會受制於B、C 程序庫的版本。對於開發團隊而言,無論是平台遷移還是購置新版本的程序庫都是一筆很大的開銷。綜上所述,微軟設置的不同版本間的完全不兼容性確實給開發者一定的麻煩,更重要的是,這並不是由技術水平限制而帶來的。
對於最終用戶而言,最常見的現象就是軟件缺少相對應的CRT而無法運行,而用戶不得不需要承擔由此帶來的上手難度;面對諸多Visual C/C++可發行組件包必將會束手無策,讓最終用戶承擔這種由非技術原因引起的后果的確很不應該。
總之,相比其它平台,作為微軟為什么如此設計Windows操作系統中的CRT,可能更多要從非技術層面去考量。
不純的動機
從上述的問題中,不難看出微軟在對待CRT的兩個決策,一個是相似功能的CRT提供了兩套,依據其作用可分為系統級和用戶級;另一個是用戶級CRT中設置了多了版本,且多個版本之間完全不兼容。依我之見,這兩個決策的形成,將本來很是容易實現的技術復雜化,可能更多是商業上的原因。
第一個決策中的兩套CRT設置,暫且沒有細究它們兩者提供的接口差別,但容易想到的是系統級版本的CRT可能會在效率和穩定性等方面故意設計得比用戶級好,這也符合閉源軟件的一貫作風。另外,諸多Windows系統軟件均是基於CRT實現無疑是承認C語言同時作為系統開發和應用開發語言的優勢,但這內外的兩套標准折射出微軟對開發者似乎不太信任,因此設定某些限制,與第二個決策一同弱化C語言的作為Windows應用開發優勢,甚至可以說是淡化C語言的地位,事實確實如此,結合微軟近年來推廣的.NET平台,版本間的兼容性問題帶來的麻煩會讓開發者在選擇開發語言上做更多的權衡,而且微軟一直在引導更多的人到C#語言上來。C#作為.NET主推語言在目前至少可以說還是主要在Windows平台下,聯想到ObjectiveC之於iOS平台,可以看出微軟在向蘋果學習,不斷提高Windows應用開發者遷移至其他平台的難度,加大開發者的黏性。但又做不到像蘋果那樣純粹(在開源方面,也沒有Linux做的純粹),這種故意將技術復雜化帶來的惡果,Windows現如今在IOS、Android雙面夾擊的窘迫狀況無疑是最后的佐證。
可能這句英語更能體現微軟對待技術態度 :“Microsoft tends to make things more complicated for some commercial reasons, although they does really make them look easier at the first time.”
參考
(1)History of DLL Hell and why it will repeat itself - Joseph Nord