qt_add_protobuf

使用 protobuf 模式生成基于 Qt 的 C++ 源代码

注意: 此命令为技术预览版,可能会在以后的版本中更改。

此命令在 Qt 6.5 中引入。

使用 qt_add_protobuf 在 CMake 脚本中调用qtprotobufgen ,并从 .proto 方案为项目生成代码。qtprotobufgen 将通过 CMake 使用qt_add_protobuf 命令调用。

qt_add_protobuf(<target>
    PROTO_FILES <file> ...
    [PROTO_INCLUDES <path> ...]
    [QML [QML_URI <uri>]]
    [OUTPUT_DIRECTORY <dir>]
    [GENERATE_PACKAGE_SUBFOLDERS]
    [COPY_COMMENTS]
    [EXPORT_MACRO <infix>]
    [OUTPUT_HEADERS <var>]
    [OUTPUT_TARGETS <var>]
    [HEADER_GUARD <pragma|filename>]
)

qtprotobufgen 生成的源文件将被添加到目标中。如果目标已经存在,生成的文件将被添加到目标源代码列表中。如果目标不存在,则会将其创建为一个库,您必须链接到该库。

参数

  • PROTO_FILES 指定代码生成过程使用的.proto文件列表。
  • PROTO_INCLUDES 指定要搜索的 protobuf 依赖目录列表。

    注意: PROTO_FILES 的位置隐含地视为 protobuf 包含路径的一部分。

  • QML 启用从 protobuf 定义生成 QML 兼容的消息类型,并将它们注册为 QML 模块。如果在不存在的目标或不是 QML 模块的目标上调用 ,将隐式创建一个新的 QML 模块。qt_add_protobuf
    find_package(Qt6 6.8 REQUIRED COMPONENTS Quick Protobuf ProtobufQuick)
    ...
    qt_add_executable(target
        ...
    )
    // creates a new QML module
    qt_add_protobuf(target
        QML
        ...
    )

    如果目标是现有的 QML 模块,qt_add_protobuf 会将生成的 protobuf 类型附加到该模块。

    find_package(Qt6 6.8 REQUIRED COMPONENTS Quick Protobuf ProtobufQuick)
    ...
    qt_add_qml_module(target
        ...
    )
    // adds to existing QML module
    qt_add_protobuf(target
        QML
        ...
    )

    注意: 如果使用 QML 参数,则必须在 find_package 调用中添加 ProtobufQuick。请参阅上面的示例。

  • QML_URI 定义了 QML 模块使用的 。URI

    每个 QML 模块都必须定义一个URI ,它在导入语句中用于向 QML 公开它的 protobuf 类型。

    qt_add_protobuf(target
        QML
        QML_URI proto.uri.example
    )

    如果QML_URI 被省略,protobuf 包名将被用作模块的URI

    注意: 如果省略QML_URI ,在PROTO_FILES 部分指定的所有.proto文件必须共享相同的 protobuf 包名,因为它将被用作生成的 QML 模块的默认URI

    注意: 应避免用相同的QML_URI 或 proto 包名创建多个 protobuf QML 模块,因为这会导致 QML 上下文中的导入错误。

    注意: 如果QML_URI 传递给qt_add_protobuf 函数,但目标已经存在,QML_URI 参数将被忽略。

    有关URI 的进一步深入讨论,请阅读Identified Modules

  • OUTPUT_DIRECTORY 定义生成文件的放置目录。默认情况下,使用当前构建目录。
  • GENERATE_PACKAGE_SUBFOLDERS 使用 文件中的软件包名称指定符来创建生成文件的文件夹结构。例如,如果软件包定义为,生成的文件将放在.proto package io.qt.testOUTPUT_DIRECTORY/io/qt/test/ 目录下。
  • COPY_COMMENTS 将 文件中的注释复制到生成的代码中。.proto
  • EXPORT_MACRO 仅适用于从<target> 创建新的共享库该选项指定生成代码中使用的导出宏的基本名称。最终的宏名构造为 。如果未设置该选项,则目标名称为 。QPB_<EXPORT_MACRO>_EXPORT EXPORT_MACRO

    请阅读创建共享库获取更多深入信息。

  • OUTPUT_HEADERS 指定一个变量,用于存储生成的头文件列表。该列表可用于定义自定义项目安装规则。
  • OUTPUT_TARGETS 指定一个变量,用于存储生成的目标列表。该列表有助于定义自定义项目安装规则。
  • HEADER_GUARD 指定用于防止生成的头文件被多重包含的机制。可能的值是 , 。默认值为 。将该选项设置为 会生成现代 pragma 头文件防护:pragma filename filename pragma
    #pragma once
    ...

    省略该选项或将该选项设置为filename 会生成ifdef 封装保护,并使用".proto "文件名作为保护后缀:

    #ifdef MYMESSAGES_QPB_H
    #define MYMESSAGES_QPB_H
    ...
    #endif // MYMESSAGES_QPB_H

    根据项目结构选择首选的保护方式。

解决 protobuf 目标之间的依赖关系

qt_add_protobuf 命令不会考虑用于为不同目标生成代码的.proto 文件之间的依赖关系。

项目可能有两个或更多带有依赖关系的.proto 文件:

// test_messages.proto
syntax = "proto3";

package test.messages;

message MyMessage {
    int32 myField = 1;
}
// test_extensions.proto
syntax = "proto3";

import "test_messages.proto";

package test.extensions;

message MyExtension {
    test.messages.MyMessage baseMessage = 1;
    int32 extension = 2;
}

上述.proto 文件可用于生成独立库:

qt_add_protobuf(test_messages
    PROTO_FILES
        test_messages.proto
)
...
qt_add_protobuf(test_extensions
    PROTO_FILES
        test_extensions.proto
)
...

由于test_extensions 目标依赖于test_messages 目标的消息,因此需要在CMake 脚本中手动链接到这些目标:

target_link_libraries(test_extensions PUBLIC test_messages)

注意: 来自test_messages 目标文件的消息被用于属于test_extensions 目标文件的头文件,因此链接到test_extensions 的目标文件应将test_messages 目标文件作为传递依赖关系。建议使用PUBLIC 链接范围,以便为 protobuf 库目标提供适当的INTERFACE_INCLUDE_DIRECTORIESINTERFACE_LINK_LIBRARIES 属性。

示例

使用 qt_add_protobuf

cmake_minimum_required(VERSION 3.16...3.22)
project(MyThings)

find_package(Qt6 REQUIRED COMPONENTS Protobuf)
qt_standard_project_setup()

qt_add_protobuf(MyMessages
    GENERATE_PACKAGE_SUBFOLDERS
    PROTO_FILES
        path/to/message.proto
        path/to/other_message.proto
    PROTO_INCLUDES
        /path/to/proto/include
)

qt_add_executable(MyApp main.cpp)

target_link_libraries(MyApp PRIVATE MyMessages)

在上面的示例中,我们生成了一个名为MyMessages 的库,其中包含传给PROTO_FILES 选项的路径中定义的消息类型。GENERATE_PACKAGE_SUBFOLDERS 选项为生成的文件生成一个文件夹结构。PROTO_INCLUDES 选项告诉 protoc 在指定目录中查找依赖项或导入项。我们创建了一个名为MyApp 的可执行文件目标,并将其链接到MyMessages 库。

QML 扩展 protobuf 示例

cmake_minimum_required(VERSION 3.16...3.22)
project(MyThings)

find_package(Qt6 REQUIRED COMPONENTS Protobuf ProtobufQuick Quick)
qt_standard_project_setup()

qt_add_protobuf(MyMessagesPlugin
    QML
    QML_URI my.messages.module.uri
    PROTO_FILES
        path/to/message.proto
        path/to/other_message.proto
    PROTO_INCLUDES
        /path/to/proto/include
)

qt_add_protobuf(MyApp
    QML
    PROTO_FILES
        path/to/internal_message.proto
    PROTO_INCLUDES
        /path/to/proto/include
)

qt_add_qml_module(MyApp
    URI example.uri
    VERSION 1.0
    QML_FILES qml/main.qml
)

qt_add_executable(MyApp main.cpp)
target_link_libraries(MyApp PRIVATE Quick)

在上面的 QML 扩展示例中,通过第一次调用qt_add_protobuf ,我们生成了一个名为MyMessagesPlugin 的 QML 模块,它包含了PROTO_FILES 选项传递的路径中定义的消息类型。我们使用QML 选项,在QML 上下文中启用 proto 消息类型注册。通过导入QML_URI 设置的路径,注册的类型可在QML 中使用。通过第二次qt_add_protobuf 调用,我们将自动生成的代码添加到现有的MyApp QML 模块中。在这种情况下,不需要QML_URI 。最后,我们为名为MyApp 的可执行文件创建一个目标,该目标有一个用于图形部分的 QML 模块,并通过my.messages.module.uri 导入将MyMessagesPlugin 加载到 main.qml 文件中。

安装独立的Qt Protobuf

qt_add_protobuf命令还会生成用于进一步安装的工件列表。你可以通过指定OUTPUT_HEADERS, 和OUTPUT_TARGETS 参数来读取这些工件,如下所示:

qt_add_protobuf(MyProtoLib
    PROTO_FILES
        mylib.proto
    OUTPUT_HEADERS
        public_headers
    OUTPUT_TARGETS
        generated_targets
)

该命令会将qt_add_protobuf 命令生成的头文件和目标文件列表相应存储到public_headersgenerated_targets 变量中。

使用标准 CMakeinstall 命令安装工件并为库生成config 文件:

include(GNUInstallDirs)
set_target_properties(MyProtoLib PROPERTIES
    PUBLIC_HEADER
        "${public_headers}"
    INTERFACE_INCLUDE_DIRECTORIES
        "$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}>"
)
install(TARGETS ${generated_targets} EXPORT MyProtoLibTargets
    PUBLIC_HEADER
        DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
install(EXPORT MyProtoLibTargets NAMESPACE MyProtoLib:: DESTINATION lib/cmake/MyProtoLib)

然后在软件包配置文件中使用生成的MyProtoLibTargets 配置。有关软件包创建过程的更多信息,请参阅CMake 官方文档

安装完成后,库就可以作为独立的 CMake 包使用了:

find_package(Qt6 COMPONENTS Protobuf)
find_package(MyProtoLib CONFIG)

add_executable(MyApp main.cpp)
target_link_libraries(MyApp PRIVATE MyProtoLib::MyProtoLib Qt6::Protobuf)

注意: qt_add_protobuf 不会隐式地将 Qt Protobuf模块作为传递依赖关系,无论是MyProtoLib 目标还是MyProtoLib CMake 包。因此 Qt Protobuf模块查询和MyAppQt6::Protobuf 的显式链接是必须的。

另请参阅 qtprotobufgen 工具

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.