在 RK3588 平台上编译 C++ 版本 gRPC 实战记录

本文记录了在 RK3588 嵌入式平台上(基于 Ubuntu 22.04)编译和安装 gRPC C++ 版本(v1.73.1)的完整流程,涵盖了从环境准备、NFS 挂载、源码编译到代码生成的全过程。

图片[1]-在 RK3588 平台上编译 C++ 版本 gRPC 实战记录-天煜博客

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
喜欢就支持一下吧
点赞7 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容