| # How to use `protobuf_generate` | |
| This document explains how to use the function `protobuf_generate` which is | |
| provided by protobuf's CMake module. | |
| ## Usage | |
| In the same directory that called `find_package(protobuf CONFIG)` and any of its | |
| subdirectories, the CMake function `protobuf_generate` is made available by | |
| [`protobuf-generate.cmake`](../cmake/protobuf-generate.cmake). It can be used to | |
| automatically generate source files from `.proto` schema files at build time. | |
| ### Basic example | |
| Let us see how `protobuf_generate` can be used to generate and compile the | |
| source files of a proto schema whenever an object target called `proto-objects` | |
| is built. | |
| Given the following directory structure: | |
| - `proto/helloworld/helloworld.proto` | |
| - `CMakeLists.txt` | |
| where `helloworld.proto` is a protobuf schema file and `CMakeLists.txt` | |
| contains: | |
| ```cmake | |
| find_package(protobuf CONFIG REQUIRED) | |
| add_library(proto-objects OBJECT "${CMAKE_CURRENT_LIST_DIR}/proto/helloworld/helloworld.proto") | |
| target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf) | |
| set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") | |
| target_include_directories(proto-objects PUBLIC "$<BUILD_INTERFACE:${PROTO_BINARY_DIR}>") | |
| protobuf_generate( | |
| TARGET proto-objects | |
| IMPORT_DIRS "${CMAKE_CURRENT_LIST_DIR}/proto" | |
| PROTOC_OUT_DIR "${PROTO_BINARY_DIR}") | |
| ``` | |
| Building the target `proto-objects` will generate the files: | |
| - `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.h` | |
| - `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.cc` | |
| and (depending on the build system) output: | |
| ```shell | |
| [build] [1/2] Running cpp protocol buffer compiler on /proto/helloworld/helloworld.proto | |
| [build] [2/2] Building CXX object /build/generated/helloworld/helloworld.pb.cc.o | |
| ``` | |
| ### gRPC example | |
| `protobuf_generate` can also be customized to invoke plugins like gRPC's | |
| `grpc_cpp_plugin`. Given the same directory structure as in the | |
| [basic example](#basic-example) and let `CMakeLists.txt` contain: | |
| ```cmake | |
| find_package(gRPC CONFIG REQUIRED) | |
| add_library(proto-objects OBJECT "${CMAKE_CURRENT_LIST_DIR}/proto/helloworld/helloworld.proto") | |
| target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf gRPC::grpc++) | |
| set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") | |
| set(PROTO_IMPORT_DIRS "${CMAKE_CURRENT_LIST_DIR}/proto") | |
| target_include_directories(proto-objects PUBLIC "$<BUILD_INTERFACE:${PROTO_BINARY_DIR}>") | |
| protobuf_generate( | |
| TARGET proto-objects | |
| IMPORT_DIRS ${PROTO_IMPORT_DIRS} | |
| PROTOC_OUT_DIR "${PROTO_BINARY_DIR}") | |
| protobuf_generate( | |
| TARGET proto-objects | |
| LANGUAGE grpc | |
| GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc | |
| PLUGIN "protoc-gen-grpc=\$<TARGET_FILE:gRPC::grpc_cpp_plugin>" | |
| IMPORT_DIRS ${PROTO_IMPORT_DIRS} | |
| PROTOC_OUT_DIR "${PROTO_BINARY_DIR}") | |
| ``` | |
| Then building `proto-objects` will generate and compile: | |
| - `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.h` | |
| - `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.cc` | |
| - `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.grpc.pb.h` | |
| - `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.grpc.pb.cc` | |
| And `protoc` will automatically be re-run whenever the schema files change and | |
| `proto-objects` is built. | |
| ### Note on unity builds | |
| Since protobuf's generated source files are unsuited for | |
| [jumbo/unity builds](https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html) | |
| it is recommended to exclude them from such builds which can be achieved by | |
| adjusting their properties: | |
| ```cmake | |
| protobuf_generate( | |
| OUT_VAR PROTO_GENERATED_FILES | |
| ...) | |
| set_source_files_properties(${PROTO_GENERATED_FILES} PROPERTIES SKIP_UNITY_BUILD_INCLUSION on) | |
| ``` | |
| ## How it works | |
| For each source file ending in `proto` of the argument provided to `TARGET` or | |
| each file provided through `PROTOS`, `protobuf_generate` will set up a | |
| [add_custom_command](https://cmake.org/cmake/help/latest/command/add_custom_command.html) | |
| which depends on `protobuf::protoc` and the proto files. It declares the | |
| generated source files as `OUTPUT` which means that any target that depends on | |
| them will automatically cause the custom command to execute when it is brought | |
| up to date. The command itself is made up of the arguments for `protoc`, like | |
| the output directory, the schema files, the language to generate for, the | |
| plugins to use, etc. | |
| ## Reference | |
| Arguments accepted by `protobuf_generate`. | |
| Flag arguments: | |
| - `APPEND_PATH` — A flag that causes the base path of all proto schema files | |
| to be added to `IMPORT_DIRS`. | |
| Single-value arguments: | |
| - `LANGUAGE` — A single value: cpp or python. Determines what kind of source | |
| files are being generated. | |
| - `OUT_VAR` — Name of a CMake variable that will be filled with the paths to | |
| the generated source files. | |
| - `EXPORT_MACRO` — Name of a macro that is applied to all generated Protobuf | |
| message classes and extern variables. It can, for example, be used to | |
| declare DLL exports. | |
| - `PROTOC_EXE` — Command name, path, or CMake executable used to run protoc | |
| commands. Defaults to `protobuf::protoc`. | |
| - `PROTOC_OUT_DIR` — Output directory of generated source files. Defaults to | |
| `CMAKE_CURRENT_BINARY_DIR`. | |
| - `PLUGIN` — An optional plugin executable. This could, for example, be the | |
| path to `grpc_cpp_plugin`. | |
| - `PLUGIN_OPTIONS` — Additional options provided to the plugin, such as | |
| `generate_mock_code=true` for the gRPC cpp plugin. | |
| - `DEPENDENCIES` — Arguments forwarded to the `DEPENDS` of the underlying | |
| `add_custom_command` invocation. | |
| - `TARGET` — CMake target that will have the generated files added as sources. | |
| Multi-value arguments: | |
| - `PROTOS` — List of proto schema files. If omitted, then every source file | |
| ending in *proto* of `TARGET` will be used. | |
| - `IMPORT_DIRS` — A common parent directory for the schema files. For example, | |
| if the schema file is `proto/helloworld/helloworld.proto` and the import | |
| directory `proto/` then the generated files are | |
| `${PROTOC_OUT_DIR}/helloworld/helloworld.pb.h` and | |
| `${PROTOC_OUT_DIR}/helloworld/helloworld.pb.cc`. | |
| - `GENERATE_EXTENSIONS` — If LANGUAGE is omitted then this must be set to the | |
| extensions that protoc generates. | |
| - `PROTOC_OPTIONS` — Additional arguments that are forwarded to protoc. Don't | |
| use it for flags that `protobuf_generate` sets from its own arguments: | |
| import paths (`-I`/`--proto_path`; use `IMPORT_DIRS` or `APPEND_PATH`), the | |
| output directory and generator options (`--<lang>_out`; use | |
| `PROTOC_OUT_DIR` and `PLUGIN_OPTIONS`) or plugins (`--plugin`; use | |
| `PLUGIN`). The generated file names are worked out from those arguments, | |
| so flags passed here aren't taken into account. |