后端开发

Linux 系统编译安装基于 C++ 的 gRPC

04 月 22 日 2021 年

本文适用于 C++ 版本 gRPC 的离线编译安装,但对于下载 gRPC 步骤强烈建议使用 git 进行。

如果在能直接连接外网的机器上编译,可直接按照 gRPC 官网文档的指引快速执行编译操作。

安装基本依赖

确保机器上包括这些基本依赖:autoconf, libtool, pkg-config 与 C++ 编译环境。

# 检查是否有 autoconf
which autoconf

# 如果没有,则安装
# CentOS
yum install autoconf
# Ubuntu
apt-get install autoconf

gRPC 的编译需要 gcc 版本在 4.9 及以上。假如版本低于此,应当在 Docker 容器中安装较新版本的 GCC 再执行编译操作。

我使用 gcc 4.9.4 成功编译 gRPC 1.28.x,另外有人测试4.9.2, 5.3.1 以及 7.3.1 版本编译成功;而我使用撰写此文时使用最新版本 10.3.0 编译报错,请读者加以选择。

更新 GCC 的方法可以参考我的这一篇博客

# 查看 gcc 版本
gcc -v

如果机器上没有 gccg++ 等,可以安装 Development Toolsbuild-essential 软件包。

# CentOS
yum groupinstall "Development Tools"
# Ubuntu
apt-get install -y build-essential

安装 CMake

make 是 gRPC 以前使用的构建命令,但是官方文档不再建议使用它。应使用 bazelcmake 代替。此处我们选择使用 cmake 执行编译。

执行下述命令,如果没有找到命令则需要安装 CMake。目前编译 gRPC 需要的 CMake 最低版本为 3.5.1,建议使用的 CMake 版本为 3.13 及以上。

# 查看当前 CMake 版本
cmake --version

CMake 官网下载需要版本的 CMake 源码或二进制文件。

例如下载适用于 x86_64 的 Linux 系统的二进制文件,可以选择下载 cmake-3.20.1-linux-x86_64.tar.gz,其中 3.20.1 为版本号。

解压,可以将 /path/to/cmake-3.20.1-linux-x86_64/bin/ 目录下的二进制文件复制粘贴到 /usr/bin/ 目录下;或是为它们创建软链接,创建软链接应使用绝对路径。

# 解压
tar -zxvf cmake-3.20.1-linux-x86_64.tar.gz
# 为二进制文件创建软链接
sudo ln -sf /path/to/cmake-3.20.1-linux-x86_64/bin/* /usr/bin/
# 再次执行,确保安装成功
cmake --version

查看版本号时如果提示 CMake Error: Could not find CMAKE_ROOT !!!,可能是原本调用的 CMake 二进制文件存放在其它目录下。例如,原来的 CMake 二进制文件存放在 /usr/local/bin/ 目录下,而调用命令时系统又优先从该目录搜索命令。因此应在创建软链接时应执行:

# 创建 cmake 二进制文件软链接
sudo ln -sf /path/to/cmake-3.20.1-linux-x86_64/bin/* /usr/local/bin/

对于其它路径,可以通过 find / -name "cmake" 来寻找。

下载 gRPC

建议在能够直接访问外网的环境利用 git 克隆 gRPC 库并获取第三方依赖,再打包出来给其它环境编译使用。

手动下载 gRPC 及第三方依赖耗时耗力,还有可能像我一样“赔了夫人又折兵”依然编译不了。

# 克隆 gRPC 仓库
git clone https://github.com/grpc/grpc.git
cd grpc
# 获取 gRPC 第三方依赖
git submodule update --init

编译安装 gRPC

官方文档建议用户选择本地路径安装 gRPC,因为全局安装后想要卸载 gRPC 会十分复杂。因此,在编译安装之前,可以首先选择一个用户本地的路径。

# 安装到 $HOME/.local 中
export MY_INSTALL_DIR=$HOME/.local
# 确保目录存在
mkdir -p $MY_INSTALL_DIR
# 添加该路径下的 bin 目录到环境变量
export PATH="$PATH:$MY_INSTALL_DIR/bin"

在 gRPC 根目录下执行下述操作

# 创建存放编译 gRPC 结果的目录
mkdir -p cmake/build
# 进入到该目录
pushd cmake/build
# 生成编译 gRPC 的 Makefile 文件
# 其中 DCMAKE_INSTALL_PREFIX 指定了 gRPC 的安装路径
cmake -DgRPC_INSTALL=ON \
    -DgRPC_BUILD_TESTS=OFF \
    -DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR \
    ../..
# 执行编译
# ${JOBS_NUM} 为同时执行的线程数,应替换为数字,下同
make -j ${JOBS_NUM}
# 安装 gRPC
make install

如果想要编译动态库 .so 文件,可以在上一步执行 cmake 命令时设置 -DBUILD_SHARED_LIBS=ON,如:

# 生成编译 gRPC 的 Makefile 文件
cmake -DBUILD_SHARED_LIBS=ON ../..

假如编译失败,可以参考笔者遇到的错误和解决方案

C++ 版本的 gRPC 还依赖于 Abseil C++ 库,因此需要单独编译安装它:

# 回到 gRPC 根目录
popd
# 创建存放 Abseil C++ 编译结果的目录
mkdir -p third_party/abseil-cpp/cmake/build
# 进入到编译目录
pushd third_party/abseil-cpp/cmake/build
# 生成编译 abseil-cpp 的 Makefile 文件
cmake -DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR \
    -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \
    ../..
# 执行编译
make -j ${JOBS_NUM}
# 安装 Abseil C++
make install

哈!大功告成。最后我们来测试一下 gRPC 是否安装成功。

测试编译安装 gRPC 成功

首先编译 gRPC 提供的示例:

# 回到 gRPC 根目录
popd
# 进入 example 目录
cd examples/cpp/helloworld
# 创建存放 example 编译结果的目录
mkdir -p cmake/build
# 进入到编译目录
pushd cmake/build
# 生成编译 example 的 Makefile 文件
# 其中 DCMAKE_PREFIX_PATH 指定我们使用的 gRPC 路径,即 gRPC 的安装路径
cmake -DCMAKE_PREFIX_PATH=$MY_INSTALL_DIR ../..
# 执行编译
make -j ${JOBS_NUM}

这样,在当前目录就会生成编译好的二进制文件。试试看吧!

在当前终端启用 gRPC 示例的服务端,它会默认监听当前主机的 50051 端口:

./greeter_server

# 显示内容如下
Server listening on 0.0.0.0:50051

打开一个新终端,进入到此目录,运行客户端,就可以看到访问的结果啦:

./greeter_client

# 显示内容如下
Greeter received: Hello world

假如退出了服务端,再运行客户端,则会打印:

# 关闭服务端,然后执行
./greeter_client

# 显示内容如下
14: failed to connect to all addresses
Greeter received: RPC failed

开始愉快地编写 gRPC 程序吧!

可能遇见的错误

编译 gRPC 执行 make 后提示 error

error: no matching function for call to ‘StrFormat(const char [22], const char*, char [64], int32_t&, long int&, const char*&, int&)

提示报错没有找到 StrFormat 函数,请确保 gcc 版本在 4.9 及以上,可以执行 gcc -v 命令查看当前版本。

建议更新gcc 4.9.4 版本,笔者在该版本下顺利编译 gRPC。