📚

[vcpkg/CMake] バージョンを指定してパッケージを導入する (マニフェストモード)

2022/11/13に公開

vcpkgについて

C/C++向けのパッケージマネージャです。[1]
https://github.com/microsoft/vcpkg

サクッと使う分には簡単に始められます。以下はboostを使う例です。多くのvcpkgに関する情報で見られるこの使い方を「クラシックモード」と言い、本記事では省略します。

vcpkg install boost:x64-windows
vcpkg integrate install

この方法の課題は、導入するパッケージのバージョン指定が(2022年現在)できない [2] ことです。それを可能にする方法がだいぶ癖があり、メモしておきます。

以下を参考にしました。

筆者の環境

以下のコマンド入力はPowerShellを想定しています。(PowerShellである必要はありません。)

事前準備

例として、OpenCVを利用するプログラムをビルドしたい、という課題とします。

例題のソースコード

OpenCVのビルド情報を見るだけの、画像処理要素ゼロの簡単コードです。

main.cpp
#include <opencv2/opencv.hpp>
#include <iostream>

int main()
{
    std::cout << cv::getBuildInformation() << std::endl;
    return 0;
}

CMake

上のコードをビルドするためのCMakeを設定します。CMakeLists.txtという名前で、C++ソースコードの隣に置きます。

CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(my-opencv-sample)

find_package(OpenCV REQUIRED)

include_directories(
    ${OpenCV_INCLUDE_DIRS}
)

add_executable(
    ${PROJECT_NAME} main.cpp
)

target_link_libraries(
    ${PROJECT_NAME} ${OpenCV_LIBRARIES}
)

もしCMakeの導入がまだであれば、以下から入手しインストールします。Release CandidateでもStableでもどちらでもほぼ問題ないと思われます。
https://cmake.org/download/

過去の導入から時間が経っている場合も再インストールをお勧めします。Visual Studioの活発な更新のため、古いCMakeでは「ビルドツールセットが見つかりません」といったエラーになることがあります。

vcpkg

公式の手引き通り導入します。

> git clone https://github.com/microsoft/vcpkg
> .\vcpkg\bootstrap-vcpkg.bat

本記事では C:/lib/vcpkg に置いたものと仮定しています。

OpenCVという例題に起因する話でもありますが、vcpkgはディスクをかなり消費しがちで、ディスク容量は潤沢に確保しておいてください。今回であれば最低10GBくらいは欲しいです。

マニフェストモード

vcpkgのもう一つの使い方がマニフェストモードといいます。vcpkgのパッケージデータをマシン上の1か所で集中管理ではなく、各プロジェクト単位で管理するという方式です。RustのCargo, Rubyのbundler, Pythonのpyproject.toml のようなものでしょうか。

vcpkgでは、vcpkg.json というJSONファイルにパッケージ設定を書きます。CMakeLists.txtの隣に置きます。

vcpkg.json
{
  "name": "my-opencv-project",
  "version-semver": "1.0.0",
  "builtin-baseline":"6f7ffeb18f99796233b958aaaf14ec7bd4fb64b2",
  "dependencies": [
    { "name": "opencv4", "version>=": "4.5.5" }
  ],
  "overrides": [
    { "name": "opencv4", "version": "4.5.5" }
  ]
}

2点、注意があります。

builtin-baselineとは?

謎のハッシュ値がありますね。一度指定せずに後述のCMake実行してみると、以下のように怒られ、答えを教えてくれます。とりあえずはそれをコピペしましょう。ですので初めての実行であれば空欄にでもしておきましょう。

> cmake -S . -B build
- Building for: Visual Studio 17 2022
-- Running vcpkg install
the top-level builtin-baseline () was not a valid commit sha: expected 40 hexadecimal characters.You can use the current commit as a baseline, which is:
        "builtin-baseline": "6f7ffeb18f99796233b958aaaf14ec7bd4fb64b2"

vcpkgリポジトリのコミットハッシュ値らしいです。後日vcpkgを更新したい場合は、最新のpullだけでなくこの値も要更新ですね。

なぜバージョンを2回書いている?

以下が参考になります。変な仕様ですね。
https://kenkyu-note.hatenablog.com/entry/2021/06/22/212309

突如として出現したフィールド"overrides"の中に"dependencies"のバージョンを上書きする情報を記入する。何この謎仕様。ここに記入されたバージョンは"builtin-baseline"や"version>="よりも優先され、boostは1.64.0に固定される。fmtの方はoverridesには何も記されていないので、バージョンは固定されず"builtin-baseline"以上のものがインストールされる。

完全に固定しなくてよいなら、overridesのほうを省いても良いです。

CMakeの実行

vcpkg.json を置いたら、cmakeを実行します。DCMAKE_TOOLCHAIN_FILEにvcpkgのツールチェインパスを指定することで、自動的にvcpkgを使ってくれます。

> cmake `
-S . `
-B build `
-G "Visual Studio 17 2022" `
-A x64 `
-D CMAKE_TOOLCHAIN_FILE=C:\lib\vcpkg\scripts\buildsystems\vcpkg.cmake

長時間かかります。OpenCVの依存から本体まで、自動的にダウンロードしてはビルドしていきます。終わると、build/以下にビルド用の各種ファイルが生成されます。今回の場合はVisual Studio向けの.vcxprojなどの構成ファイルです。

.vcxprojファイルを開いてGUIからビルドしても構いません。コマンドのまま進めたければ例えば以下のようにします。

> cmake --build build

これで念願の.exeが出来上がりました。

> ./build/Debug/my-opencv-sample.exe

General configuration for OpenCV 4.5.5 =====================================
  Version control:               unknown

  Platform:
    Timestamp:                   2022-11-13T02:22:38Z
    Host:                        Windows 10.0.19044 AMD64
    (以下略)

2022年11月現在、vcpkgで普通にopencv4を取得すると4.6.0が入るはずのところ、4.5.5にできているのが確認できました。

思うところ・注意点

  • いまのところvcpkg.jsonは手打ちしかないと理解しています。コマンドでのサポートが欲しいですね。
  • バージョン固定はこれで完璧、と言いたいところですが、現実にはうまくいかない例が多いです。例えばOpenCVでは、本記事で述べた4.5.5はできるのですが、4.5.1や4.5.2等はvcpkgによる依存ライブラリのビルドにてエラーになります。特定の番号にこだわりなく、何でもよいから固定しておきたいのであればよいですが、訳あって決め打ちのバージョンが欲しい場合は運次第です。
    • あまりvcpkg自体がバージョン固定に向いていない所感はあります。このマニフェストモードのサポートも結構最近ようやくであり、その前後で不満を述べるコメントが散見されます。 [3] [4]
    • vcpkgをフォークして、所望のバージョンが得られる古い状態に戻したりパッチを当てるなどお好みの状態にしたうえでクラシックモードを使うのが、マニフェストモードを一通り触った今でも何だかんだ無難という所感になってしまいました。例にしたOpenCVが大規模で複雑過ぎた説もありますが。
脚注
  1. Microsoftが出していることや、"vc" という名づけに関わらず、Windows以外でも利用可能です。 ↩︎

  2. 公式の最新vcpkgを取得してシンプルに使う場合 ↩︎

  3. コメントの例1: https://github.com/Microsoft/vcpkg/issues/1681#issuecomment-487154857 ↩︎

  4. コメントの例2: https://github.com/Microsoft/vcpkg/issues/1681#issuecomment-933054175 ↩︎

Discussion