- Qt 6.10
- Qt Protobuf
- CMake Commands in Qt6 Protobuf
- qt_add_protobuf
- Qt 6.10.2 Reference Documentation

CMake Commands

# qt_add_protobuf

Generates Qt-based C++ source code using a protobuf schema

This command was introduced in Qt 6.5.

Use qt_add_protobuf to invoke `qtprotobufgen` in your CMake scripts and generate the code from the .proto schemes for your projects.`qtprotobufgen` would be invoked through CMake using the `qt_add_protobuf` command.

     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>]
     )

The source files generated by `qtprotobufgen` are then added to the target. If the target already exists, the generated files are added to the target source list. If the target doesn't exist, it is created as a library to which you must link.

## Arguments

- `PROTO_FILES` specifies the list of .proto files used by the code generation procedure.
- `PROTO_INCLUDES` specifies the list of directories to be searched for protobuf dependencies.

  Note: The location of the `PROTO_FILES` is implicitly considered part of the protobuf include path.

- `QML` enables the generation of QML-compatible message types from protobuf definitions and registers them as a QML module. If `qt_add_protobuf` is called on a non-existent target or a target that is not a QML module, a new QML module will be created implicitly.

       find_package(Qt6 6.8 REQUIRED COMPONENTS Quick Protobuf ProtobufQuick)
       ...
       qt_add_executable(target
           ...
       )
       // creates a new QML module
       qt_add_protobuf(target
           QML
           ...
       )

  If target is an existing QML module, `qt_add_protobuf` will attach the generated protobuf types to that module.

       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
           ...
       )

  Note: If you use QML argument, you have to add ProtobufQuick into find_package call. See examples above.

- `QML_URI` defines the `URI` used for the QML module.

  Every QML module must define a `URI`, which is used in import statements to expose its protobuf types to QML.

       qt_add_protobuf(target
           QML
           QML_URI proto.uri.example
       )

  If `QML_URI` is omitted, the protobuf package name will be used as the module's `URI`.

  Note: If the `QML_URI` is omitted, all .proto files specified in the `PROTO_FILES` section must share the same protobuf package name, as it will be used as the default `URI` for the resulting QML module.

  Note: You should avoid creating several protobuf QML modules with the same `QML_URI` or proto package name, because it leads to import error in the QML context.

  Note: If `QML_URI` is passed to the `qt_add_protobuf` function but the target already exists, the `QML_URI` argument will be ignored.

  Read Identified Modules for further in-depth discussion of the `URI`.

- `OUTPUT_DIRECTORY` defines the directory where the generated files will be placed. By default, the current build directory is used.
- `GENERATE_PACKAGE_SUBFOLDERS` uses the package name specifier from the `.proto` files to create the folder structure for the generated files. For example, if the package is defined as: `package io.qt.test`, the generated files will be placed in OUTPUT_DIRECTORY/io/qt/test/.
- `COPY_COMMENTS` copies comments from the `.proto` files into the generated code.
- `EXPORT_MACRO` applies only when creating a new shared library from the <target>. This option specifies the base name for the export macro used in the generated code. The final macro name is constructed as `QPB_<EXPORT_MACRO>_EXPORT`. If this option is not set, the target name is used as `EXPORT_MACRO`.

  Read Creating Shared Libraries for further in-depth information.

- `OUTPUT_HEADERS` specifies a variable that will store the list of generated headers. This list can be useful for defining custom project install rules.
- `OUTPUT_TARGETS` specifies a variable that will store the list of generated targets. This list can be useful for defining custom project install rules.
- `HEADER_GUARD` specifies the mechanism used for guarding generated header files from multiple inclusion. Possible values are `pragma`, `filename`. Defaults to `filename`. Setting the option to `pragma` generates the modern pragma header guard:

       #pragma once
       ...

  Omitting the option or setting the option to `filename` generates the `ifdef` wrapping guard, and uses the '.proto' filename as the guard infix:

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

  Select the preferred guard style according to your project structure.

## Resolving dependencies between protobuf targets

The `qt_add_protobuf` command doesn't consider the dependencies between `.proto` files that are used to generate code for different targets.

The project may have two or more `.proto` files with dependencies:

     // 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;
     }

The above `.proto` files can be used to generate the standalone libraries:

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

Since the `test_extensions` target depends on messages from the `test_messages` target, you need to link to such targets manually in your `CMake` scripts:

     target_link_libraries(test_extensions PUBLIC test_messages)

Note: Messages from `test_messages` target are used in header files that belong to the `test_extensions` target, so targets that link to `test_extensions` should have the `test_messages` target as a transitive dependency. It's recommended to use the `PUBLIC` linking scope, to have the proper `INTERFACE_INCLUDE_DIRECTORIES` and `INTERFACE_LINK_LIBRARIES` properties for protobuf library targets.

## Example

### Using 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)

In the example above, we generate a library called `MyMessages`, which contains the message types defined in the paths passed to the `PROTO_FILES` option. The `GENERATE_PACKAGE_SUBFOLDERS` option to generate a folder structure for the generated files. And the `PROTO_INCLUDES` option tells protoc to look for dependencies or imports in the specified directories. We create a target for an executable called `MyApp`, which we link to the `MyMessages` library.

### QML extended protobuf example

     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)

In the QML extended example above, by the first `qt_add_protobuf` call, we generate a QML module called `MyMessagesPlugin`, which contains the message types defined in the paths passed to the `PROTO_FILES` option. We use the `QML` option, that enables proto message types registration in the `QML` context. The registered types will be available in `QML` by importing a path that is set by the `QML_URI`. By second `qt_add_protobuf` call we add auto-generated code into the existing `MyApp` QML module. The `QML_URI` is not required in such cases. Finally, we create a target for an executable called `MyApp`, which has a QML module for the graphical part and loads `MyMessagesPlugin` into the main.qml file via the `my.messages.module.uri` import.

### Installing standalone Qt Protobuf library

The qt_add_protobuf command also produces lists of artifacts for further installation. You can read these artifacts by specifying `OUTPUT_HEADERS`, and `OUTPUT_TARGETS` arguments as follows:

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

The command stores the list of the header files and targets produced by the `qt_add_protobuf` command to the `public_headers` and `generated_targets` variables accordingly.

Use the standard CMake `install` command to install the artifacts and generate the `config` files for your library:

     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)

Then use the generated `MyProtoLibTargets` config in the package config file. You can read more about the package creation process in the official CMake documentation.

After installation the library is available as the standalone CMake package:

     find_package(Qt6 COMPONENTS Protobuf)
     find_package(MyProtoLib CONFIG)

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

Note: qt_add_protobuf doesn't implicitly add `Qt Protobuf` module as the transitive dependency, neither for the `MyProtoLib` target nor for the `MyProtoLib` CMake package. Therefore, the `Qt Protobuf` module lookup and the explicit linking of `MyApp` to `Qt6::Protobuf` are mandatory.

See also The qtprotobufgen Tool.

CMake Commands