Tech Notes

OpenSiv3Dとvcpkgを同居させたら(やや)面倒なことになった話

結論から言って設定一つで解決する程度の話だったのだが、割と手間取ったのでメモ。

Siv3Dはゲームとかビジュアライザの類をモダンなC++で作れるフレームワークだ。自分はC++が好きなので愛用している。

vcpkgはC/C++のライブラリをパッケージとして管理できるツールだ。自分はC++が好きなので愛用している。

ある日のこと、Siv3Dでちょっとゲームを作るかーと思ってVisual StudioでSiv3Dのプロジェクトを作成したら、コンパイルが通らなかった。公式配布のテンプレートだぞ?なぜコンパイルが通らない。

出てきたエラーは以下の通り。

1>libpng16.lib(pngtrans.obj) : error LNK2005: png_set_add_alpha は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngtrans.obj) : error LNK2005: png_set_packing は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngrtran.obj) : error LNK2005: png_set_expand_gray_1_2_4_to_8 は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngrtran.obj) : error LNK2005: png_set_gamma は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngrtran.obj) : error LNK2005: png_set_gray_to_rgb は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngrtran.obj) : error LNK2005: png_set_palette_to_rgb は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngrtran.obj) : error LNK2005: png_set_scale_16 は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngrtran.obj) : error LNK2005: png_set_tRNS_to_alpha は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(png.obj) : error LNK2005: png_create_info_struct は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(png.obj) : error LNK2005: png_destroy_info_struct は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(png.obj) : error LNK2005: png_get_io_ptr は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngwrite.obj) : error LNK2005: png_create_write_struct は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngwrite.obj) : error LNK2005: png_destroy_write_struct は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngwrite.obj) : error LNK2005: png_set_filter は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngwrite.obj) : error LNK2005: png_write_end は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngwrite.obj) : error LNK2005: png_write_info は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngwrite.obj) : error LNK2005: png_write_png は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngwrite.obj) : error LNK2005: png_write_row は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngwio.obj) : error LNK2005: png_set_write_fn は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngset.obj) : error LNK2005: png_set_IHDR は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngset.obj) : error LNK2005: png_set_rows は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngget.obj) : error LNK2005: png_get_IHDR は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngget.obj) : error LNK2005: png_get_channels は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngget.obj) : error LNK2005: png_get_gAMA は既に libpng16.lib(libpng16.dll) で定義されています。
1>libpng16.lib(pngget.obj) : error LNK2005: png_get_valid は既に libpng16.lib(libpng16.dll) で定義されています。

どういう訳だか分からないが、 libpngの関数などが二重に定義されているようだった。 Siv3Dの再インストールなどを試してみたが効果はなく、同じエラーが出るばかりである。どうしたものか。

ところでVisual Studioには、システムにvcpkgがインストールされていた場合(※)、自動的に連携する仕組みがある。特に何の設定もされていないC++プロジェクトの場合、Visual Studioはvcpkgでインストールされたライブラリを自動的に読み込もうとする。

(※): 正確にはvcpkg integrate installされていた場合

もしやと思いプロジェクトの設定を確認すると、果たしてVcpkgとの連携は有効になっていた。

これを無効にしてやる。

すると何の障害もなくするりとビルドが通ったのであった。これにて一件落着である。

教訓

今回の問題の原因は、自分がvcpkgで「たまたま」libpngのパッケージをインストールしていたことであり、そしてSiv3Dが「たまたま」libpngを用いるフレームワークであり、愚かなVisual Studioがその二つを同時に取り込んで衝突させたからであった。

Visual Studioを使っていてなおかつvcpkgをインストールしている環境で開発する場合、vcpkg以外からライブラリを取り込む場合は「このプロジェクトではvcpkgは使いませんよ」と明示的に設定しないと衝突する危険性がある。

vcpkgはライブラリの管理という点では便利だが、あまり考えなしにvcpkg integrate installを使っているとちょいちょい痛い目に遭う。