本页内容

qt_add_protobuf

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

该命令定义在 Qt6 软件包的 Protobuf 组件中。请使用以下命令加载该软件包:

find_package(Qt6 REQUIRED COMPONENTS Protobuf)

该命令于 Qt 6.5 版本中引入。

在 CMake 脚本中使用 qt_add_protobuf 调用 `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>]
    [GENERATE_NON_FINAL_MESSAGES] # since Qt 6.11
    [GENERATE_NON_FINAL_PROPERTIES] # since Qt 6.12
)

如果禁用了无版本号的命令,请改用qt6_add_protobuf() 。它支持与本命令相同的参数集。

说明

由qtprotobufgen 生成的源文件随后会被添加到目标中。如果目标已存在,生成的文件将被添加到目标的源文件列表中;如果目标不存在,则会将其作为库创建,您必须将其链接到程序中。

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

    注意: PROTO_FILES 的位置 会被默认视为 protobuf 包含路径的一部分。

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

    如果target是现有的 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`,该文件用于在 `import` 语句中向 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` 的更深入讨论。

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

    请参阅《创建共享库》以获取更多详细信息。

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

    省略该选项或将其设置为filename 时,将生成ifdef 包裹式保护机制,并使用 '.proto' 文件名作为保护后缀:

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

    请根据您的项目结构选择合适的保护符样式。

  • GENERATE_NON_FINAL_MESSAGES (自 Qt 6.11 起)会生成不带final 限定符的QtProtobuf 消息类。此选项是为了向后兼容而提供的。自 Qt 6.11 起,QtProtobuf 消息类默认会生成为final 。若要扩展生成的消息的行为,请优先使用组合而非继承。此选项将在 Qt 7 中移除。
  • GENERATE_NON_FINAL_PROPERTIES (自 Qt 6.12 起)会为不带FINAL 限定符的QtProtobuf 消息类生成属性。FINAL 修饰符可使QML工具应用性能优化并生成更高效的代码。自Qt 6.12起,QtProtobuf 消息属性默认会使用FINAL 修饰符进行生成。此选项仅为向后兼容而提供,将在Qt 7中移除。有关FINAL 修饰符的更多信息,请参阅Qt属性系统。

解析 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_DIRECTORIES 和INTERFACE_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_headers 和generated_targets 变量中。

使用标准的 CMake `install ` 命令来安装构建产物并为您的库生成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 module作为传递依赖,无论是针对MyProtoLib 目标,还是针对MyProtoLib CMake包。因此, Qt Protobuf 必须进行模块查找,并显式将MyApp 链接到Qt6::Protobuf 。

另请参阅 qtprotobufgen 工具。

© 2026 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.