gRPC C++ の環境を構築する

めるぽん
13 min readSep 8, 2019

アプリケーションから gRPC C++ を利用できる環境を作るのは、CMake の add_subdirectory を使えばある程度簡単にできます。

しかし真面目にアプリケーションを作る時は add_subdirectory はオススメできません。理由としては、

  • サーバ用、クライアント用などで CMakeLists.txt を分けると通常はビルドディレクトリが変わるので、gRPC C++ を再度コンパイルしようとして時間が掛かる
  • gRPC C++ の依存関係を含めてビルドすると、ビルド済みであってもチェックだけで数秒掛かってしまい、ちょっとした変更なのに結構時間を使ってしまう
  • gRPC C++ とそれ以外のライブラリで利用方法が違ってしまい、扱いが面倒になる

あたりです。なのでここでは gRPC C++ を別途インストールして、それをアプリケーションから利用する方法について説明します。

Homebrew とか何かのリポジトリとか使ってインストールしてもいいですが、それだとバージョンの指定が出来ないし、プロジェクト毎に違うバージョンを利用したりもできなくて微妙なので自前でローカルにビルドします。

ソースの取得

単に git clone して目的のバージョンに切り替えて git submodule update -i するだけです。
ついでにビルドディレクトリやインストールディレクトリの変数も設定しておきます。

GRPC_VERSION=”1.22.0"
BUILD_DIR=”`pwd`/_build”
INSTALL_DIR=”`pwd`/_build”
mkdir -p $BUILD_DIR
cd $BUILD_DIR
git clone https://github.com/grpc/grpc.git grpc-source
cd grpc-source
git reset --hard v$GRPC_VERSION
git submodule update -i --recursive

gRPC C++ が依存しているライブラリのインストール

gRPC C++ はいくつかのライブラリに依存しているので、それをインストールしてやる必要があります。

ただ、それらのライブラリも gRPC の中に submodule として入っているので、単純に submodule からビルドしてインストールしてやるだけでいいです。

2020/2/5 追記: gRPC 1.27.0 で、単純に gRPC をインストールすれば BoringSSL, zlib, cares, protobuf がすべてインストールされるようになりました。そのため以下の依存ライブラリのビルドは不要になり、gRPC_*_PROVIDER=package という指定も不要になります。

インストールする依存ライブラリは BoringSSL, zlib, cares, protobuf です。
まずは BoringSSL から。

mkdir -p $BUILD_DIR/boringssl-build
cd $BUILD_DIR/boringssl-build
cmake $BUILD_DIR/grpc-source/third_party/boringssl \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$INSTALL_DIR/boringssl
make -j4
# make install はインストールするものが無いって言われるので
# 手動でインストールする
mkdir -p $INSTALL_DIR/boringssl/lib
cp ssl/libssl.a crypto/libcrypto.a $INSTALL_DIR/boringssl/lib
mkdir -p $INSTALL_DIR/boringssl/include
rm -rf $INSTALL_DIR/boringssl/include/openssl
cp -r $GRPC_SOURCE_DIR/third_party/boringssl/include/openssl $INSTALL_DIR/boringssl/include/openssl

BoringSSL は CMake でビルドできるので、それを使ってビルドします。
ただしインストールの設定はしてくれていないようなので、自前でコピーして所定の場所にインストールします。

続いて zlib。

cd $BUILD_DIR/grpc-source/third_party/zlib
./configure --prefix=$INSTALL_DIR/zlib --static
make -j4
make install
make clean

こっちは configure だったので、そのまま実行してるだけです。自分は静的ライブラリだけあればいいの--static を指定しています。
zlib のビルドオプションの詳細は ./configure --helpを参照してください。

次に cares。

mkdir -p $BUILD_DIR/cares-build
cd $BUILD_DIR/cares-build
cmake $BUILD_DIR/grpc-source/third_party/cares/cares \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$INSTALL_DIR/cares \
-DCARES_STATIC=ON \
-DCARES_SHARED=OFF
make -j4
make install

これも CMake なので普通に叩くだけ。静的ファイルだけでいいのでその辺の設定を入れてます。
詳細は cmake $BUILD_DIR/grpc-source/third_party/cares/cares -LH とか打って確認すると良いです。

最後に protobuf。

mkdir -p $BUILD_DIR/protobuf-build
cd $BUILD_DIR/protobuf-build
cmake $BUILD_DIR/grpc-source/third_party/protobuf/cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$INSTALL_DIR/protobuf \
-DCMAKE_PREFIX_PATH="$INSTALL_DIR/zlib" \
-Dprotobuf_BUILD_TESTS=OFF
make -j4
make install

これも CMake なので普通に叩くだけ。
ただ、protobuf は zlib に依存しているので、さっきインストールした zlib を探せるように `CMAKE_PREFIX_PATH` を設定しています。
また、テストは不要なのでビルド時間を減らすために除外しています。

これで gRPC C++ の依存ライブラリのインストールが出来ました。
うまくいってれば $INSTALL_DIR の下に boringssl/, zlib/, cares/, protobuf/ ディレクトリがあり、それぞれにライブラリがインストールされているはずです。

gRPC C++ のインストール

依存ライブラリがインストールできたので、次は gRPC C++ のインストールです。

mkdir -p $BUILD_DIR/grpc-build
cd $BUILD_DIR/grpc-build
cmake $BUILD_DIR/grpc-source \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$INSTALL_DIR/grpc \
-DgRPC_ZLIB_PROVIDER=package \
-DgRPC_CARES_PROVIDER=package \
-DgRPC_PROTOBUF_PROVIDER=package \
-DgRPC_SSL_PROVIDER=package \
-DgRPC_BUILD_CSHARP_EXT=OFF \
-DOPENSSL_ROOT_DIR=$INSTALL_DIR/boringssl \
-DCMAKE_PREFIX_PATH="$INSTALL_DIR/cares;$INSTALL_DIR/protobuf;$INSTALL_DIR/zlib"
make -j4
make install

gRPC C++ は CMake でのビルドもできるので、CMake を使っています。

gRPC_*_PROVIDER=package の指定は、依存ライブラリとして外部のライブラリを利用するという指定です。
add_subdirectory する場合には gRPC_*_PROVIDER=module を使って zlib や protobuf などのライブラリも一緒にビルドするという指定もできますが、こうやって gRPC C++ だけインストールする場合には gRPC_*_PROVIDER=module の指定はできません。module を指定した場合はインストールができなくなります。

C# 拡張用のライブラリは不要なので gRPC_BUILD_CSHARP_EXT=OFF しています。

BoringSSL, zlib, cares, protobuf は $INSTALL_DIR にインストールしたので、そのパスが探せるように OPENSSL_ROOT_DIR と CMAKE_PREFIX_PATH を指定しています。

これで gRPC C++ がインストールできました。あとはこれを利用するアプリケーションを書くだけです。

gRPC C++ を利用したアプリケーションの作成

CMakeLists.txt と同じディレクトリに helloworld.proto と helloworld.cpp があるとして、以下のように書きます。

cmake_minimum_required(VERSION 3.12)project(testapp C CXX)find_package(gRPC REQUIRED)set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
get_filename_component(HELLOWORLD_PROTO "./helloworld.proto" ABSOLUTE)
get_filename_component(HELLOWORLD_PROTO_PATH "${HELLOWORLD_PROTO}" PATH)
# Generated sources
set(HELLOWORLD_PROTO_SOURCES
"${CMAKE_CURRENT_BINARY_DIR}/proto/helloworld.pb.cc"
"${CMAKE_CURRENT_BINARY_DIR}/proto/helloworld.grpc.pb.cc")
set(HELLOWORLD_PROTO_HEADERS
"${CMAKE_CURRENT_BINARY_DIR}/proto/helloworld.pb.h"
"${CMAKE_CURRENT_BINARY_DIR}/proto/helloworld.grpc.pb.h")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/proto")
add_custom_command(
OUTPUT
${HELLOWORLD_PROTO_SOURCES}
${HELLOWORLD_PROTO_HEADERS}
COMMAND
${_PROTOBUF_PROTOC}
ARGS
--grpc_out "${CMAKE_CURRENT_BINARY_DIR}/proto"
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}/proto"
-I "${HELLOWORLD_PROTO_PATH}"
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
"${HELLOWORLD_PROTO}"
MAIN_DEPENDENCY
"${HELLOWORLD_PROTO}")
add_executable(testapp
${PROJECT_SOURCE_DIR}/helloworld.cpp
${HELLOWORLD_PROTO_SOURCES})
target_include_directories(testapp
PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/proto")
# set_target_properties(testapp
# PROPERTIES CXX_STANDARD 17 C_STANDARD 99)
target_link_libraries(testapp gRPC::grpc++)

gRPC C++ では proto ファイルから C++ コードを生成する必要があるので、生成方法を add_custom_command で指定しています。
この辺はまあ C++のサンプル を見ながら書くだけです。

C++ ファイルの出力は <ビルドディレクトリ>/proto に行われるようにしてるので、これを include できるように target_include_directories で指定しておきます。
あとは target_link_libraries でアプリケーションに gRPC::grpc++ をリンクすることを伝えます。これだけ指定しておけば、gRPC C++ だけでなく zlib や protobuf といったライブラリも一緒にリンクしてくれるようになります。

このアプリケーションをビルドする場合、以下のように cmake を実行してビルドすることになります。

INSTALL_DIR="`pwd`/_build"mkdir build
cd build
cmake .. \
-DOPENSSL_ROOT_DIR="$INSTALL_DIR/boringssl" \
-DCMAKE_PREFIX_PATH="$INSTALL_DIR/grpc;$INSTALL_DIR/cares;$INSTALL_DIR/protobuf;$INSTALL_DIR/zlib"
make -j4

gRPC C++ をビルドした時と同じで、インストール済みのライブラリを発見してもらうために OPENSSL_ROOT_DIR と CMAKE_PREFIX_PATH の指定が必要です。
ここが必要に応じてシェルスクリプトを作っておくといいでしょう。

これで build/testapp が生成されるはずなので、それが実行できるようになれば環境構築完了です。

--

--