由于项目需求,准备在嵌入式上使用rpc方案,调研了多个方案,最终由于Grpc和protobuf天然的亲和性,决定对Grpc进行移植。
Grpc地址:https://github.com/grpc/grpc
Grpc的交叉编译支持三种方式:bazel,cmake,makefile;bazel 由于编译太麻烦,主要适合google内部,直接放弃了,本文主要讲解基于cmake的交叉编译方式,makefile 也是类似方式。
一 交叉编译
1. 首先下载Grpc:
git clone git@github.com:grpc/grpc.git
2. 由于Grpc 依赖较多的第三方库,我不想在系统中都安装,所以更新submodule
git submodule update --init
3. 交叉编译,grpc 交叉编译比较麻烦,主要原因时grpc 中包含了很多动态生成的操作,比如:使用protoc 生成protobuf的code,使用protoc-plugin 生成rpc的code;这些操作都时在编译时执行的,而我们编译的系统时ARM上的所以运行会报错,解决这些问题的办法就是关闭无用的处理,或替换为X86的工具,具体命令如下:
make build; // 创建编译临时目录
cmake -DCMAKE_TOOLCHAIN_FILE=XXX.cmake -DgRPC_PROTOBUF_PROVIDER=package -DgRPC_PROTOBUF_PACKAGE_TYPE=MODULE -DProtobuf_PROTOC_EXECUTABLE=/usr/local/bin/protoc -DgRPC_BUILD_GRPC_PYTHON_PLUGIN=OFF -DABSL_RUN_TESTS=OFF ../
实际编译时,由于有些工具会依赖protoc,会报很多编译的错误,可以使用以下命令,关闭所有plugin
cmake -DCMAKE_TOOLCHAIN_FILE=XXXX.cmake -DgRPC_PROTOBUF_PROVIDER=package -DgRPC_PROTOBUF_PACKAGE_TYPE=MODULE -DProtobuf_PROTOC_EXECUTABLE=/usr/local/bin/protoc -DgRPC_BUILD_GRPC_PYTHON_PLUGIN=OFF -DgRPC_BUILD_GRPC_PHP_PLUGIN=OFF -DgRPC_BUILD_GRPC_OBJECTIVE_C_PLUGIN=OFF -DgRPC_BUILD_GRPC_NODE_PLUGIN=OFF -DgRPC_BUILD_GRPC_CSHARP_PLUGIN=OFF -DgRPC_BUILD_GRPC_CPP_PLUGIN=OFF -DgRPC_BUILD_CODEGEN=OFF -DgRPC_BUILD_CSHARP_EXT=OFF -DgRPC_BUILD_GRPC_RUBY_PLUGIN=OFF -DABSL_RUN_TESTS=OFF -DBUILD_TESTING=OFF -DCARES_BUILD_TOOLS=OFF -DCMAKE_INSTALL_PREFIX=XXXX ..
此外,还有几个工具编译也需要屏蔽以下,CMAKE没有选项只能屏蔽CMakeLists
PS:此处将protobuf 设置为X86安装的protoc工具,其中package 表示直接从系统中查找,否则要编译grpc自带的third,需要设置为module,参照:https://stackoverflow.com/questions/52202453/cross-compiling-grpc-using-cmake
4. 执行编译操作,我们只需要使用rpc功能,所以只编译一个模块
cmake --build . --target grpc++_unsecure
因为是内部通信,所以我编译的时unsecure,否则可以编译
cmake --build . --target grpc++
PS: 此处要说明一下,如果想查看有哪些可以编译的模块,可以执行 make help
5. 目前编译 grcp++_reflection 会报错:_gRPC_CPP_PLUGIN-NOTFOUND: program not found or is not executable
由于我没用到就放弃了
二 执行测试用例
1.编译protobuf库
cmake -DCMAKE_TOOLCHAIN_FILE=XXX.cmake -Dprotobuf_BUILD_TESTS=OFF ..
2. 编写protobuf 文件
包含rpc的protobuf 文件和常规的唯一区别,就时定义一个rpc 的service,用例如下:
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name =