CMakeとProtocol BuffersとVisual Studio 2015
Google Protocol Buffers を Visual Studio 2015 でビルドする手順と、Visual Studio 2015 プロジェクトからそれらを参照する方法を備忘録。なお以下 4 種類のビルドを行えるようにする:
- Win32 Debug
- Win32 Release
- x64 Debug
- x64 Release
Protocol Buffers をビルドする際の要点
- Protocol Buffers を Visual Studio 2015 でビルドするには CMake を使う
- 定義されている CMake のターゲット名として、自動単体テスト用の
check
、インストール用のinstall
がある - ビルド結果の単体テストには Google Mock, Google Test が使われている
- 自分で取ってきて配置するのは面倒なので、それらが同梱された
protobuf-cpp-x.x.x.zip
という名前のアーカイブを使うと楽で良い
- 自分で取ってきて配置するのは面倒なので、それらが同梱された
- ヘッダ・ライブラリのインストール先は
CMAKE_INSTALL_PREFIX
で指定- リリースビルドとデバッグビルドは、ライブラリファイル名が異なるため同一ディレクトリに配置可能
- Win32 版と x64 版は、ライブラリファイル名が同じなので異なるディレクトリに配置する必要あり
- 日本語環境では、単体テスト用ソースの一部で文字コード関連のエラーが発生する(少なくとも 3.3.0 の場合は)
- ビルドに先立って
_CL_
環境変数に/utf-8
を付けるか、問題のソースを修正してからビルドする
- ビルドに先立って
- よく分からないが Visual Studio プロジェクトファイルを生成した場合
msbuild
やcmake --build
から単体テストを実行すると失敗するので、単体テストだけはテストプログラムを直接起動する必要がある(少なくとも 3.3.0 の場合は) - Protocol Buffers を使うプログラムの方では、
find_package(Protobuf)
で検索すればよい
配置例
以下のように C:\Libraries
というディレクトリに Win32
と x64
という、各プラットフォーム向けのライブラリ一式を格納するサブディレクトリを作り、その下に Protocol Buffers のファイルを配置することにする:
C:\Libraries\Win32\bin C:\Libraries\Win32\include C:\Libraries\Win32\lib C:\Libraries\x64\bin C:\Libraries\x64\include C:\Libraries\x64\lib
ビルド・インストールの手順例
以下、protobuf-cpp-3.3.0.zip
に含まれる protobuf-3.3.0
を、C:\Source
に展開した前提で記す。
「Visual Studio 2015 開発者コマンドプロンプト」を開いてソースを展開したディレクトリに入り、次のように Visual Studio のプロジェクトファイルを生成する(コピペしたり、バッチファイルに転記できるようプロンプト部分は省略):
set _CL_=/utf-8 cd "C:\Source\protobuf-3.3.0\cmake" REM --- Visual Studio のプロジェクトファイルを生成 --- mkdir build\x64 cd build\x64 cmake ..\.. -A x64 -DCMAKE_INSTALL_PREFIX=C:\Libraries\x64 REM --- ビルドと単体テストの実行 --- cmake --build . --config Debug Debug\tests.exe
最初に _CL_
という環境変数を設定している点について補足。Protocol Buffers 3.3.0 に付属する単体テストのソースの一部には UTF-8 としても不正なデータ列が含まれている(そういうデータを正しく拒否できるかテストしている)。しかし、日本語環境では Visual Studio はソースファイルを Shift JIS だと思って解釈し始め、その不正なバイト列に出くわしたところで何かがオカシくなるらしく、その後のソースを正しく解釈できなくなってビルドに失敗してしまう。そこで、C/C++ 用コンパイルオプションに /utf-8
を強制的に追加することで対処すべく環境変数 _CL_
に設定を行っている。
また、日本語環境でビルドすると CommandLineInterfaceTest.Win32ErrorMessage
というテストが失敗すると思う。このテストの実装を読めば分かるけれど、日本語環境では確実に失敗する内容なので無視して良いと思う。
それと、ターゲット "check
" つまり check.vcxproj
をビルドすると単体テストができるのだけれど、Visual Studio の IDE で開いてビルドすればテスト成功するのに、msbuild
コマンド(したがって cmake --build
も)では、なぜか大半のテストが失敗してしまった。ただし上記のようにテストプログラムである tests.exe
を直接実行してやると成功するので、少なくとも生成されたライブラリが壊れていないことは確認できたと判断し、良しとした。
続いて、次のコマンドでインストールを行う:
cmake --build . --config Debug --target install
なおインストール先はプロジェクト生成時に指定した CMAKE_INSTALL_PREFIX
に従い、 C:\Libraries\x64
下に include
や lib
等が出力される。
以上で x64 版のデバッグビルドについては作業完了。続いて x64 版のリリースビルドを作成する。手順は同様。
cd "C:\Source\protobuf-3.3.0\cmake\build\x64" cmake --build . --config Release Release\tests.exe cmake --build . --config Release --target install
そして Win32 版のデバッグビルド、Win32 版のリリースビルドも同様に作成する:
cd "C:\Source\protobuf-3.3.0\cmake\build\Win32" cmake --build . --config Debug Debug\tests.exe cmake --build . --config Debug --target install cmake --build . --config Release Release\tests.exe cmake --build . --config Release --target install
Protocol Buffers を使うプログラム側
環境変数 CMAKE_PREFIX_PATH
または cmake
コマンド実行時のコマンドラインオプション -DCMAKE_PREFIX_PATH
で、C:\Libraries\Win32
または C:\Libraries\x64
のうち適切な方を設定しつつ Visual Studio プロジェクトを生成すれば良い。
次のような 3 ファイルしか無い単純なソースツリーのプロジェクトを前提にすると:
src/CMakeLists.txt src/example.cc # プロトコルバッファを使うプログラムのソース src/person.proto # プロトコルバッファ定義ファイル
CMakeLists.txt は次のような感じになった:
cmake_minimum_required(VERSION 2.8) project(CMakeExample_Protobuf) # Visual Studio には CRT ライブラリを静的リンクさせる(プロトコルバッファに合わせる) if(MSVC) string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG}) string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL}) string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE}) string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO}) string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL}) string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}) endif(MSVC) # プロトコルバッファのライブラリを検索する find_package(Protobuf REQUIRED) message(STATUS "PROTOBUF_INCLUDE_DIRS: ${PROTOBUF_INCLUDE_DIRS}") # デバッグ用 message(STATUS "PROTOBUF_LIBRARIES: ${PROTOBUF_LIBRARIES}") # デバッグ用 # "person.proto" から .pb.cc と .pb.h を生成し、生成されたソースとヘッダのファイル名を変数で受ける protobuf_generate_cpp(MY_PROTOBUF_SOURCES MY_PROTOBUF_HEADERS person.proto) message(STATUS "MY_PROTOBUF_SOURCES: ${MY_PROTOBUF_SOURCES}") # デバッグ用 message(STATUS "MY_PROTOBUF_HEADERS: ${MY_PROTOBUF_HEADERS}") # デバッグ用 # プロトコルバッファが生成した .pb.h のあるディレクトリを変数に入れておく set(MY_PROTOBUF_HEADER_DIR ${CMAKE_CURRENT_BINARY_DIR}) # 後は普通にプログラムをビルドするための定義をしていく add_executable(example example.cc ${MY_PROTOBUF_SOURCES} ${MY_PROTOBUF_HEADERS}) include_directories( ${PROJECT_SOURCE_DIR} ${PROTOBUF_INCLUDE_DIRS} ${MY_PROTOBUF_HEADER_DIR}) target_link_libraries(example ${PROTOBUF_LIBRARIES})