前書き
この記事はC++ Advent Calendar 2019 25日目の記事です。それにみんなさんメリークリスマス!
問題の縁起
C++プロジェクトには事情によって依存ライブラリの管理に対して以下の要件は常に必要になると思います:
- ビルド環境の仮定はしない方がいいであります。
- ライブラリの特定のバージョンを依存して、バージョン違うと依存関係が満たさないことにしないといけなりません。
CMakeを使ってプロジェクト組み立てれば、普通その要件がfind_package
で成し遂げることにすると思います。ただし、プロジェクトがビルドする前に備え付けたライブラリのバージョンが必ずあってることと仮定できないし、必要になったライブラリのバージョンもビルドする者から明示的に確保されなければならず、プロジェクトのドキュメントに載ることしかありません。なお、ライブラリのインストール先をCMakeがデフォルトで探せない場合、モジュールモードにもコンフィグモードにもビルドする者からインストール先のパスを手動に設定するのが必要になります。
cmake -DBOOST_ROOT=/path/to/boost -DProtobuf_ROOT=/path/to/protobuf -Drange-v3_ROOT=/path/to/mitama /path/to/project
依存したライブラリの数が増えるとライブラリのインストール先の設定もどんどん面倒になっちゃいます。まぁ、Makefile/Ninja/vcprojと比べればCMakeがライブラリ管理に対してよくやってたかもしれませんが、そのビルドプロセスを更に簡単になる方法がないのかと、自分は前に常に思います。
そしてその果に、VcPkgがいたんだ。
#VcPkg とは
VcPkgはマイクロソフト社が開発したC/C++向けのパッケージマネージャーです。歴史的にはいろんな認識と経緯がありましたが、現在は大抵「WindowsとLinuxとMacOS共に使うことができて、CとC++のパッケージ管理をより簡単にするソフト」として人々に認識されています。CMakeと一緒に使われるときは普通こうになります。
# ライブラリのインストール
PS D:\vcpkg> .\vcpkg install boost protobuf range-v3
# インストールされたライブラリをプロジェクトのCMake実行環境の中で設定する
PS D:\vcpkg> cmake -DCMAKE_TOOLCHAIN_FILE=".\scripts\buildsystems\vcpkg.cmake" \path\to\project
そしてプロジェクトのCMake実行環境にはfind_path
/find_library
/find_program
/find_package
などが、VcPkgのライブラリのインストール先を優先にして、探したかったものがあったらそのものを返すことになってしまうのです。
VcPkgの構造
本文に対して気になるべきだったのは以下です。
パス | 意味 |
---|---|
./ports/ |
パッケージとそのバージョンを定義するCONTROL 、及びインストールためのportfile.cmake というCMakeスクリプト |
./scripts/buildsystems/vcpkg.cmake |
VcPkgのパッケージのインストール先をプロジェクトのCMake実行環境の中で設定するためのツールチェインファイル |
./scripts/cmake/ |
./ports/ に置かれたportfile.cmake のためのヘルパースクリプト |
./scripts/toolchains/ |
OSごとの環境設定 |
./triplets/ |
トリプレットの定義 |
./vcpkg-root |
そのファイルがいたディレクトリが有効なVcPkgルートディレクトリと宣言する空きファイル |
なお、VcPkgでライブラリをインストールした後、以下のパスが現れています
パス | 意味 |
---|---|
./downloads/ |
ダウンロードされたビルドツールとパッケージのソース |
./installed/vcpkg/ |
インストールされたパッケージのメタデータ |
./installed/<triplet>/ |
トリプレットごとのパッケージのインストール先 |
./installed/<triplet>/debug/ |
トリプレットごとのパッケージのデバッグライブラリのインストール先 |
./packages/ |
パッケージのビルド先 |
問題の解決
最初から提出された問題の解決するため、VcPkgはこういうコマンドラインオプションがあります。
PS D:\vcpkg> .\vcpkg --help
--vcpkg-root <path> Specify the vcpkg root directory
(default: $VCPKG_ROOT)
つまりVcPkgは、他のVcPkgルートディレクトリを指定することができます。そして上の言った通り、VcPkgルートディレクトリがパッケージの情報とトリプレットの設定などを定義しているので、もしプロジェクト自分が上の言った必要なファイルを備えてVcPkgルートディレクトリを作れば、プロジェクトに必要されたライブラリ環境がビルド時に簡単に作ることができるようになります。
まぁ、いまのVcPkgの設計に限って自らのVcPkgルートディレクトリを作るにはまずVcPkgのところから./scripts/
をコピペするのが必要です(VcPkgのライセンスがMITだから多少はね?)。コピペが完了になると残るのはパッケージの定義とトリプレットの設定だけです。
詳しく解説すると面倒くさくなるので、とりあえずその使い方の例にするプロジェクトのレポをGitHubで立ち上げてみました( https://github.com/gnaggnoyil/vcpkg_usage_sample )。./vcpkg/
ディレクトリにパッケージのバージョンとトリプレットの環境設定を定義し、そのプロジェクトのビルド環境を備えたいときには以下のように行われます:
vcpkg install range-v3 --vcpkg-root ./vcpkg --triplet x64-linux-hoge
そしてCMakeを実行するときにはこうになります:
cmake -DCMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-linux-hoge .
ビルドする者からの明示的な設定がすべて不要で、プロジェクト側もライブラリのバージョン依存関係を簡単に仮定することができます。自分にとっては最初から提出された問題はこうやって少し完璧に解決することになりそうだと思います。まぁ、もともとVcPkgがそう使ってると設計するではなさそうなので、自分はそれVcPkgの「濫用」かもと思います(笑)。
それでは、今回言いたかったのは以上です。(文法の誤り)よくわからないがとりあえず投稿するヨン!