CMake + Protobuf 自动生成 cpp 文件(pb.h, pb.cc)

【Protoc】VS2019 (VS平台) 使用 CMake 编译安装、使用 Protobuf 库

本文介绍在 macOS 系统下 cmake 和 protobuf 一起使用的一种方式——使用 cmake 自动编译 proto 文件为 pb.cc 和 pb.h 文件。

protobuf

protobuf 是谷歌发布的一种数据封装协议, 用于数据传输。在使用时需要定义好 proto 文件, 然后用 protoc 工具编译为 pb.h 和 pb.cc 文件。打开命令行输入如下命令

protoc -I=${proto_file_dir} --cpp_out=${pb_file_dir} *.proto

这里面有三个参数, -I 表示 proto 文件的路径; --cpp_out 表示输出路径; 最后一个参数表示需要被编译为 pb.h 和 pb.cc 文件的 proto 文件, *.proto 表示 -I 路径下的所有 proto 文件。


好了, 正文开始。

背景介绍

文件结构

.
├── CMakeLists.txt
├── originFile
│   └── proto1
│       ├── proto1.proto
│       ├── proto2.proto
│       └── proto3.proto
│   └── proto2
│       ├── proto4.proto
│       ├── proto5.proto
│       └── proto6.proto

目标

我们要把 originFile 中的文件编译为 pb 文件。

根据上面的指令, 我们可以很方便很快捷的生成 pb 文件,似乎没有什么不妥。但是在不同的主机上使用不同版本的 protobuf 时, 都需要重新使用指令来生成 pb 文件(因为某一版本的 protobuf 生成的 pb 文件, 不能被其他版本的 protobuf 使用)。为了简化这一过程, 我们把生成 pb 文件的事,交给 cmake 来做, 在 cmake 过程中自动去根据 proto 文件生成 pb 文件。

方法

不指定输出路径

直接上 CmakeLists.txt 文件的内容

# 项目基本配置
cmake_minimum_required(VERSION 3.5)
project(common_pb)

# 获取protobuf库
find_package(Protobuf REQUIRED)

#设置输出路径
SET(PROTO_DIR ${CMAKE_SOURCE_DIR}/proto/originFile)

#获取需要编译的proto文件
file(GLOB_RECURSE MSG_PROTOS_1 ${PROTO_DIR}/proto1/*.proto)
file(GLOB_RECURSE MSG_PROTOS_2 ${PROTO_DIR}/proto2/*.proto)

# 将 proto 编译为 pb
PROTOBUF_GENERATE_CPP(SOURCES_1 HEADERS_1 ${MSG_PROTOS_1})
PROTOBUF_GENERATE_CPP(SOURCES_2 HEADERS_2 ${MSG_PROTOS_2})

这种方式生成的 pb 文件输出在 build 文件夹里面,且不论 proto 文件结构如何, 生成的 pb 文件都会被放在同一个目录下。

这里有另一种方式,来指定输出文件的路径。

指定输出路径

cmake_minimum_required(VERSION 3.5)
project(common_pb)

find_package(Protobuf REQUIRED)

#设置输出路径
SET(PROTO_DIR ${CMAKE_SOURCE_DIR}/originFile/)
SET(PB_DIR ${CMAKE_SOURCE_DIR}/pbCCFile)
message("[PROTO_DIR]" ${PROTO_DIR})

#设置protoc的搜索路径
LIST(APPEND PROTO_FLAGS -I${PROTO_DIR})
#获取需要编译的proto文件
file(GLOB_RECURSE MSG_PROTOS ${PROTO_DIR}/*.proto)

foreach(msg ${MSG_PROTOS})
   get_filename_component(FIL_NAME ${msg} NAME_WE)
   get_filename_component(FILE_PATH_ABS ${msg} ABSOLUTE)
   string(REPLACE "${PROTO_DIR}" "" FILE_PATH_REL ${FILE_PATH_ABS})
   string(REPLACE ".proto" ".pb.cc" FILE_NAME_CC ${FILE_PATH_REL})
   string(REPLACE ".proto" ".pb.h" FILE_NAME_H ${FILE_PATH_REL})
   message("[pb file relative path] " ${FILE_NAME_CC})
   # 使用自定义命令
   add_custom_command(
      OUTPUT 
         "${PB_DIR}/${FILE_NAME_CC}"
         "${PB_DIR}/${FILE_NAME_H}"
      COMMAND  ${PROTOBUF_PROTOC_EXECUTABLE}
      ARGS 
         --cpp_out  ${PB_DIR}
         -I ${PROTO_DIR}
         ${msg}
      DEPENDS ${msg}
      COMMENT "Running C++ protocol buffer compiler on ${msg}"
      VERBATIM
   )

   set(PROTO_SRC ${PROTO_SRC} ${PB_DIR}/${FILE_NAME_CC})
   set(PROTO_INC ${PROTO_INC} ${PB_DIR}/${FILE_NAME_H})
endforeach()

# 设置文件属性为 GENERATED
set_source_files_properties(${PROTO_SRC} ${PROTO_INC} PROPERTIES GENERATED TRUE)

通过这种方式生成的 pb 可以指定输出路径。 这种方式需要自行管理文件依赖和导入路径。

posted @ 2023-11-22 14:19  RioTian  阅读(852)  评论(0编辑  收藏  举报