vs2015部署---下一代VC運行時庫系統:the Universal CRT


 

前言

其實the Universal CRT(通用C運行時庫)已經不能算是“下一代”,因為它已經在前兩年伴隨着Visual Studio 2015和Windows10發布。但是由於之前使用VS2015開發的應用還較少,關注的人也少,相關的文章更少。所以筆者想干脆用一篇文章,深入淺出的介紹一下Universal CRT。

什么是CRT?

CRT,也就是“C Runtime”,中文譯為:C運行時。我們一直稱為C Runtime Library(C運行時庫)。它主要負責實現C程序在運行時的各種抽象功能實現。不同的C編譯器會有不同的具體實現程序,比如Windows下常見的微軟的VC編譯器的msvcrt.dll;GCC/Glibc的crt0.o、crti.o等。具體到二進制表現形式,可以是動態庫,也可以是靜態庫。

CRT一般會至少負責以下功能:

  • 實現C庫函數。比如:printf、fopen等
  • 初始化程序啟動所需要的一些功能
  • 異常處理
  • 多線程處理

CRT也可以看成是一個操作系統抽象層。大家都知道,每一種操作系統都有自己的API或者是系統調用。像C語言之所以能夠跨平台(代碼級),就是因為我只需要用C庫函數寫程序,CRT會轉化為相應平台的具體實現的API來處理。

下面我們要着重討論的是Windows下的開發工具Visual C++配套的CRT,以下將統稱為“VC運行時庫”。

VC運行時庫的歷史

(注:上表中的划代是作者自己的划代方式)

第一代

我記得我最早學C語言還是上大二(2002年)的時候,那時可是VC的黃金年代。額~~應該說是鑽石年代。大家都在學習VC++6.0,一個堪稱經典的版本。VC++6.0是為了配合Windows98的應用軟件開發而發布的,發布的年代也差不多就是98年前后,所以內部有些文件又稱之為VC98。

到這個時候,VC運行時庫文件只有一個叫msvcrt.dll的,一般在c:\windows\system32下,大家發行軟件產品的時候,基本上不需要考慮是否需要帶個什么庫,因為默認操作系統都會自帶的。

逐漸的,大家發現一個非常棘手的問題,那就是隨着功能的增多,不同版本的msvcrt.dll支持的功能和函數不同,版本的識別和兼容成了難題。當時很多安裝包為了自己的需要,會不停的覆蓋系統的msvcrt.dll,導致運行不穩定。如果把WinXP系統的msvcrt.dll覆蓋了Win98的,那會導致WinXP不穩定。所以后來就發展除了第二代的CRT。

第二代

自從微軟發布Visual Studio.Net 2002/2003開始,為了解決日益增長的功能和DLL版本兼容性問題,微軟給現有的運行時庫加上了版本號,並且把運行時庫拆分為多個文件,比較常見的是msvcrXXX.dll和msvcpXXX.dll。其中XXX是版本號。

版本號的定義和文件命名如下表所示:

其中msvcrXXX.dll(注意不是msvcrtXXX.dll)一般負責實現C語言的基礎特性,如程序啟動、異常處理、庫函數等功能。msvcpXXX.dll負責標准C++庫的相關實現。大家可以看看其中的導出函數就能明白。

在這一階段中,開發者想要發布軟件產品,就必須確保目標計算機上必須已經安裝了相應版本的運行時庫。一般情況下,微軟推薦大家使用運行時庫安裝包來進行安裝。對於大型軟件為了預防萬一,都會附帶vcredist.exe安裝包。但是這種方法很不受待見。因為現在大多數軟件都是通過互聯網進行分發,對安裝包大小很敏感。每次打包附帶一個運行時庫包,既增加了用戶的下載時間,又增加了推廣成本。

現在大部分軟件的做法是將這兩個dll放在軟件目錄下發行。但是問題又來了,光是VC2008的msvcr90.dll的就有N個版本,不同語言有不同版本,隨着update增加的修正版本也很多。大部分情況應該不會有問題,但筆者就曾經遇到過加載錯誤版本的運行時庫而程序崩潰又查不出問題的經歷。這個時候微軟要求必須使用manifest文件來指定加載的VC運行時庫版本。直到VC2010,由於編譯器內置了manifest,所以就不需要額外提供。

第三代

自Visual Studio 2010開始,微軟大力改進了很多C++特性,陸續在2012、2013、2015版本中增加了對C99、C++11、C++14、C++17等標准的支持,使得C++庫的功能成倍增加。這種小步快跑的更新模式,使得如何有效的讓VC運行時庫向前和向后兼容而不破壞現有的軟件組件的問題變得異常突出。再加上讓VC運行時庫能夠更好的支持Win8/10提倡的PC和移動設備並舉的理念,微軟團隊決定在Visual Studio 2015對VC運行時庫進行重構。然后“the Universal CRT”就應運而生了。

the Universal CRT

the Universal CRT(以下簡稱UCRT),顧名思義,意思為“通用C運行時庫”。關鍵就在“通用”這兩個字上。早期的設計理念就是要把相對通用的功能獨立出來。這個概念最早在Visual Studio 14 (即vs2015)的CTP1 [1] 發布的時候提出來 [2] 。VS很神奇的跳過了13.0這個版本,直接從12.0(vs2013)跳到了14.0(vs2015),估計是因為歐美人把13這個數字認為是不吉利的有關。盡管UCRT的版本號稱是1.0,但真實的VCRuntime還是14.0。

早期的設計

當vs2015還在CTP階段時,微軟的設想是將VC運行時庫拆分成三部分。

vcruntime140.dll 包含運行期需要處理的功能,如:進程啟動、異常處理、以及耦合到相關編譯器的功能。

appcrt140.dll包含所有平台上都可用的所有功能,且以后保持這部分CRT的向后兼容性。包括:堆、數學庫、stdio庫、locale庫、大多數字符串操作函數、時間庫和一些其他功能等。

desktopcrt140.dll包含所有只能由桌面應用程序使用的功能,且以后保持這部分CRT的向后兼容性。包括:處理多字節字符串、exec和spawn進程管理函數、direct-to-console I/O函數的功能等等。

正式版本

在最終發布正式版的時候,微軟將appcrt140.dll和desktopcrt140.dll合並為一個不帶版本號的程序庫:ucrtbase.dll。它對應的Debug版本的命名是ucrtbased.dll。這個后來被正式命名為“the Universal CRT”。

API Sets for Universal Windows Platform (UWP) apps

令很多人吐槽的是,UCRT並不只是一個DLL,它還附帶了一堆以“api-ms-”開頭的DLL程序文件,且有40個之多!可以看到,這些DLL導出了幾乎所有的win32api。這其實是微軟在Windows10中大力推動的“Universal Windows Platform (UWP) apps”即“通用Windows平台應用”的api接口 [3] 。這些dll有些默認為“delay load”,也就會是被延遲加載。一般基於UCRT編譯的程序,不是直接調用ucrtbase.dll,而是調用VCRuntime140.dll和UWP apis來間接調用。

基於UCRT程序的部署方法

什么程序是基於UCRT的?

如果你是用Visual Studio 2015和2017來編寫C或C++程序,那么就已經是基於UCRT的。

需要關注的程序模塊

VCRuntime140.dll 這是VC運行時庫和編譯器相關的必備模塊,必須存在。

msvcp140.dll 如果你寫的程序含有C++標准庫的代碼,那就必須存在。

ucrtbase.dll和api-ms-**.dll 必須存在。

部署方法

第一種

微軟強烈推薦使用vcredist.exe來給目標機安裝相應的文件。它會安裝所有對的UCRT文件和必備組件。這是最省事兒便捷的方法。

但是vcredist_x86.exe和vcredist_x64.exe就各有近14MB的體積!大型程序發布的時候可能無所謂,而很多很多基於互聯網發布的程序,卻不可能這么干。互聯網程序對安裝包的大小很敏感,這直接影響最終用戶終端的到達率和推廣成本。

可參考PHP7.1的Windows版的下載頁面和安裝包。

第二種

程序自帶VCRuntime140.dll和msvcp140.dll,再給系統打基於msu的KB2999226補丁。KB2999226補丁會給系統安裝UCRT。一般情況下,Windows10已經自帶了UCRT,不需要額外打補丁。

這種方法不適用於WinXP系統。而在中國WinXP系統還有很大保有量,大家都不會輕易放棄這個龐大的用戶群的。

可參考Python 3.5的Windows安裝包。

第三種

現在互聯網程序大多使用的是app-local的部署模式,意思就是把依賴庫放在自己程序目錄下,既不會跟別的應用軟件沖突,又方便了軟件分發。

起初,微軟並沒有打算針對UCRT程序繼續這樣的部署模式。但是后來大家反響比較強烈,所以在Windows 10 SDK發布的時候,把UCRT和UMP的相關dlls都一起發布了。這個目錄一般是“C:\Program Files (x86)\Windows Kits\10\Redist\ucrt”。

你也可以在Visual Studio 2015的安裝目錄下找到VCRuntime140.dll和msvcp140.dll。這個目錄一般是“C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x86\Microsoft.VC140.CRT”。

有些開發者一開始可能會被ucrt目錄下的四十幾個文件嚇到,不過還好都不大,打包壓縮以后都很小。

可參考Visual Studio 2015配套的Remote Debugger 調試工具。這個工具由於要求是“standalone”的,所以就是用此方法部署的。可以在這里找到:“C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Remote Debugger\x86”。

UCRT展望

UCRT的確給我們帶來了很多全新的概念,也給我們帶來了少許的不適應。但這畢竟是未來的發展方向。基於UCRT的Visual Studio 2015給我們帶來的眾多新的C、C++語言標准的支持,我相信以后C++程序會變得更加強大。按照網上的一些說法,未來不排除會對VCRuntime模塊再次優化重構的可能性,這個我們只能拭目以待了。Visual Studio 2017即將發布,我們也將繼續跟進UCRT的發展方向。

[1] CTP 即Community Technology Preview,譯為社區技術預覽版,一般是微軟開發軟件的早期對內測試版

[2] 參考 https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/

[3] 參考: https://msdn.microsoft.com/zh-cn/library/mt186421.aspx

from:http://www.qingpingshan.com/m/view.php?aid=223329


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM