- Qt 6.6
- Qt Protobuf
- CMake Commands in Qt6 Protobuf
- qt_add_protobuf
- Qt 6.6.3 Reference Documentation

# qt_add_protobuf

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

Note: This command is in technology preview and may change in future releases.

This command was introduced in Qt 6.5.

Usually `qtprotobufgen` would be invoked through CMake using the `qt_add_protobuf` command.

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

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

## Arguments

- `COPY_COMMENTS` copies comments from `.proto` files. If provided in the parameter list, comments related to messages and fields are copied to generated header files.
- `GENERATE_PACKAGE_SUBFOLDERS` generates a folder structure for the generated files matching the `.proto` file's package name. For example, `package io.qt.test;` would put the generated files into `io/qt/test/`.
- `EXTRA_NAMESPACE` is an optional namespace that will be used for the generated classes. The classes are always generated in a namespace whose name is the same as the package name specified in the `.proto` file. If this option is used, then everything will be nested inside the extra namespace.
- `EXPORT_MACRO` is the base name of the symbol export macro used for the generated code. The generated macro name is constructed as `QPB_<EXPORT_MACRO>_EXPORT`. If the option is not set, the macro is not generated.
- `QML` enables QProtobufMessage types in QML context by registering them as a QML module. Protobuf types can extend an existing QML module. See code examples:

       qt_add_qml_module(targetname
           ...
       )

       qt_add_protobuf(targetname
           QML
           ...
       )

       qt_add_executable(targetname
           ...
       )

       qt_add_protobuf(targetname
           QML
           ...
       )

  If `qt_add_protobuf` is called with a non-existing target or the target is not a QML module, a new QML module will be created implicitly. In case of the new QML module creation, the qt_add_qml_module command is called inside the `qt_add_protobuf` command. See code example:

       qt_add_executable(targetname
           ...
       )

       qt_add_protobuf(targetplugin
           QML
           QML_URI proto.uri.example
       )

  Every QML module has to define a `URI` name. Other QML modules may use this name in import statements to import the module into a user application. Use the `QML_URI` option to set the `URI` name. It has to be specified in dotted notation, e.g. `Qt.Protobuf.Package`. If `QML_URI` is omitted, then the protobuf package name will be used as the module `URI`.

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

  Note: If the `QML_URI` is skipped, all *.proto files specified in the `qt_add_protobuf` command should have the same `protobuf` package name, since it shall be used as a default `URI` for the resulting QML module.

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

- `QML_URI` enables QProtobufMessage types in the QML context by registering them in a QML module via the provided `URI` import path. The `URI` option will be used in the line of the generated `qmldir` file, and also used to form the target path by replacing dots with forward slashes.

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

- `PROTO_FILES` is the list of `.proto` files that will be used in the generation procedure.
- `PROTO_INCLUDES` is the list of directories that will be searched for dependencies.
- `OUTPUT_DIRECTORY` is the directory where the generated files will be put. By default, the current directory (while evaluating the function) is used.
- `OUTPUT_HEADERS` can be used to specify a variable that will hold the list of headers created by the function. This list can be useful for custom project install rules.
- `OUTPUT_TARGETS` can be used to specify a variable that will hold the list of targets created by the function. This list can be useful for custom project install rules.

## 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:

     syntax = "proto3";

     package test.messages;

     message MyMessage {
         int32 myField = 1;
     }

     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, users need to link to such targets manually in their `CMake` scripts:

     target_link_libraries(test_extensions PUBLIC test_messages)

Note: It's recommended to use the `PUBLIC` linking scope, since messages from `test_messages` target are referenced 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.

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