1. 程式人生 > >vs2015部署---下一代VC執行時庫系統:the Universal CRT

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,譯為社群技術預覽版,一般是微軟開發軟體的早期對內測試版

作者簡介:陳建明,目前就職於上海愷英網路科技有限公司,C++專業組組長。十多年來,儘管各種程式語言均有涉獵,但主要一直致力於Windows C++平臺的各種應用架構、開發和前沿技術的研究。

責編:何永燦([email protected]

相關推薦

vs2015部署---下一代VC執行系統the Universal CRT

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

VC 執行 /MD、/MDd 和 /MT、/MTd

有段時間在寫cuda程式是出現過 error LNK2005: _exit 已經在 MSVCRTD.lib(MSVCR71D.dll) 中定義 等類似錯誤 原因應該是在vs2010 工程屬性中 c/c++的程式碼生成(code generation)中的設定與cuda

[轉]C和C++執行

轉自csdn原文:https://blog.csdn.net/ithzhang/article/details/20160009 圖片請去原文檢視 在使用VC構建專案時,經常會遇到下面的連結錯誤:   初學者面對這些錯誤常常不知所錯:libcmt.lib是什麼東西?msvcrtd.dll又是幹嗎用的?在

什麼是c執行

nafxcw.lib 和 libcmt.lib衝突問題。 解決辦法: 屬性設定裡讓程式先找到nafxcw.lib. 解決辦法參考:https://www.cnblogs.com/suiyingjie/archive/2012/10/29/2745031.html 從vs2008 工程

執行 MT\MD的區分和優劣

  VC專案屬性→配置屬性→C/C++→程式碼生成→執行時庫 可以採用的方式有:多執行緒(/MT)、多執行緒除錯(/MTd)、多執行緒DLL(/MD)、多執行緒除錯DLL(/MDd)、單執行緒(/ML)、單執行緒除錯(/MLd)。 Reusable Library&nb

Qt在pro中設定執行MT、MTd、MD、MDd,只適合VS版本的Qt

轉自:http://blog.csdn.net/caoshangpa/article/details/51416077 一.在pro中設定執行時庫 最近在用Qt5.6.0(VS2013版本)呼叫一份用Visual Studio 2013編譯的Debug版本靜態庫時出現如下錯誤:

[原]java執行修改系統環境變數

專案需要在程式執行時修改系統的環境變數,並在結束時還原。 Java執行時可以用System.getEnv(“{EnvName}”)的方法獲得系統環境變數,比如PATH。 但是,Java 6.0沒有setEnv方法,查詢API文件得知Java 8.0也沒有se

判斷是否已經安裝vc2008執行

Visual C++ Redistributable(簡稱VC執行庫),現在的系統VC2005是必須安裝,QQ、遊戲、網路應用都離不開VC2005的支援,(也就是說VC不安裝這些都不能用),VC2008執行庫呢是可選的,現在或將來新遊戲都依賴VC2008程式碼呢沒什麼精闢之處

GCC編譯、連結、執行查詢順序(最真實可信)

參考了不少資料,其中最靠譜是這個:http://www.mingw.org/wiki/librarypathhowto和http://www.kaizou.org/2015/01/linux-libraries/經過線上實際驗證,GCC編譯、連結、執行時庫查詢順序如下,這個順

終於理解了什麼是c/c++執行,以及libcmt msvcrt等內容

在各個版本的編譯器中,我們可以通過配置選項來設定程式使用的C和C++執行時庫的型別。如下圖(其他版本編譯器大同小異):MT選項:連結LIB版的C和C++執行庫。在連結時就會在將C和C++執行時庫整合到程式中成為程式中的程式碼,程式體積會變大。 MTd選項:LIB的除錯版。 M

執行路徑指定

這裡補充一點,動態庫(.so)是直接可以呼叫的,並不會被編譯程序序。只讀檔案系統,將其中一個目錄通過nfs方式mount到其它地方(比如PC機),將動態庫放於該目錄下,並將該目錄指定為庫的搜尋路徑(export LD_LIBRARY_PATH=),程式執行時會呼

VS的執行(Runtime lIB)

在開發window程式是經常會遇到編譯好好的程式拿到另一臺機器上面無法執行的情況,這一般是由於另一臺機器上面沒有安裝響應的執行時庫導致的,那麼這個與編譯選項MT、MTd、MD、MDd有什麼關係呢?這是msdn上面的解釋: MT:mutithread,多執行緒庫

C執行(C Run-time Library)詳解

一、什麼是C執行時庫1)C執行時庫就是 C run-time library,是 C 而非 C++ 語言世界的概念:取這個名字就是因為你的 C 程式執行時需要這些庫中的函式.2)C 語言是所謂的“小核心”語言,就其語言本身來說很小(不多的關鍵字,程式流程控制,資料型別等);所以,C 語言核心開發出來之後,De

CRT(C Runtime Library)—— C/C++執行

C runtime library(part of the C standard library) 任何一個 C 程式,它的背後都有一套龐大的程式碼來進行支撐,使得該程式得以執行在更高級別上,而不必擔心同計算機底層操作的細節,這套程式碼至少包括:

執行MT、MTd、MD、MDd的研究

在開發window程式是經常會遇到編譯好好的程式拿到另一臺機器上面無法執行的情況,這一般是由於另一臺機器上面沒有安裝響應的執行時庫導致的,那麼這個與編譯選項MT、MTd、MD、MDd有什麼關係呢?這是msdn上面的解釋: MT:mutithread,多執行緒庫,編譯器會

【VS開發】MFC執行與debug、release版本之間的配置關係

參考內容:  前段時間從網上下來一個有意思的程式碼,用VS2010開啟時需要將工程轉換為2010的工程,轉化後卻出現了編譯不通過的問題,類似這樣的錯誤:c:\program files\microsoft visual studio 10.0\vc\atlmfc\inc

VS執行下載地址

Microsoft Visual C++ 2008 SP1 Redistributable Package (x86) 地址:http://www.microsoft.com/en-us/download/details.aspx?id=5582 Microsoft Vi

C/C++執行到底在Windows中起什麼作用(猜想)

以下是作者的一些猜想: 1. 我們在用VC程式設計時,會在執行我們的main函式前,系統先通過Kernel32呼叫一些函式,執行一些C的初始化準備工作,我們一般叫C執行時庫的初始化。那麼這些初始化的作用是什麼?是否是必要的?不知道大家有沒有思考過這個問題。 以下是我對這

FBX在Windows下執行的選擇

  有時候有寫些造福後人的文章,但往往都是說不透徹,我自己學得都不透徹.能造福一些算一些吧,以後看完了再補上.最近弄的用FBX SDK操作FBX動作檔案的東西,弄了這是第五個星期了,總算快弄完了.簡單說下庫的選擇.   如官方的說明所言,可以選擇3種使用FBX SDK的方式

C執行Visual C++ C RunTime Lib

CRT 全稱:Visual C++ C RunTime Lib 就是C執行時庫。 注: 以下內容部分引自CSDN中相關討論的帖子,並結合自己的理解整理而成。僅供參考。 1)執行時庫就是 C run-time library,是 C 而非 C++ 語言世界的概念:取這個