1# How to use `protobuf_generate` 2 3This document explains how to use the function `protobuf_generate` which is provided by protobuf's CMake module. 4 5## Usage 6 7In the same directory that called `find_package(protobuf CONFIG)` and any of its subdirectories, the CMake function `protobuf_generate` is made available by 8[`protobuf-generate.cmake`](../cmake/protobuf-generate.cmake). It can be used to automatically generate source files from `.proto` schema files at build time. 9 10### Basic example 11 12Let 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. 13 14Given the following directory structure: 15 16- `proto/helloworld/helloworld.proto` 17- `CMakeLists.txt` 18 19where `helloworld.proto` is a protobuf schema file and `CMakeLists.txt` contains: 20 21```cmake 22find_package(protobuf CONFIG REQUIRED) 23 24add_library(proto-objects OBJECT "${CMAKE_CURRENT_LIST_DIR}/proto/helloworld/helloworld.proto") 25 26target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf) 27 28set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") 29 30target_include_directories(proto-objects PUBLIC "$<BUILD_INTERFACE:${PROTO_BINARY_DIR}>") 31 32protobuf_generate( 33 TARGET proto-objects 34 IMPORT_DIRS "${CMAKE_CURRENT_LIST_DIR}/proto" 35 PROTOC_OUT_DIR "${PROTO_BINARY_DIR}") 36``` 37 38Building the target `proto-objects` will generate the files: 39 40- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.h` 41- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.cc` 42 43and (depending on the build system) output: 44 45```shell 46[build] [1/2] Running cpp protocol buffer compiler on /proto/helloworld/helloworld.proto 47[build] [2/2] Building CXX object /build/generated/helloworld/helloworld.pb.cc.o 48``` 49 50### gRPC example 51 52`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) 53and let `CMakeLists.txt` contain: 54 55```cmake 56find_package(gRPC CONFIG REQUIRED) 57 58add_library(proto-objects OBJECT "${CMAKE_CURRENT_LIST_DIR}/proto/helloworld/helloworld.proto") 59 60target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf gRPC::grpc++) 61 62set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") 63set(PROTO_IMPORT_DIRS "${CMAKE_CURRENT_LIST_DIR}/proto") 64 65target_include_directories(proto-objects PUBLIC "$<BUILD_INTERFACE:${PROTO_BINARY_DIR}>") 66 67protobuf_generate( 68 TARGET proto-objects 69 IMPORT_DIRS ${PROTO_IMPORT_DIRS} 70 PROTOC_OUT_DIR "${PROTO_BINARY_DIR}") 71 72protobuf_generate( 73 TARGET proto-objects 74 LANGUAGE grpc 75 GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc 76 PLUGIN "protoc-gen-grpc=\$<TARGET_FILE:gRPC::grpc_cpp_plugin>" 77 IMPORT_DIRS ${PROTO_IMPORT_DIRS} 78 PROTOC_OUT_DIR "${PROTO_BINARY_DIR}") 79``` 80 81Then building `proto-objects` will generate and compile: 82 83- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.h` 84- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.cc` 85- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.grpc.pb.h` 86- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.grpc.pb.cc` 87 88And `protoc` will automatically be re-run whenever the schema files change and `proto-objects` is built. 89 90### Note on unity builds 91 92Since 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 93to exclude them from such builds which can be achieved by adjusting their properties: 94 95```cmake 96protobuf_generate( 97 OUT_VAR PROTO_GENERATED_FILES 98 ...) 99 100set_source_files_properties(${PROTO_GENERATED_FILES} PROPERTIES SKIP_UNITY_BUILD_INCLUSION on) 101``` 102 103## How it works 104 105For each source file ending in `proto` of the argument provided to `TARGET` or each file provided through `PROTOS`, `protobuf_generate` will set up 106a [add_custom_command](https://cmake.org/cmake/help/latest/command/add_custom_command.html) which depends on `protobuf::protoc` and the proto files. 107It declares the generated source files as `OUTPUT` which means that any target that depends on them will automatically cause the custom command to execute 108when 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 109generate for, the plugins to use, etc. 110 111## Reference 112 113Arguments accepted by `protobuf_generate`. 114 115Flag arguments: 116 117- `APPEND_PATH` — A flag that causes the base path of all proto schema files to be added to `IMPORT_DIRS`. 118 119Single-value arguments: 120 121- `LANGUAGE` — A single value: cpp or python. Determines what kind of source 122 files are being generated. 123- `OUT_VAR` — Name of a CMake variable that will be filled with the paths to 124 the generated source files. 125- `EXPORT_MACRO` — Name of a macro that is applied to all generated Protobuf 126 message classes and extern variables. It can, for example, be used to 127 declare DLL exports. 128- `PROTOC_EXE` — Command name, path, or CMake executable used to run protoc 129 commands. Defaults to `protobuf::protoc`. 130- `PROTOC_OUT_DIR` — Output directory of generated source files. Defaults to 131 `CMAKE_CURRENT_BINARY_DIR`. 132- `PLUGIN` — An optional plugin executable. This could, for example, be the 133 path to `grpc_cpp_plugin`. 134- `PLUGIN_OPTIONS` — Additional options provided to the plugin, such as 135 `generate_mock_code=true` for the gRPC cpp plugin. 136- `DEPENDENCIES` — Arguments forwarded to the `DEPENDS` of the underlying 137 `add_custom_command` invocation. 138- `TARGET` — CMake target that will have the generated files added as sources. 139 140Multi-value arguments: 141 142- `PROTOS` — List of proto schema files. If omitted, then every source file 143 ending in *proto* of `TARGET` will be used. 144- `IMPORT_DIRS` — A common parent directory for the schema files. For example, 145 if the schema file is `proto/helloworld/helloworld.proto` and the import 146 directory `proto/` then the generated files are 147 `${PROTOC_OUT_DIR}/helloworld/helloworld.pb.h` and 148 `${PROTOC_OUT_DIR}/helloworld/helloworld.pb.cc`. 149- `GENERATE_EXTENSIONS` — If LANGUAGE is omitted then this must be set to the 150 extensions that protoc generates. 151- `PROTOC_OPTIONS` — Additional arguments that are forwarded to protoc. 152