FindProtobuf

注意

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

find_package(Protobuf CONFIG)

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

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

此模块在模块模式下查找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 版本新增。

封装protoc编译器使用要求的导入可执行文件Target,如果找到Protobuf和protoc则可用。

结果变量

此模块定义了以下变量

Protobuf_FOUND

布尔值,表示是否找到(请求版本的)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目标。当未使用OUT_VAR <variable>时,此选项是必需的。

LANGUAGE <lang>

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

OUT_VAR <variable>

将填充生成源文件路径的CMake变量的名称。

EXPORT_MACRO <macro>

应用于所有生成的Protobuf消息类和外部变量的预处理器宏的名称。例如,这可以用于声明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>,这些文件将与该目标的所有.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为每个包含.proto文件的目录调用-I参数)。

GENERATE_EXTENSIONS <extensions>...

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

PROTOC_OPTIONS <options>...

版本 3.28 新增。

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

PROTOC_EXE <executable>

4.0 版本新增。

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

DESCRIPTORS

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

注意

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

已废弃的命令

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

注意

protobuf_generate_cpp()protobuf_generate_python()命令仅在调用find_package(Protobuf ...)的同一目录范围内才能正确工作。

注意

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

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)命令选项。

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

示例

示例:查找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并将其导入的库目标链接到项目目标

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

示例:处理Proto模式文件

以下示例演示了如何将添加到目标的所有*.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})