FindProtobuf

注意

如果 Protobuf 库是使用其基于 CMake 的构建系统构建和安装的,它会提供一个包配置文件,供find_package()命令在配置模式下使用。

find_package(Protobuf CONFIG)

在这种情况下,导入的目标和 CMake 命令,如protobuf_generate(),由上游包提供,而不是由本模块提供。此外,此处记录的某些变量在配置模式下不可用,因为导入的目标是首选的。有关使用详细信息,请参阅上游文档,这是 Protobuf 与 CMake 结合使用的推荐方式。

本模块仅在模块模式下工作。

本模块在模块模式下查找 Protocol Buffers 库 (Protobuf)。

find_package(Protobuf [<version>] [...])

Protobuf 是由 Google 开发的一种开源、语言中立、平台中立的数据结构化序列化机制。它通常用于程序之间或网络之间的数据交换。

版本 3.6 中添加: 支持在find_package(Protobuf <version>)命令中使用 <version> 参数。

版本 3.6 中更改: 所有输入和输出变量都使用 Protobuf_ 前缀。为向后兼容支持带有 PROTOBUF_ 前缀的变量。

导入的目标

此模块提供以下 导入目标

protobuf::libprotobuf

版本 3.9 中添加。

封装 Protobuf 库使用需求的 Target,在找到 Protobuf 库时可用。

protobuf::libprotobuf-lite

版本 3.9 中添加。

封装 protobuf-lite 库使用需求的 Target,在找到 Protobuf 及其 lite 库时可用。

protobuf::libprotoc

版本 3.9 中添加。

封装 protoc 库使用需求的 Target,在找到 Protobuf 及其 protoc 库时可用。

protobuf::protoc

3.10 版本新增。

导入的 executable target,封装 protoc 编译器使用需求,在找到 Protobuf 和 protoc 时可用。

结果变量

此模块定义了以下变量

Protobuf_FOUND

3.3 版本中新增。

布尔值,指示是否找到 (所请求版本的) Protobuf 库。

Protobuf_VERSION

3.6 版本新增。

找到的 Protobuf 版本。

Protobuf_INCLUDE_DIRS

使用 Protobuf 所需的包含目录。

Protobuf_LIBRARIES

链接 Protobuf 所需的库。

Protobuf_PROTOC_LIBRARIES

链接 protoc 库所需的库。

Protobuf_LITE_LIBRARIES

链接 protobuf-lite 库所需的库。

缓存变量

以下缓存变量也可以设置

Protobuf_INCLUDE_DIR

包含 Protobuf 头文件的目录。

Protobuf_LIBRARY

protobuf 库的路径。

Protobuf_PROTOC_LIBRARY

protoc 库的路径。

Protobuf_PROTOC_EXECUTABLE

protoc 编译器的路径。

Protobuf_LIBRARY_DEBUG

protobuf 调试库的路径。

Protobuf_PROTOC_LIBRARY_DEBUG

protoc 调试库的路径。

Protobuf_LITE_LIBRARY

protobuf-lite 库的路径。

Protobuf_LITE_LIBRARY_DEBUG

protobuf-lite 调试库的路径。

Protobuf_SRC_ROOT_FOLDER

使用 MSVC 编译时,如果设置了此缓存变量,则会搜索 protobuf 默认的 Visual Studio 项目构建位置以查找库和二进制文件。

  • <Protobuf_SRC_ROOT_FOLDER>/vsprojects/{Debug,Release},或

  • <Protobuf_SRC_ROOT_FOLDER>/vsprojects/x64/{Debug,Release}

提示

在调用 find_package(Protobuf) 之前,本模块接受以下可选变量:

Protobuf_DEBUG

3.6 版本新增。

布尔变量,启用本模块的调试消息以供调试之用。

Protobuf_USE_STATIC_LIBS

版本 3.9 中添加。

设置为 ON 以强制使用静态库。默认为 OFF。

命令

如果找到 Protobuf,本模块将提供以下命令:

生成源文件

protobuf_generate

3.13 版本新增。

在构建时自动从 .proto 模式文件中生成源文件。

protobuf_generate(
  [TARGET <target>]
  [LANGUAGE <lang>]
  [OUT_VAR <variable>]
  [EXPORT_MACRO <macro>]
  [PROTOC_OUT_DIR <out-dir>]
  [PLUGIN <plugin>]
  [PLUGIN_OPTIONS <plugin-options>]
  [DEPENDENCIES <dependencies>...]
  [PROTOS <proto-files>...]
  [IMPORT_DIRS <dirs>...]
  [APPEND_PATH]
  [GENERATE_EXTENSIONS <extensions>...]
  [PROTOC_OPTIONS <options>...]
  [PROTOC_EXE <executable>]
  [DESCRIPTORS]
)
TARGET <target>

要将生成的文件添加为源的 CMake Target。当未使用 OUT_VAR <variable> 时,此选项是必需的。

LANGUAGE <lang>

单个值:cpppython。确定要生成的源文件的类型。默认为 cpp。对于其他语言,请使用 GENERATE_EXTENSIONS 选项。

OUT_VAR <variable>

将包含生成源文件路径的 CMake 变量的名称。

EXPORT_MACRO <macro>

应用于所有生成的 Protobuf 消息类和 extern 变量的预处理器宏的名称。例如,这可以用于声明 DLL 导出。该宏应展开为 __declspec(dllexport)__declspec(dllimport),具体取决于正在编译的内容。

此选项仅在 LANGUAGEcpp 时使用。

PROTOC_OUT_DIR <out-dir>

生成源文件的输出目录。默认为:CMAKE_CURRENT_BINARY_DIR

PLUGIN <plugin>

3.21 版本新增。

一个可选的插件可执行文件。这可能是 grpc_cpp_plugin 的路径。

PLUGIN_OPTIONS <plugin-options>

版本 3.28 新增。

传递给插件的其他选项,例如 gRPC C++ 插件的 generate_mock_code=true

DEPENDENCIES <dependencies>...

版本 3.28 新增。

文件生成所依赖的依赖项。这些将转发给底层的add_custom_command(DEPENDS)调用。

版本 4.1 中更改: 此参数现在接受多个值 (DEPENDENCIES a b c...)。以前只能指定一个值 (DEPENDENCIES "a;b;c;...")。

PROTOS <proto-files>...

要处理的 .proto 模式文件列表。如果同时指定了 <target>,则这些文件将与该 Target 的所有 .proto 源文件合并。

IMPORT_DIRS <dirs>...

一个或多个模式文件公共父目录的列表。例如,如果模式文件是 proto/helloworld/helloworld.proto,并且导入目录是 proto/,则生成的文件将是 <out-dir>/helloworld/helloworld.pb.h<out-dir>/helloworld/helloworld.pb.cc

APPEND_PATH

如果指定,所有 proto 模式文件的基本路径将附加到 IMPORT_DIRS (它会导致 protoc 使用 -I 参数调用,为包含 .proto 文件的每个目录)。

GENERATE_EXTENSIONS <extensions>...

如果省略了 LANGUAGE,则必须设置此项以指定 protoc 生成的扩展。

PROTOC_OPTIONS <options>...

版本 3.28 新增。

直接传递给 protoc 编译器的其他命令行选项列表。

PROTOC_EXE <executable>

4.0 版本新增。

用于生成 Protobuf 绑定的命令行程序、路径或 CMake 可执行文件。如果省略,默认使用 protobuf::protoc 导入的目标。

DESCRIPTORS

如果指定,则为每个 .proto 源文件,将命令行选项 --descriptor_set_out=<proto-file> 附加到 protoc 编译器,从而能够创建自描述消息。此选项仅在 <lang>cpp 且 Protobuf 在模块模式下找到时可用。

注意

当 Protobuf 在配置模式下找到时,此选项不可用。

已弃用的命令

以下命令是为了向后兼容而提供的。

注意

命令 protobuf_generate_cpp()protobuf_generate_python() 仅在相同的目录范围内,即 find_package(Protobuf ...) 被调用的地方,才能正常工作。

注意

如果 Protobuf 在配置模式下找到,从 Protobuf 版本 3.0.0 开始,protobuf_generate_cpp()protobuf_generate_python() 命令**不可用**,除非在上游包配置提示变量 protobuf_MODULE_COMPATIBLE 在调用 find_package(Protobuf ...) 之前设置为布尔 true。

protobuf_generate_cpp

版本 4.1 已弃用: 使用 protobuf_generate()

在构建时自动从 .proto 模式文件中生成 C++ 源文件。

protobuf_generate_cpp(
  <sources-variable>
  <headers-variable>
  [DESCRIPTORS <variable>]
  [EXPORT_MACRO <macro>]
  <proto-files>...
)
<sources-variable>

要定义的变量名,它将包含一个生成的 C++ 源文件列表。

<headers-variable>

要定义的变量名,它将包含一个生成的头文件列表。

DESCRIPTORS <variable>

3.10 版本新增。

要定义的变量名,如果请求,它将包含一个生成的描述符文件列表。

注意

当 Protobuf 在配置模式下找到时,此选项不可用。

EXPORT_MACRO <macro>

一个宏的名称,它应该展开为 __declspec(dllexport)__declspec(dllimport),具体取决于正在编译的内容。

<proto-files>...

一个或多个要处理的 .proto 文件。

protobuf_generate_python

版本 4.1 已弃用: 使用 protobuf_generate()

3.4 版本新增。

在构建时自动从 .proto 模式文件中生成 Python 源文件。

protobuf_generate_python(<python-sources-variable> <proto-files>...)
<python-sources-variable>

要定义的变量名,它将包含一个生成的 Python 源文件列表。

<proto-files>...

一个或多个要处理的 .proto 文件。


命令 protobuf_generate_cpp()protobuf_generate_python() 在调用前接受以下可选变量:

Protobuf_IMPORT_DIRS

版本 4.1 已弃用。

用于搜索导入的 .proto 文件的其他目录列表。

PROTOBUF_GENERATE_CPP_APPEND_PATH

版本 4.1 已弃用: 使用 protobuf_generate(APPEND_PATH) 命令选项。

一个布尔变量,如果设置为布尔 true,则会导致 protoc 使用 -I 参数调用,为包含 .proto 文件的每个目录。默认情况下,它设置为布尔 true。

示例

示例:查找 Protobuf

查找 Protobuf 库

find_package(Protobuf)

或者,查找 Protobuf 并指定最低必需版本

find_package(Protobuf 30)

或者,查找 Protobuf 并将其设为必需 (如果未找到,处理将停止并显示错误消息)

find_package(Protobuf REQUIRED)

示例:在配置模式下查找 Protobuf

当 Protobuf 库使用其基于 CMake 的构建系统构建和安装时,可以在配置模式下找到它。

find_package(Protobuf CONFIG)

然而,一些 Protobuf 安装可能仍然不提供包配置文件。下面的示例展示了如何使用CMAKE_FIND_PACKAGE_PREFER_CONFIG变量在配置模式下查找 Protobuf,并在找不到配置文件时回退到模块模式

set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
find_package(Protobuf)
unset(CMAKE_FIND_PACKAGE_PREFER_CONFIG)

示例:使用 Protobuf

查找 Protobuf 并将其导入的库 Target 链接到项目 Target。

find_package(Protobuf)
target_link_libraries(example PRIVATE protobuf::libprotobuf)

示例:处理 Proto 模式文件

以下示例演示了如何将添加到 Target 的所有 *.proto 模式源文件处理为 C++ 源文件。

CMakeLists.txt
cmake_minimum_required(VERSION 3.24)
project(ProtobufExample)

add_executable(example main.cxx person.proto)

find_package(Protobuf)

if(Protobuf_FOUND)
  protobuf_generate(TARGET example)
endif()

target_link_libraries(example PRIVATE protobuf::libprotobuf)
target_include_directories(example PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
person.proto
syntax = "proto3";

message Person {
  string name = 1;
  int32 id = 2;
}
main.cxx
#include <iostream>
#include "person.pb.h"

int main()
{
  Person person;
  person.set_name("Alice");
  person.set_id(123);

  std::cout << "Name: " << person.name() << "\n";
  std::cout << "ID: " << person.id() << "\n";

  return 0;
}

示例:使用 Protobuf 和 gRPC

以下示例展示了如何使用 Protobuf 和 gRPC。

CMakeLists.txt
find_package(Protobuf REQUIRED)
find_package(gRPC CONFIG REQUIRED)

add_library(ProtoExample Example.proto)
target_link_libraries(ProtoExample PUBLIC gRPC::grpc++)

protobuf_generate(TARGET ProtoExample)
protobuf_generate(
  TARGET ProtoExample
  LANGUAGE grpc
  PLUGIN protoc-gen-grpc=$<TARGET_FILE:gRPC::grpc_cpp_plugin>
  PLUGIN_OPTIONS generate_mock_code=true
  GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc
)

示例:升级已弃用的命令

以下示例展示了如何使用已弃用的命令及其现代替代命令来处理 .proto 文件并生成 C++ 代码。

CMakeLists.txt (使用已弃用命令)
find_package(Protobuf)

if(Protobuf_FOUND)
  protobuf_generate_cpp(
    proto_sources
    proto_headers
    EXPORT_MACRO DLL_EXPORT
    DESCRIPTORS proto_descriptors
    src/protocol/Proto1.proto
    src/protocol/Proto2.proto
  )
endif()

target_sources(
  example
  PRIVATE ${proto_sources} ${proto_headers} ${proto_descriptors}
)
target_link_libraries(example PRIVATE protobuf::libprotobuf)
CMakeLists.txt (已升级代码)
find_package(Protobuf)

if(Protobuf_FOUND)
  protobuf_generate(
    TARGET example
    EXPORT_MACRO DLL_EXPORT
    IMPORT_DIRS src/protocol
    DESCRIPTORS
    PROTOS
      src/protocol/Proto1.proto
      src/protocol/Proto2.proto
  )
endif()

target_link_libraries(example PRIVATE protobuf::libprotobuf)

以下示例展示了如何使用已弃用的命令及其现代替代命令来处理 .proto 文件并生成 Python 代码。

CMakeLists.txt (使用已弃用命令)
find_package(Protobuf)

if(Protobuf_FOUND)
  protobuf_generate_python(python_sources foo.proto)
endif()

add_custom_target(proto_files DEPENDS ${python_sources})
CMakeLists.txt (已升级代码)
find_package(Protobuf)

if(Protobuf_FOUND)
  protobuf_generate(
    LANGUAGE python
    PROTOS foo.proto
    OUT_VAR python_sources
  )
endif()

add_custom_target(proto_files DEPENDS ${python_sources})