一、編譯開源庫的傳統方法
Windows 下開發 C/C++ 程序,少不了編譯開源的第三方庫。比如用於網絡連接的高性能庫 libcurl、用於壓縮解壓的 zlib 等等。使用這些庫開發極大的方便了程序員,使得我們不必重復造輪子。但是使用這些庫必須要處理以下問題。
編譯方式
由於這些開源庫絕大部分都來源於 Linux 系統,導致其工程文件、編譯系統都使用 gnu 系列工具,使得將其移植到 Windows 的 VC 開發環境下一直是難點。盡管最近幾年很多開源庫都支持了跨平台的 CMake,但是編譯過程仍然復雜和多樣化。
常見的編譯方式有:
| 編譯方式 | 特點 | 舉例 |
|---|---|---|
| configure、make | 需要msys這樣的unix環境才可以編譯 | ffmpeg |
| 自定義編譯工具 | 需要學習特定的編譯命令和工具 | openssl、boost |
| cmake | 相對簡單輕松 | libcurl |
| VC工程文件 | 這種最簡單,直接拿來即可編譯 |
編譯類型
當了解了這些還不夠,我們還需要考慮預先編譯出哪種類型的開源庫程序。比如:Debug還是Release、動態庫還是靜態庫、MD還是MT、32位還是64位。光是這三種組合就有16種可能性。如果像libcurl這種還要考慮是否引用其他開源庫的功能,那么編譯類型的組合會更多。管理起來很麻煩。
工程目錄設定
由於多樣的編譯類型,工程目錄也必須仔細設定才能保證自己的軟件項目能夠正常編譯。
二、為什么要用Vcpkg
正是由於編譯開源庫的傳統方法的缺陷,所以出現了 Vcpkg,優點如下:
- 自動下載開源庫源代碼。
- 源碼包的緩存管理和版本管理,可以升級版本。
- 輕松編譯。
- 依賴關系檢查(比如編譯 libcurl,會自動下載 zlib、openssl 進行編譯)。
- 無縫集成 Visual Studio,不需要設置庫文件、頭文件的所在目錄,自動集成。
- Visual Studio 全平台支持,不僅支持 Debug/Release、x86/x64 編譯,還支持 UWP、ARM 平台的編譯。
三、windows下安裝Vcpkg
(1)由於官方建議把 vcpkg 目錄放到 C:\src\ 下,所以先創建再移動到該目錄:
$ cd c:/src
(2)git 克隆官方的 git 倉庫:
$ git clone https://github.com/microsoft/vcpkg
(3)進入到倉庫中,編譯 Vcpkg:
$ cd vcpkg
$ ./bootstrap-vcpkg.bat
注意:
-
Vcpkg 大量使用 psl 腳本,所以官方強烈推薦使用 PowerShell 而不是 CMD 命令行來執行各種操作。盡管在使用的時候兼容 CMD,但是在編譯這一步,請使用 PowerShell,以下所有操作也如此。
-
如果下載失敗,輸出
Downloading vcpkg.exe failed. Please check your internet connection, ...,說明外網下載不穩定,需要嘗試多次下載或梯子上網。
成功后輸出:
Downloading https://github.com/microsoft/vcpkg-tool/releases/download/2021-02-24-d67989bce1043b98092ac45996a8230a059a2d7e/vcpkg.exe -> C:\src\vcpkg\vcpkg.exe
Done.
更詳細可以參考 Vcpkg 的官方 git 地址:https://github.com/microsoft/vcpkg/blob/master/README_zh_CN.md
四、使用Vcpkg
4.1 查看Vcpkg支持的開源庫列表
$ ./vcpkg.exe search
執行命令后,兩三分鍾后才顯示出來支持的開源庫列表,基本上常用的 C++ 開源庫都支持。(使用 PowerShell 執行)
4.2 指定編譯某種架構的程序庫
如果不指定安裝的架構,vcpkg 默認把開源庫編譯成 x86 的 Windows 版本的庫。那 vcpkg 總共支持多少種架構呢?我們可以使用如下命令便知:
$ ./vcpkg.exe help triplet
我們可以看到會列出如下清單:
- arm-uwp
- arm-windows
- arm64-uwp
- arm64-windows
- x64-uwp
- x64-windows-static
- x64-windows
- x86-uwp
- x86-windows-static
- x86-windows
這個清單以后隨着版本的迭代還會再增加。vcpkg 不僅支持 x86 架構,還支持 arm 架構。注意:這里的 arm 架構特指類似於 surface 這種運行在 arm 處理器上的 Win10 平台,而並非我們傳統意義上的 Linux 或 android 的 ARM 平台。
4.3 安裝一個開源庫
那如果要安裝編譯某一個架構的開源庫,我們該怎么寫呢?我們只需要在需要安裝的包后面指定相應的 triplet 即可。例如我們需要編譯 64 位 Windows 版本的 jsoncpp,那么執行如下命令即可。
$ ./vcpkg.exe install jsoncpp:x64-windows
看到Installing package jsoncpp[core]:x64-windows... done,則說明安裝成功。
如果電腦中沒有安裝 CMake、7zip 等軟件,Vcpkg 會自動下載 portable 版本的 CMake、7zip 等軟件。但是由於各種原因,下載的網速很慢,所以建議先自行下載合適版本的對應軟件。最好是下載最新版本的。實際測試發現,會先同時下載以下軟件:
7zip-18.1.0-windows
cmake-3.19.2-windows
nuget-5.5.1-windows
powershell-core-7.1.0-windows
報錯及解決辦法
(1)在下載 powershell 時會下載不成功,提示:
Failed to download from mirror set:
https://github.com/PowerShell/PowerShell/releases/download/v7.1.0/PowerShell-7.1.0-win-x86.zip: WinHttpSendRequest() failed: 12002
只能復制上面下載鏈接,發現手動下載正常,下載完成后拷貝 PowerShell-7.1.0-win-x86.zip 到 C:\src\vcpkg\downloads 目錄下,然后再執行安裝指令,會跳過下載這步直接開始解壓 PowerShell 壓縮包。
遇到下載其他依賴庫的壓縮包失敗時,也可考慮使用這種手動下載的方法。
后面下載 jsoncpp/archive/9059f5cad030ba11d37818847443a53918c327b1.tar.gz 也不成功,采用上面方法后,修改名稱為 open-source-parsers-jsoncpp-9059f5cad030ba11d37818847443a53918c327b1.tar.gz。
(2)缺少英文語言包,報錯:
Warning: The following VS instances are excluded because the English language pack is unavailable.
解決辦法:到 VS 安裝向導,修改安裝,點語言包,勾選英語;安裝即可。
4.4 移除一個已經安裝(編譯)的開源庫
如果移除一個已經安裝的開源庫,那么執行 remove 指令即可。比如我們要移除 jsoncpp,那么執行命令:
$ ./vcpkg.exe remove jsoncpp
注意:
這個時候只是移除了默認的 x86-winodws 版本的文件,如果有其他平台的版本需要移除,需要制定相應的 triplet。移除也只是移除了二進制程序庫而已,源碼包和解壓縮的源碼並沒有刪除。
如果想要一鍵移除“過時”的包,執行命令:
$ ./vcpkg.exe remove --outdated
4.5 列出已經安裝的開源庫
執行 list 指令即可,例如:
$ ./vcpkg.exe list
假如前面安裝了 jsoncpp,會輸出:jsoncpp:x64-windows 1.9.4 jsoncpp is an implementation of a JSON reader an...
4.6 更新已經安裝的開源庫
一般有兩種更新方式。一個是 update 指令,可以顯示可以升級的開源庫的列表。另一個是 upgrade 的指令,會重新編譯所有需要更新的包。
4.7 導出已經安裝的開源庫
有的時候,一個項目組中有很多人,不需要每個人都參與編譯。一個人編譯好所有開源庫后到處給別人即可。有的時候也是出於備份的目的,也會導出已經安裝的開源庫。導出可以執行 export 指令。例如,我要導出 jsoncpp 庫,那么執行:
$ ./vcpkg.exe export jsoncpp --zip
注意,導出時必須指定導出的包格式。vcpkg 支持 5 種導出包格式,有:
| 參數 | 格式 |
|---|---|
| –raw | 以不打包的目錄格式導出 |
| –nuget | 以 nuget 包形式導出 |
| –ifw | 我也不知道這是啥格式 |
| –zip | 以 zip 壓縮包形式導出 |
| –7zip | 以 7z 壓縮包形式導出 |
一般地,導出包的格式為:vcpkg-export-<日期>-<時間>
默認情況下只會導出 x86-windows 的包,如果要導出所有包,那需要制定相應的 triplet。比如,如果同時導出 x86 和 x64 版本的 jsoncpp,那執行命令:
$ ./vcpkg.exe export jsoncpp:x86-windows jsoncpp:x64-windows --zip
如果要指定輸出目錄和特定文件名,需使用 "–output=" 參數。
4.8 導入備份的開源庫
導入比較簡單,執行 import 指令即可。例如:
$ ./vcpkg.exe import xxx.7z
五、Vcpkg和Visual Studio的集成
5.1 什么是集成?
上面我們已經安裝了一些第三方庫,那如何使用呢?常規情況下,我們需要設置 include 目錄、lib 目錄等,會有很多工作量。Vcpkg 提供了一套機制,可以全自動的適配目錄,而開發者不需要關心已安裝的庫的目錄在哪里,也不需要設置。這是 Vcpkg 的一大優勢。
5.2 集成到全局
“集成到全局” 適用於 Visual Studio 開發環境和 msbuild 命令行。執行命令:
$ ./vcpkg.exe integrate install
當出現 Applied user-wide integration for this vcpkg root. 字樣的時候,說明已經集成成功。這時候可以在任意的工程中使用安裝好的第三方庫。
5.3. 移除全局集成
移除全局集成只要執行下列命令即可:
$ ./vcpkg.exe integrate remove
5.4 集成到工程
上面已經可以集成到全局,為什么還要 “集成到工程” 呢?因為在大部分情況下,我們不希望集成到全局,畢竟有很多第三方庫我們希望自定義處理一下,或者干脆不想集成第三方庫。那么集成到工程是最靈活的處理方式。也是工程級項目推薦的處理方式。
“集成到工程” 是整個 vcpkg 中最復雜的一項,它需要利用 Visual Studio 中的 nuget 插件來實現。我們接下來一步一步來說。
1. 生成配置
執行命令:
$ ./vcpkg.exe integrate project
這時候會在 <vcpkg_dir>\scripts\buildsystems 目錄下,生成 nuget 配置文件。其中 <vcpkg_dir> 是指 vcpkg 實際所在目錄。
2. 基本配置
打開 Visual Studio,點擊菜單工具 -> NuGet 包管理器 -> 程序包管理器設置”,進入設置界面,點擊 “程序包源”。

點擊 “加號” 增加一個源。修改源的名字為 vcpkg。在“源”的選項中點擊右側的 "…" 選擇 vcpkg 目錄下的 “scripts\buildsystems” 目錄,然后點擊右側的“更新按鈕”。點擊 “確定”,關閉設置對話框。
到此,全局性的設置已經完成,以后不必再重復設置了。
3. 工程配置
用 Visual Studio 打開一個工程或解決方案。右鍵點擊需要設置的工程,選擇 “管理NuGet程序包”。在右上角的 “程序包源” 中選擇剛剛設置的 “vcpkg”。這樣在 “瀏覽” 選項卡中就可以看到 “vcpkg.H.Repos.vcpkg”。點擊最右側的 “安裝”。這樣就可以集成到某個工程了。

5.5 測試使用
#include <iostream>
#include <fstream>
#include <cassert>
#include "json/json.h" // 直接就可以include,無需額外配置
std::string createJson(void)
{
std::string jsonStr;
Json::Value root;
Json::StreamWriterBuilder writerBuilder;
std::ostringstream os;
// 設置默認無格式化的輸出
writerBuilder.settings_["indentation"] = "";
root["Name"] = "Zhangsan";
root["Age"] = 25;
// jsonWriter是智能指針, 當jsonWriter被析構時, 它所指向的對象(內存)也被自動釋放
std::unique_ptr<Json::StreamWriter> jsonWriter(writerBuilder.newStreamWriter());
jsonWriter->write(root, &os);
jsonStr = os.str();
return jsonStr;
}
void saveJsonStringToFile(const char* file, std::string& jsonStr)
{
std::ofstream ofs;
ofs.open(file);
assert(ofs.is_open());
ofs << jsonStr;
ofs.close();
}
int main()
{
std::string jsonStr;
jsonStr = createJson();
saveJsonStringToFile("./test.json", jsonStr);
return 0;
}
jsoncpp 的更多使用請參考:新版jsoncpp的一些基本用法
到此,就可以在 VS 上隨意使用 jsoncpp 庫了,在 exe 生成目錄下也發現了 jsoncpp.dll。
5.6 集成到CMake
最新的 Visual Studio 2015、2017 和 2019 大力支持 CMake 工程,所以對 cmake 的支持當然不能少。在 cmake 中集成只要在 cmake 文件中加入下面這句話即可。
-DCMAKE_TOOLCHAIN_FILE=<vcpkg_dir>/scripts/buildsystems/vcpkg.cmake
其中 <vcpkg_dir> 是指 vcpkg 實際所在目錄。
5.7 集成靜態庫
Vcpkg 默認編譯鏈接的是動態庫,如果要鏈接靜態庫,目前還沒有簡便的方法。需要做如下操作
- 用文本方式打開 vcxproj 工程文件。
- 在 xml 的段里面增加如下兩句話即可:
<VcpkgTriplet>x86-windows-static</VcpkgTriplet>
<VcpkgEnabled>true</VcpkgEnabled>
在 CMake 中集成靜態庫,需要額外指令:
cmake .. -DCMAKE_TOOLCHAIN_FILE=.../vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x86-windows-static
六、使用Vcpkg時的注意點
- Vcpkg 僅支持 Visual Studio 2015 update 3 及以上版本,究其原因,很可能和 C++11 的支持度以及集成原理有關系。
- 目前 Vcpkg 編譯靜態庫,默認只支持 MT 模式。
七、小結
Vcpkg 目前還在不斷的完善中,但不可否認,它已經極大的減少了我們在項目啟動時,准備第三方庫的時間。提高了工作效率。按照時髦的話來說,就是避免了重復造輪子。目前 Vcpkg 已經集成了上百個常用的開源庫,而且數量還在不停增長。畢竟是微軟旗下的開源項目,質量還是可以得到保障的,完全可以在工業級項目中得以使用。源代碼托管在 github上,github 社區很活躍,有興趣的朋友也可以參與進來。
參考:
Visual Studio開源庫集成器Vcpkg全教程--利用Vcpkg輕松集成開源第三方庫
