本文记录了在 RK3588 嵌入式平台上(基于 Ubuntu 22.04)编译和安装 gRPC C++ 版本(v1.73.1)的完整流程,涵盖了从环境准备、NFS 挂载、源码编译到代码生成的全过程。
![图片[1]-在 RK3588 平台上编译 C++ 版本 gRPC 实战记录-天煜博客](https://blog.itianyu.cn/wp-content/uploads/2026/01/20260120121521269-image.png)
1. 环境准备与 NFS 挂载
为了方便在宿主机和开发板之间传输文件,我们通常使用 NFS 挂载开发目录。
挂载 NFS
假设宿主机 IP 为 192.168.8.11,挂载到板端的 /home/z/nfs 目录:
# 挂载命令
sudo mount -t nfs 192.168.8.11:/home/z/work/dev /home/z/nfs
预期目录结构:
挂载成功后,我们将使用 /home/z/nfs/grpc/ 作为工作目录。
安装依赖工具
编译 gRPC 需要 CMake 3.16+ 以及基本的构建工具:
# 安装基础依赖
sudo apt update
sudo apt install -y cmake build-essential autoconf libtool pkg-config git
检查 CMake 版本:
cmake --version
注:如果系统默认 CMake 版本过低(低于 3.16),请务必先手动升级 CMake。
2. 获取 gRPC 源码
我们将编译 v1.73.1 版本。由于 gRPC 包含大量子模块,拉取时需特别注意网络环境。
# 进入工作目录
cd /home/z/nfs/grpc/
# 配置代理(如果下载速度慢,请替换为你自己的代理地址)
git config --global http.proxy http://192.168.206.18:7890
git config --global https.proxy http://192.168.206.18:7890
# 克隆仓库及其子模块 (使用 shallow clone 加快速度)
git clone --recurse-submodules -b v1.73.1 --depth 1 --shallow-submodules https://github.com/grpc/grpc
# 下载完成后取消代理
git config --global --unset http.proxy
git config --global --unset https.proxy
3. 编译与安装
我们将分别演示 Release 模式(用于部署)和 Debug 模式(用于开发调试)的编译方法。
3.1 Release 模式编译 (推荐)
Release 模式拥有最高的优化级别,生成的二进制体积小,适合生产环境。
# 设置安装路径
export GRPC_INSTALL_DIR=/home/z/grpc/install_grpc_V1.73.1_aarch64_release
mkdir -p $GRPC_INSTALL_DIR
export PATH="$GRPC_INSTALL_DIR/bin:$PATH"
cd grpc
mkdir -p cmake/build_release
pushd cmake/build_release
# 执行 CMake 配置
cmake -DCMAKE_BUILD_TYPE=Release \
-DgRPC_INSTALL=ON \
-DgRPC_BUILD_TESTS=OFF \
-DCMAKE_CXX_STANDARD=17 \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_INSTALL_PREFIX=$GRPC_INSTALL_DIR \
../..
# 编译并安装 (根据 CPU 核心数调整 -j 参数)
make -j 4
make install
popd
3.2 Debug 模式编译
Debug 模式包含完整的调试信息,但运行速度较慢,体积较大。
# 设置安装路径
export GRPC_INSTALL_DIR=/home/z/grpc/install_grpc_V1.73.1_aarch64_debug
mkdir -p $GRPC_INSTALL_DIR
export PATH="$GRPC_INSTALL_DIR/bin:$PATH"
cd grpc
mkdir -p cmake/build_debug
pushd cmake/build_debug
cmake -DCMAKE_BUILD_TYPE=Debug \
-DgRPC_INSTALL=ON \
-DgRPC_BUILD_TESTS=OFF \
-DCMAKE_CXX_STANDARD=17 \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_INSTALL_PREFIX=$GRPC_INSTALL_DIR \
../..
make -j 4
make install
popd
附:CMake 构建类型对比表
| 构建类型 | 优化级别 | 调试信息 | 断言检查 | 生成速度 | 二进制体积 | 适用场景 |
| Release | 最高 | 无 | 禁用 | 较慢 | 小 | 生产环境部署 |
| Debug | 无 | 完整 | 启用 | 快 | 大 | 开发调试 |
| RelWithDebInfo | 高 | 部分 | 禁用 | 适中 | 适中 | 需要调试的生产版本 |
| MinSizeRel | 最高 | 无 | 禁用 | 较慢 | 最小 | 嵌入式/体积敏感场景 |
4. 使用 gRPC 生成 C++ 代码
编译完成后,我们需要使用 protoc 编译器和 grpc_cpp_plugin 插件将 .proto 文件转换为 C++ 代码。
设置环境变量
# 指向你的 gRPC 安装目录
export GRPC_INSTALL_DIR=/opt/grpc_share # 或上文中你编译的路径
export PATH="$GRPC_INSTALL_DIR/bin:$PATH"
export LD_LIBRARY_PATH=$GRPC_INSTALL_DIR/lib:$LD_LIBRARY_PATH
执行生成命令
假设你的 proto 文件在 ../protos 目录下:
# 示例 1: 生成 imgUpload 相关代码
protoc -I ../protos --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` ../protos/imgUpload.proto
protoc -I ../protos --cpp_out=. ../protos/imgUpload.proto
# 示例 2: 生成 carPlate 相关代码
protoc -I ../protos --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` ../protos/carPlate.proto
protoc -I ../protos --cpp_out=. ../protos/carPlate.proto
附录:自动化管理脚本 (grpc_toolkit.sh)
为了简化日后的安装、编译和版本管理,我编写了一个 Shell 脚本工具。保存为 grpc_toolkit.sh 并赋予执行权限即可使用。
功能:
- 一键安装/卸载 gRPC
- 批量编译
.proto文件 - 版本查询
- 环境变量配置
脚本代码:
#!/bin/bash
# grpc_toolkit.sh - gRPC 开发工具
# 默认配置
GRPC_INSTALL_DIR="/opt/grpc"
SOURCE_DIR=""
PROTO_PATH="./"
OUTPUT_DIR="./generated"
ACTION=""
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
# 显示帮助信息
show_help() {
echo -e "${GREEN}gRPC 开发工具${NC}"
echo "使用方法: $0 [选项] [命令]"
echo "命令:"
echo " install [源目录] 安装 gRPC 到 $GRPC_INSTALL_DIR"
echo " compile [proto文件] 编译 .proto 文件生成 C++ 代码"
echo " version 显示 gRPC 和 Protobuf 版本信息"
echo " uninstall 卸载 gRPC"
echo " setenv 设置 gRPC 环境变量"
echo ""
echo "选项:"
echo " -h, --help 显示此帮助信息"
echo " -i, --install-dir 指定gRPC安装目录 (默认: $GRPC_INSTALL_DIR)"
echo " -o, --output 指定编译 .proto 文件时生成代码的输出目录"
echo " -p, --proto-path 指定proto文件搜索路径 (默认: 当前目录)"
}
# 检查是否有 sudo 权限
check_sudo() {
if [ "$(id -u)" -ne 0 ]; then
echo -e "${RED}错误: 此操作需要管理员权限${NC}"
echo -e "${YELLOW}请使用: sudo $0 $*${NC}"
exit 1
fi
}
# 解析命令行参数
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help) show_help; exit 0 ;;
-i|--install-dir) GRPC_INSTALL_DIR="$2"; shift 2 ;;
-o|--output) OUTPUT_DIR="$2"; shift 2 ;;
-p|--proto-path) PROTO_PATH="$2"; shift 2 ;;
install) ACTION="install"; SOURCE_DIR="$2";
if [ -z "$SOURCE_DIR" ]; then echo -e "${RED}需指定源目录${NC}"; exit 1; fi; shift 2 ;;
compile) ACTION="compile"; shift; PROTO_FILES+=("$@"); break ;;
version) ACTION="version"; shift ;;
uninstall) ACTION="uninstall"; shift ;;
setenv) ACTION="setenv"; shift ;;
*) echo -e "${RED}错误: 未知参数: $1${NC}"; show_help; exit 1 ;;
esac
done
if [ -z "$ACTION" ]; then echo -e "${RED}错误: 未指定命令${NC}"; show_help; exit 1; fi
# --- 核心功能函数 ---
install_grpc() {
check_sudo install "$SOURCE_DIR"
echo -e "${GREEN}安装 gRPC 到 $GRPC_INSTALL_DIR...${NC}"
[ ! -d "$SOURCE_DIR" ] && { echo -e "${RED}源目录不存在${NC}"; exit 1; }
mkdir -p "$GRPC_INSTALL_DIR"
for dir in bin include lib; do
if [ -d "$SOURCE_DIR/$dir" ]; then
rsync -avz --delete "$SOURCE_DIR/$dir" "$GRPC_INSTALL_DIR/"
fi
done
echo -e "${YELLOW}更新 pkgconfig...${NC}"
PKG_DIR="$GRPC_INSTALL_DIR/lib/pkgconfig"
if [ -d "$PKG_DIR" ]; then
for pc_file in "$PKG_DIR"/*.pc; do
[ -f "$pc_file" ] || continue
sed -i -e "s|^prefix=.*|prefix=$GRPC_INSTALL_DIR|" \
-e "s|^exec_prefix=.*|exec_prefix=\${prefix}|" \
-e "s|^libdir=.*|libdir=\${prefix}/lib|" \
-e "s|^includedir=.*|includedir=\${prefix}/include|" "$pc_file"
done
fi
set_grpc_env
echo -e "${GREEN}安装完成!${NC}"
}
compile_proto() {
[ ${#PROTO_FILES[@]} -eq 0 ] && { echo -e "${RED}需指定 .proto 文件${NC}"; exit 1; }
export PATH="$GRPC_INSTALL_DIR/bin:$PATH"
export LD_LIBRARY_PATH="$GRPC_INSTALL_DIR/lib:$LD_LIBRARY_PATH"
if ! command -v protoc &> /dev/null; then
echo -e "${RED}错误: 未找到 protoc,请检查安装路径${NC}"; exit 1;
fi
mkdir -p "$OUTPUT_DIR"
for proto_file in "${PROTO_FILES[@]}"; do
# 路径处理逻辑...
if [ -f "$proto_file" ]; then full_path=$(realpath "$proto_file");
elif [ -f "$PROTO_PATH/$proto_file" ]; then full_path="$PROTO_PATH/$proto_file";
else echo -e "${RED}文件未找到: $proto_file${NC}"; exit 1; fi
proto_name=$(basename "$full_path" .proto)
out_subdir="$OUTPUT_DIR/$proto_name"
mkdir -p "$out_subdir"
proto_dir=$(dirname "$full_path")
echo -e "${GREEN}正在编译: $(basename "$full_path")${NC}"
protoc -I "$proto_dir" --grpc_out="$out_subdir" --plugin=protoc-gen-grpc="$(which grpc_cpp_plugin)" "$(basename "$full_path")"
protoc -I "$proto_dir" --cpp_out="$out_subdir" "$(basename "$full_path")"
done
echo -e "${GREEN}编译完成,输出目录: $OUTPUT_DIR${NC}"
}
show_version() {
export PATH="$GRPC_INSTALL_DIR/bin:$PATH"
export LD_LIBRARY_PATH="$GRPC_INSTALL_DIR/lib:$LD_LIBRARY_PATH"
export PKG_CONFIG_PATH="$GRPC_INSTALL_DIR/lib/pkgconfig:$PKG_CONFIG_PATH"
echo -e "${GREEN}--- 版本信息 ---${NC}"
command -v protoc &> /dev/null && protoc --version || echo -e "${RED}未找到 protoc${NC}"
if [ -f "$GRPC_INSTALL_DIR/lib/pkgconfig/grpc.pc" ]; then
echo -e "gRPC 库版本: $(pkg-config --modversion grpc 2>/dev/null)"
fi
}
uninstall_grpc() {
check_sudo uninstall
rm -rf "$GRPC_INSTALL_DIR"
remove_grpc_env
echo -e "${GREEN}gRPC 已卸载${NC}"
}
set_grpc_env() {
ENV_FILE="$HOME/.bashrc"
[ -f "$HOME/.zshrc" ] && ENV_FILE="$HOME/.zshrc"
if ! grep -q "$GRPC_INSTALL_DIR" "$ENV_FILE"; then
echo -e "\n# gRPC 环境配置\nexport GRPC_INSTALL_DIR=$GRPC_INSTALL_DIR\nexport PATH=\"\$GRPC_INSTALL_DIR/bin:\$PATH\"\nexport LD_LIBRARY_PATH=\"\$GRPC_INSTALL_DIR/lib:\$LD_LIBRARY_PATH\"\nexport PKG_CONFIG_PATH=\"\$GRPC_INSTALL_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH\"" >> "$ENV_FILE"
echo -e "${GREEN}环境变量已写入 $ENV_FILE${NC}"
fi
}
remove_grpc_env() {
ENV_FILE="$HOME/.bashrc"
[ -f "$HOME/.zshrc" ] && ENV_FILE="$HOME/.zshrc"
sed -i "/# gRPC 环境配置/,/export PKG_CONFIG_PATH.*$/d" "$ENV_FILE"
}
# 命令分发
case "$ACTION" in
install) install_grpc ;;
compile) compile_proto ;;
version) show_version ;;
uninstall) uninstall_grpc ;;
setenv) set_grpc_env ;;
esac
© 版权声明
转载请注明出处,并标明原文链接。
本网站尊重知识产权,如有侵权,请及时联系我们删除。
本站所有原创内容仅用于学习和交流目的,未经作者和本站授权不得进行商业使用或盈利行为。
本网站尊重知识产权,如有侵权,请及时联系我们删除。
本站所有原创内容仅用于学习和交流目的,未经作者和本站授权不得进行商业使用或盈利行为。
THE END










暂无评论内容