位元詩人 [Windows] 程式設計教學:用 vcpkg 安裝 C 或 C++ 函式庫

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

我現在對 vcpkg 的理解

當時我把 vcpkg 當作「Windows 上的套件管理工具」,但後來回頭看,這樣的理解其實不太完整。

vcpkg 不只是套件管理器,而是 build system 的一部分。它實際上在做的是,把原本以 GNU/Linux 為主的函式庫生態,轉換成可以在 Windows(特別是 MSVC)上編譯與使用的形式。

這也解釋了為什麼在使用 vcpkg 時,常會遇到一些看似奇怪的問題:這些問題不一定是操作錯誤,而是因為上游函式庫原本並不是為 Windows 環境設計。

從這個角度來看,vcpkg 有點像是在 Windows 上模擬一個 Unix 函式庫生態,但又缺乏完整的系統環境與社群維護規模。因此在某些情境(例如 Visual Studio / MSVC 工作流程)下很方便,但在其他情境下就未必適合。

目前我個人的做法,是在 WSL 中處理大部分 C、C++ 開發,只有在需要 Windows 原生環境時,才使用其他工具(例如 MSYS2)。本文則保留當時使用 vcpkg 的流程,供有需要的讀者參考。

聲明

本文操作流程基於 2019 年 4 月當時的 vcpkg 使用方式。

目前 vcpkg 已有不少變化(例如 manifest mode 等),本文不再更新操作流程,僅作為歷史紀錄與參考。

前言

C 和 C++ 的函式庫(library)並沒有「套件」(package)的概念,而是以標頭檔(header)與二進位檔(binary)的形式發佈。GNU/Linux 或其他類 Unix 系統上常見的函式庫套件,其實是後來在工具鏈之外額外建立的管理機制。

在 Windows 上,過去並不強調套件管理,開發者通常是將標頭檔與二進位檔直接複製到專案中使用。微軟後來嘗試推出套件管理方案;早期使用 NuGet,但成效有限,而 vcpkg 則是較新的嘗試。

筆者認為 vcpkg 在理念上是好的,但在當時仍屬新專案,文件較少,實際使用時可能會遇到不少問題,需要自行除錯。

在本文中,我們以 GTK+ 版本的 Hello World 程式為範例,展示 vcpkg 的使用方式。

安裝 Visual Studio 2019

經筆者實測,使用 Visual Studio 2017 或 Visual Studio 2019 皆可,此處以 Visual Studio 2019 為例。在安裝時要選擇必要的工作負載 (workload)「使用 C++ 的桌面開發」:

在 Visual Studio 2019 上安裝 C 或 C++ 開發所用的工作負載

如果讀者已經安裝過 Visual Studio 2019 了,也不需要移除,只要重新執行 Visual Studio Installer,選擇必要的工作負載即可。

此外,要選擇必要的語言套件「英文」:

在 Visual Studio 2019 中選擇「英文」套件

如果沒有選擇這個項目,在編譯 vcpkg 時會報錯。即使裝了英文的語言套件,介面仍然可以繼續用中文,只是多一個語言套件包。

安裝 vcpkg

在 vcpkg 中,許多套件來自自由軟體專案。這些專案原本多半依賴類 Unix 的 shell 環境與 Autotools(GNU Build System)進行建置。

vcpkg 的做法,是為這些套件撰寫對應的 CMake 設定檔,使其能在 Windows 上編譯。某種程度上,這相當於重新包裝原有的建置流程。雖然這看起來有些重複,但微軟願意維護這些 CMake 設定,仍然降低了在 Windows 上使用這些函式庫的門檻。

(註:這裡其實反映了 vcpkg 的核心設計——將原本偏向 Unix 的建置流程轉換到 Windows 環境。這也是後續許多問題的來源。)

在接下來的操作中,會用到 「x64 Native Tools Command Prompt for vS 2019」:

Visual Studio 2019 中的 Visual C++ 的終端機視窗

這個命令列環境除了 Windows 終端機原本的功能外,還對終端機做了一些額外的設定,所以在該終端機內可以用 Visual C++ 編譯 C 和 C++ 原始碼。vcpkg 本身和該專案所發布的套件都是以原始碼的形式發佈,下載後需要再重新編譯成二進位檔。

在 vcpkg 裡面有許多套件都來自於自由軟體,在 Windows 上沒有 shell 環境要怎麼編譯這些套件呢?vcpkg 的做法是幫這些套件重新寫 CMake 設定檔,就可以繞過在 Windows 上無法用 Autotools (GNU Build System) 的問題。其實這樣有點重造輪子,因為這些套件在類 Unix 系統上已經可以編譯了,但微軟肯花時間維護這些自由軟體的 CMake 設定檔,基本上還算佛心。

在本文中,我們將 vcpkg 安裝到 C:\tools 目錄中,讀者可自己更改到其他位置。這裡用 Git 將整個 vcpkg 專案拷貝 (clone) 下來:

C:\tools> git clone https://github.com/Microsoft/vcpkg.git
C:\tools> cd vcpkg

輸入以下指令以編譯 vcpkg:

C:\tools\vcpkg> .\bootstrap-vcpkg.bat

該命令稿內部會自行呼叫 PowerShell 來執行編譯的動作,所以在傳統的 Windows 終端機內也可以使用。編譯 vcpkg 的時間並不會太久,稍微等一下即可。

接著,將 vcpkg 整合到 Visual Studio 中:

C:\tools\vcpkg> .\vcpkg.exe integrate install
Applied user-wide integration for this vcpkg root.

All MSBuild C++ projects can now #include any installed libraries.
Linking will be handled automatically.
Installing new libraries will make them instantly available.

CMake projects should use: "-DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake"

之後 Visual Studio 就會自動偵測到 vcpkg 內的套件。不過,筆者只是拿 Visual C++ 來編譯套件,沒有用到 IDE 的部分,有興趣的讀者可自行嘗試。

安裝 GTK+

在編譯 gtk 時,要修改「系統地區設定」,這是為了編譯 glib 套件的緣故,而 glib 是 gtk 的相依套件 (參考這裡)。

進入 Windows 設定,選擇「時間與語言」:

在 Windows 設定中選擇「時間和語言」

在「地區與語言」這個子類別中選擇「系統管理語言設定」 (要稍微向下捲一下視窗):

在「地區與語言」中選擇「系統管理語言設定」

選擇「變更系統地區設定」:

選擇「變更系統地區設定」

將「系統地區設定」調成「英文 (美國)」:

將「系統地區設定」調成「英文 (美國)」

調整完後,需要重新開機,讓更動生效。編譯 gtk 後,可再將「系統地區設定」重新調回原本的語系,只是在編譯程式時會跳警告訊息,但仍可編譯成功。

重回 Visual C++ 的終端機環境,使用以下指令編譯 gtk:

C:\tools\vcpkg> .\vcpkg install gtk:x64-windows

預設情形下,vcpkg 會編譯 32 位元的套件,但在 64 位元的系統上,不一定要守著 32 位元的機械碼,故此處改用 64 位元的套件。

(註:這類需要調整系統設定的問題,在當時並不少見,也反映了部分套件在 Windows 上的相容性問題。)

建置 GTK+ 版本的 Hello World 專案

接下來,應該要寫一些小程式來試試 gtk 套件;為了節省各位讀者的時間,筆者寫了一個 GTK+ 版本的 Hello World 程式,讓讀者省下寫程式的時間,專心學 vcpkg 的用法即可。讀者要自己重寫範例程式也可以,但要注意一定要寫相對應的 CMake 設定檔,因為 vcpkg 相關的設定檔也是用 CMake 寫的。

將工作目錄移動到專案所在的根目錄後,建立 build 子目錄:

C:\path\to\project> mkdir build
C:\path\to\project> cd build

若使用 Visual Studio 2017,則輸入以下的 CMake 指令:

C:\path\to\project\build> cmake .. -G"Visual Studio 15 2017" -DVCPKG_TARGET_TRIPLET=x64-windows -Ax64 -DCMAKE_PREFIX_PATH="C:/tools/vcpkg/installed/x64-windows" -DCMAKE_TOOLCHAIN_FILE="C:\tools\vcpkg\scripts\buildsystems\vcpkg.cmake" -DCMAKE_GENERATOR_PLATFORM=x64

(註:這裡使用的是 classic mode 的整合方式。後續版本的 vcpkg 已逐漸轉向 manifest mode。)

這個指令比較長,建議讀者不要硬背這個指令,而要去拆解該指令每個參數的意義,之後才能根據自己的需求去變化。

-G 代表指定 CMake 的 generator。CMake 跨平台的秘訣在於可以生成對應不同平台和編譯環境的專案設定檔。此處使用 "Visual Studio 15 2017",代表生成 Visual Studio 2017 的專案設定檔。

-D 代表專案的設定,在這個指令中,這些專案相關設定會傳到 Visual Studio 2017 的專案設定檔中。VCPKG_TARGET_TRIPLET 是設定 vcpkg 所用的目標架構 (參考這裡),此處選擇 x64-windows,代表是 64 位元的 Windows 平台。

(註:triplet 不只是「平台名稱」,還隱含了編譯方式與 ABI 設定,這也是 vcpkg 較難理解的一部分。)

CMAKE_PREFIX_PATH 是設定 vcpkg 中安裝套件所在的位置。由於 Windows 沒有採用類似於類 Unix 系統的 /user/include/usr/lib 等系統目錄,而是把套件集中在同一個目錄中,所以我們要自行指定該目錄所在的位置。如果讀者前往該目錄觀看,會發現該目錄內的架構很像類 Unix 系統中的系統目錄。

CMAKE_TOOLCHAIN_FILE 則是指定工具鍵所在的設定檔,這樣 CMake 才能吃到 vcpkg 的設定檔。同樣也是要自行指定 vcpkg 所在的目錄。

CMAKE_GENERATOR_PLATFORM 則是指定 generator 的平台,此處設為 x64,表示採用 64 位元架構。

若使用 Visual Studio 2019,只要修改 generator 的部分即可:

C:\path\to\project\build> cmake .. -G"Visual Studio 16 2019" -DVCPKG_TARGET_TRIPLET=x64-windows -Ax64 -DCMAKE_PREFIX_PATH="C:/tools/vcpkg/installed/x64-windows" -DCMAKE_TOOLCHAIN_FILE="C:\tools\vcpkg\scripts\buildsystems\vcpkg.cmake" -DCMAKE_GENERATOR_PLATFORM=x64

如果 Visual Studio 內附的 CMake 不夠新的話,會無法產生適用於 Visual Studio 2019 的專案,這時候可自行安裝新版的 CMake。

生成 Visual Studio 專案設定檔後,要手動修改專案的 VcpkgEnabled 屬性 (參考這裡):

<PropertyGroup Label="Globals">
    ...
    <VcpkgEnabled>true</VcpkgEnabled>
</PropertyGroup>

筆者無法確定為什麼 Visual Studio 要把這項屬性關閉,請手動調一下設定檔。

以本範例程式來說,要將 vcpkg/installed/x64-windows/lib/gtk-3.0.lib 複製一份,命名為 gtk.lib 並放在相同的目錄。要不然編譯時會報錯。

最後輸入以下指令即可編譯此範例程式:

C:\path\to\project\build> cmake --build . -- /t:Rebuild /p:Configuration=Release /p:Platform=x64

最後在 build/Release 目錄中,產生執行檔,點擊即可開啟視窗:

GTK+ 的 Hello World 程式

這裡展示的指令比較複雜,原本的出處在這裡,有需要的讀者可自行參考。

結語

對於使用 C 或 C++ 撰寫應用程式的開發者來說,vcpkg 的出現,確實試圖改善 Windows 上缺乏套件管理工具的情況。

不過在實際使用上,vcpkg 與其說是一個單純的套件管理器,不如說是整合建置流程的一部分。這也使得它在某些情境下相當方便,但在其他情境下則可能增加複雜度。

本文記錄的是當時的使用方式。隨著工具與生態的演進,實際的工作流程也可能有所不同,讀者可依自身需求選擇合適的工具與環境。

關於作者

位元詩人 (ByteBard) 是資訊領域碩士,喜歡用開源技術來解決各式各樣的問題。這類技術跨平台、重用性高、技術生命長。

除了開源技術以外,位元詩人喜歡日本料理和黑咖啡,會一些日文,有時會自助旅行。