vcpkgに新しいパッケージを追加する方法

vcpkgはMicrosoftがオープンソースで開発している、Windows用のC++パッケージマネージャです。コマンドラインから使用したいライブラリをインストールするだけで、面倒くさいインクルードパスの設定、ライブラリディレクトリの設定、依存ファイルの設定などを行わずに簡単にライブラリを使用することができる優れものです。


vcpkgは公式で大量のパッケージが用意されていますが、さすがにネット上に存在するあらゆるライブラリをパッケージとして含むことは不可能なので、標準では用意されていないパッケージが当然存在します。そのようなライブラリについても、vcpkgにはパッケージとして追加する手段が提供されています。今回はこの方法について説明していきたいと思います。vcpkgの使い方については公式のドキュメントが存在するので、各関数の詳細などはそちらをご覧ください。


なお、ここでの説明はスタティックライブラリの場合の場合で、ダイナミックライブラリについては想定していないのでご了承ください。ダイナミックライブラリの場合でも出力先のディレクトリ以外は同じだと思います。


vcpkgのパッケージインストールの流れ


パッケージの追加の説明に入る前に、vcpkgがパッケージをインストールする流れを説明しておきます。
vcpkgがインストール時に用いるフォルダは大きく4つあります。

  • downloads: ネットからダウンロードしたソースコードのアーカイブが置かれる場所
  • buildtrees: ダウンロードしたアーカイブが展開され、ビルドなどを行う場所
  • packages: 公開するためのビルド済みファイルなどをおく場所
  • installed: 実際に利用されるパッケージファイルをおく場所 

これらのディレクトリを使用して、vcpkgは以下の流れでパッケージをインストールしていきます。

  1. ソースコードのアーカイブファイルをdownloadsにダウンロード
  2. アーカイブをbuildtrees/[ポート名]/srcに展開
  3. 必要ならbuildtrees/[ポート名]/src内でビルド
  4. 生成されたライブラリファイルやインクルードファイルをpackages/[ポート名]にコピー
  5. packages/[ポート名]/のファイルをinstallebd/ディレクトリ下の対応するトリプレットのディレクトリにコピー

最後のコピーはvcpkgが自動で行ってくれるので、パッケージを追加するために1~4の手順を後術のポートファイル内で定義していくことになります。


パッケージの追加


本題のパッケージの追加方法の説明に入ります。パッケージの追加には公式ドキュメントにその例が載っています。


vcpkgに新たなパッケージを追加するためには、CONTROLとportfile.cmakeの二つのファイルを作成する必要があります。CONTROLはパッケージの情報を記述するファイル、portfile.cmakeはアーカイブファイルのダウンロードからビルドしたライブラリファイルの配置までを定義するファイルです。この二つのファイルの記述方法について、それぞれ説明していきます。

CONTROLとportfile.cmakeのテンプレート生成

この得体の知れないファイルを一から作るのは難しいなぁ。と思う方がいるかもしれませんが(僕だけかもしれませんが)、素晴らしいことに、vcpkgにはこの二つのファイルのテンプレートを生成してくれる機能があります。

vcpkg.exe create [パッケージ名] [ソースコードアーカイブのダウンロードURL] ([アーカイブの保存名])

それぞれの引数の詳細は以下のとおりです。

  • パッケージ名
vcpkgでパッケージのインストールなどを行う時に用いられるもので、分かりやすい名前を英数字とハイフンのみを用いて決めます。
  • ソースコードアーカイブのダウンロードURL
ソースコード一式が入ったzip、tar形式のアーカイブのダウンロードURLを入力します。GitHubの特定のコミットなどを用いたい場合はhttps://github.com/[GitHubアカウント名/リポジトリ名]/archive/[タグ又はコミットハッシュ].tar.gzを指定することができます。
  • アーカイブの保存名
この引数はオプションで、ダウンロードしたアーカイブファイルを保存するときの名前を指定します。指定しなかった場合はダウンロードしたファイル名がそのまま使われます。公式ドキュメントによると[パッケージ名]-[バージョン番号].[拡張子]にするのが望ましいようです。

これらを指定して上記コマンドを実行すると、portsディレクトリ内にCONTROLとportfile.cmakeが入ったパッケージ名のディレクトリが作成されます。この生成されたテンプレートを基に、正しくインストールできるように修正を行っていきます。

CONTROL

生成されたテンプレートの"Source"にパッケージ名、"Version"にバージョン、"Description"に説明、そして"Build-Depends"にビルド時の依存ライブラリを定義します。"Build-Depends"はテンプレートには含まれていないので、必要なら末尾に追加しましょう。
CONTROLファイルについてはこれだけなので、特に迷うことはないでしょう。パッケージ名には英数字とハイフンのみを用いることができます。

portfile.cmake

このファイルがvcpkgのキモ(だと勝手に思ってる)で、一番時間がかかるであろうところです。このファイルでは大まかに以下の流れで処理を行います。

  • アーカイブのダウンロードと展開
  • パッチの適用(必要なら)
  • ビルド
  • packagesディレクトリの適切な場所に必要ファイルをコピー

ポートファイルではvcpkgで定義されている変数や関数が使用できます。
定義されている変数一覧は、ポートファイル内に以下を追加して実行することで確認することができます。(下記コードは座敷牢日誌「CMakeで設定されているすべての変数を出力する」より引用)

message(STATUS "*** dump start cmake variables ***")
get_cmake_property(_variableNames VARIABLES)
foreach(_variableName ${_variableNames})
        message(STATUS "${_variableName}=${${_variableName}}")
endforeach()
message(STATUS "*** dump end ***")

関数についてはvcpkg公式ドキュメントに載っています。

アーカイブのダウンロードと展開

これはテンプレートで生成されたコードの状態で行ってくれます。
vcpkg_download_distfileがアーカイブのダウンロードを、vcpkg_extract_source_archiveがその展開をしています。
一つだけ変更しなければならない点は、SOURCE_PATHの設定です。標準では"${CURRENT_BUILDTREES_DIR}/src/[アーカイブ保存名]"になっていますが、ここを"${CURRENT_BUILDTREES_DIR}/src/[アーカイブを展開した時にできるディレクトリ名]"に変更してください。一度自分でアーカイブをダウンロードして展開し、どのような名前のディレクトリが作成されるのか確認すると良いでしょう。

ソースファイルがGitHubやBitbucketにある場合は、vcpkg_download_distfileとvcpkg_extract_source_archiveの代わりにvcpkg_from_githubやvcpkg_from_bitbucketを使います。詳細は公式ドキュメントをご確認ください。

パッチの適用(必要なら)

公開されているソースコードがそのままではビルドができない場合などは、自分でソースコードを修正してパッチファイルを作り、パッチの適用を行うようにする必要があります。パッチの適用についても公式のドキュメントで例が示されています。


パッチの作成から適用の記述までおおまかに説明します。

パッチの作成にはgitのdiffコマンドを使用します。まずはアーカイブファイルをダウンロード、展開し、PowerShellでそのディレクトリに移動してください。そこで

git init
git add .
git commit -m "適当なコメント"

でリポジトリの初期化から現在の状態をリポジトリに反映するまで行います。
そして正しくビルドでできるようにソースコードを修正します。修正したら、addやコミットはせずに、以下のコマンドでパッチファイルを作成します。

git diff | out-file -enc [ソースコードの文字コード] [任意のパッチファイル名]

公式ドキュメントでは-encオプションの値としてasciiが指定されていますが、ソースコードに日本語などのASCIIコードで表せない文字が入っている場合、パッチの適用に失敗する可能性があります。その場合は-encのオプションにソースコードのも文字コードを指定すると上手くいくようです。

パッチファイルが作成できたら、できたパッチファイルをポートディレクトリにコピーします。
そしてポーチファイルにパッチ適用のコードを追加しましょう。パッチ適用には以下の関数を使います。

vcpkg_apply_patches(
    SOURCE_PATH ${SOURCE_PATH}
    PATCHES ${CMAKE_CURRENT_LIST_DIR}/[パッチファイル名]
)

これをアーカイブ展開のコードの下に入れます。

ビルド

MSBuild、CMakeなどさまざまなビルド方法に対応した関数が定義されています。それぞれ公式ドキュメントで説明されているので、確認してください。基本的には対応する関数を適切な引数とともに呼び出せば済みます。

vcpkgはソースコードベースのパッケージマネージャで、ビルドを利用者の環境で行うため、バイナリファイルの互換性の問題などが発生しにくいことが売りの一つになっています。そのため、ソースコードをビルドしてライブラリを生成するのがvcpkgとしては自然な流れですが、ビルド済みライブラリを用いてビルドを行わない事もできます。この場合は、ビルド済みライブラリを含むアーカイブをダウンロードしてこのステップを飛ばし、アーカイブを展開して得られたビルド済みライブラリを次の章の説明に従ってpackagesディレクトリに配置することになります。

packagesディレクトリの適切な場所に必要ファイルをコピー

各種ファイルを以下の場所にコピーする必要があります。

  • ヘッダファイル: ${CURRENT_PACKAGES_DIR}/include
  • リリースビルド用ライブラリ: ${CURRENT_PACKAGES_DIR}/lib
  • デバッグビルド用ライブラリ: ${CURRENT_PACKAGES_DIR}/debug/lib
  • ライセンスファイル: ${CURRENT_PACKAGES_DIR}/share/[ポート名]/copyright

CURRENT_PACKAGES_DIRはvcpkgで定義されている変数で、packageディレクトリ内の現在のパッケージ用の場所を示しています。ヘッダファイルオンリーなライブラリの場合は、ライブラリ用ファイルのコピーは必要ありません。

コピー時によく使うcmakeのコマンドと簡単な説明を以下に列挙しておきます。
 


file(COPY [コピー元のファイルパス] DESTINATION [コピー先のディレクトリ])
file(COPY [コピー元のファイルパス] DESTINATION [コピー先のディレクトリ] RENAME [コピー先のファイル名])

ファイルのコピーを行います。最後にRENAMEを指定することで、コピー先のファイル名を変更することができます。


file(INSTALL [コピー元のファイルパス] DESTINATION [コピー先のディレクトリ])
file(INSTALL [コピー元のファイルパス] DESTINATION [コピー先のディレクトリ] RENAME [コピー先のファイル名])

基本的にはCOPYと同じですが、INSTALLの場合はメッセージが出力されます。


file(GLOB [結果を格納する変数名] [検索パターン])

パターンに一致するファイルのパスリストを指定された変数に格納します。検索パターンはファイルパスに以下のものがを混ぜたものです。

パターンに使うことができるのは
  • *: 0文字以上の任意の文字列
  • ?: 任意の一文字
  • [abc]: カッコ内の一文字
  • [a-z]: ハイフン両端の文字に挟まれた一文字。大文字小文字は区別されない

この関数による結果をCOPYやINSTALLに渡すことで、複数ファイルにたいしてまとめて処理を行うことができます。


file(RENAME [対象のファイル/ディレクトリパス] [名前変更後のファイル/ディレクトリ名])

ファイルやディレクトリの名前を変更します。


file(DOWNLOAD [ダウンロード元のURL] [ダウンロードしたファイルの保存パス])

Webからファイルをダウンロードします。

この他にも色々コマンドがあるので、CMakeのドキュメントを確認してください。


ポートファイルはこれで完成です。次に実際にインストールしてみましょう。

インストールしてみる 

インストールは以下のコマンドで行なえます。トリプレットは対象のプラットフォームのことを指します。"x86-windows"や"x64-windows-static"などです。

vcpkg.exe install [パッケージ名]:[トリプレット]

エラーメッセージが出たらそれを見て修正していきます。これを繰り返して、インストールが成功するようになれば完了です。代表的なエラーメッセージ(おそらく)は以下の通りです

Contains invalid characters. Only alphanumeric lowercase ASCII characters and dashes are allowed
不正な名前のパッケージ名をインストールしようとした時に起こります。ポート名には英数字とハイフンしか使えません。ドット(.)やアンダースコア(_)などが入っていないか確認しましょう。

Downloading [ダウンロードURL]... Failed. Status: 22;"HTTP response code said error"
アーカイブのダウンロードに失敗した時に起こります。アーカイブファイルのURLが誤っていないか確認してください。

 File does not have expected hash:
ポートファイルのテンプレート作成後にアーカイブのダウンロードURLを変更したことなどが原因で、アーカイブファイルのハッシュ値とポートファイル内で記述されているハッシュ値が一致しない状態になっています。vcpkg_download_distfile関数のSHA512引数に正しいハッシュ値を指定する必要があります。ここで必要なSHA512ハッシュはPowerShellを用いて以下のように取得できます。

certutil -hashfil [アーカイブファイル名] SHA512


ビルドに失敗した
ビルドの標準出力とエラー出力の内容が保存されたファイルの場所がエラーメッセージに書かれているはずなので、確認して対処しましょう。それらのファイルに何も出力されていない場合は、そもそもビルドコマンドが失敗した可能性があるので、ポートファイルのビルドに用いた関数の引数などを改めて確認してください。

Applying patch failed. This is expected if this patch was previously applied.
二回目以降のインストールの試行ですでにパッチが適用されている場合、このエラーメッセージは問題ありません。
はじめてのインストールでこのエラーが出た場合は文字コードが原因の可能性があります。パッチの作成の章で説明した通り、パッチファイルとソースコードの文字コードを同じにしてみましょう。

The folder [/include、/lib又は/debug/lib] is empty or not present. This indicates the library was not correctly installed.
packagesディレクトリの指定場所にヘッダファイル又はライブラリファイルが存在しません。ちゃんとコピーできているか、確認しましょう。

Mismatching number of debug and release binaries. Found [debug/libディレクトリのファイル数] for debug but [libディレクトリのファイル数] for release.
リリース用ライブラリファイルをデバッグ用ライブラリファイルの数は等しくないといけません。コピーのミスがないか確認してみましょう。

The software license must be available at ${CURRENT_PACKAGES_DIR}/share/[ポート名]/copyright
/share/[ポート名]/copyrightが存在しない時に起こります。
ダウンロードしたアーカイブにLICENSEなどが含まれているなら、それを/share/[ポート名]/copyrightにコピーします。Web上にあるならダウンロードして/share/[ポート名]/copyrightにコピーします。ダウンロードできないような場所にあるなら、その内容をテキストファイルに保存してportfile.cmakeと同じディレクトリに置き、それを/share/[ポート名]/copyrightにコピーするようにすれば良いと思います。

その他

SOURCE_PATHが誤っている可能性があります。生成されたテンプレートで設定されているSOURCE_PATHは"[対象のポートディレクトリ]/src/[アーカイブのダウンロード名]"となっているので、アーカイブの展開で生成されるディレクトリ名を確認して"[対象のポートディレクトリ]/src/[展開で生成されるディレクトリ名]"に変更してみてください。


少し端折ってしまった部分もありますが、これがvcpkgにパッケージを追加する際の一連の流れになります。公式のマニュアルや実際のポートファイルも参考になるので、つまずいたり迷ったら除いてみると解決するかもしれません。

vcpkgにパッケージを追加する上でつまずいた点などをまとめた記事も公開しているので、そちらも参考にしてください。


質問や間違いなどありましたら、気軽にコメントしてください。


参考文献


スポンサーサイト



コメント

コメントの投稿

非公開コメント

プロフィール

Cdec

Author:Cdec
情報系修士出身のIT企業会社員。趣味で変なゲームを作ったり、気まぐれにゲームしたりしています。
研究ではDeepLearning関連のことをしていました。

■メインPC
Win10Pro, Corei7-9700K, DDR4 16GB, SSD 256GB, HDD 2TB*2, RTX2060
■サブPC
Win10Pro, Corei5-8250U, DDR4 8GB, SSD 256GB
■サブサブPC
Win10Pro, Corei5-3337U, DDR3 4GB, SSD 256GB
■ファイルサーバー
WinServer2016Standard, DDR4 4GB, Corei5-6500, SSD 128GB, HDD 750GB*2+1TB
■開発環境&ライブラリ
ゲーム開発ではVisualStudio, Unity, DXライブラリ、研究ではVisualStudioCode, Caffe, Chainer
■使う言語
ゲーム開発ではC++やC#、たまにLuaで、研究ではPython