• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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