File: proto_extras.gni

package info (click to toggle)
chromium 141.0.7390.107-1
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 6,246,132 kB
  • sloc: cpp: 35,264,965; ansic: 7,169,920; javascript: 4,250,185; python: 1,460,635; asm: 950,788; xml: 751,751; pascal: 187,972; sh: 89,459; perl: 88,691; objc: 79,953; sql: 53,924; cs: 44,622; fortran: 24,137; makefile: 22,313; tcl: 15,277; php: 14,018; yacc: 8,995; ruby: 7,553; awk: 3,720; lisp: 3,096; lex: 1,330; ada: 727; jsp: 228; sed: 36
file content (334 lines) | stat: -rw-r--r-- 12,519 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# Copyright 2025 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# Generate extra functionality for protobuf messages, including:
# - Serialization to base::Value.
# - Stream operator support for C++ printing.
# - equality operator support
# - (future) gtest matchers.
# This does not directly generate the protobuf bindings for any language, so
# callers must include the build target for C++ bindings in the deps. It
# is intended to be used in conjunction with proto_library, not on its own.
#
# Conversion to `base::Value` support:
# - The main generated method is `Serialize(const ProtoMessage& message)`, which
#   returns a `base::Value` (as a dictionary), and resides in the namespace of
#   the proto message.
# - There is a helper method to facilitate the serialization of optional
#   messages, called `MaybeSerialize(const std::optional<ProtoMessage>&
#   message, std::string_view name, base::DictValue& output_dictionary)`.
#   This will serialize the proto to a `base::DictValue` and set it on the
#   passed in `output_dictionary` with the given `name`.
# - Include via <name>.to_value.h.
# - Disable via `omit_to_value_serialization` (default is false)
# - Caveats:
#   - Integer types in the proto that are not compatible with base::Value are
#     serialized as strings (e.g. uint64_t).
#   - Map field scalar keys (numbers) are always converted to a string, as
#     `base::Value` does not support other types as keys for dictionaries.
#
# Stream operator (<<) support:
# - The generated operator resides in the namespace of the proto message.
# - Include via <name>.ostream.h.
# - Disable via `omit_stream_operators` (default is false).
#
# Equality operator (==) support:
# - The generated operator resides in the namespace of the proto message.
# - Include via <name>.equal.h.
# - Disable via `omit_equality` (default is false).
#
# The proto_extras template reads the following other properties:
# - sources (required): The .proto files to generate from.
# - proto_in_dir: The directory to find the proto files in. Defaults to "//".
# - deps: These should be proto_library targets.
# - extras_deps: These are the proto_extras targets for any proto dependencies.
# - defines: This is forwarded to all generated targets.
# - visibility: This is forwarded to all generated targets.
#
# The functionality is split up per-file (instead of everything in a 'utils' or
# 'extras' file) as per go/no-utils guidance. This:
# - Helps prevent scope creep of lots of functionality in one file, and
#   provides the infrastructure to easily make more functionality in a dedicated file.
# - Reduces header includes and build size.
# - Minimizes the build graph if users only need one piece of functionality.
#
# For cases where the message uses the full google::protobuf::Message type,
# the protobuf_full_support option can be used to ensure the generated code
# with the full protobuf library. Due to android build complications, this also
# requires the `use_fuzzing_engine_with_lpm` build flag to be set.
# This option is relevant for base::Value serialization and equality.
#
# Example:
#   proto_extras("foo_extras") {
#     sources = [
#       "foo.proto",
#     ]
#     deps = [
#       ":foo",                    # The target generating foo.pb.h
#       ":foo_dependency",         # The target generating foo_dependency.pb.h
#     ]
#     extras_deps = [
#       ":foo_dependency_extras",  # The proto_extras target for foo_dependency.
#     ]
#     omit_to_value_serialization = true   # default is false
#     omit_stream_operators = true         # default is false
#     protobuf_full_support = true         # default is false
#     # Note: This target fails as there is no functionality being generated!
#   }
#
# Consumers would then depend on ":foo_extras", and include foo.to_value.h,
# foo.ostream.h, etc.
#
# Other Notes:
# - base::DictValue is the preferred type to base::Value::Dict, as it is
#   forward-declarable, allowing for less header includes.

import("//testing/libfuzzer/fuzzer_test.gni")
import("//third_party/protobuf/proto_library.gni")

template("proto_extras") {
  _generate_to_value = true
  if (defined(invoker.omit_to_value_serialization) &&
      invoker.omit_to_value_serialization) {
    _generate_to_value = false
  }
  _generate_ostream = true
  if (defined(invoker.omit_stream_operators) &&
      !invoker.omit_stream_operators) {
    _generate_ostream = false
  }
  _generate_equality = true
  if (defined(invoker.omit_equality) && invoker.omit_equality) {
    _generate_equality = false
  }
  _protobuf_full_support = false
  if (defined(invoker.protobuf_full_support) && invoker.protobuf_full_support &&
      use_fuzzing_engine_with_lpm) {
    _protobuf_full_support = true
  }
  _proto_in_dir = "//"
  if (defined(invoker.proto_in_dir)) {
    _proto_in_dir = invoker.proto_in_dir
  }

  assert(
      !_generate_ostream || _generate_to_value,
      "Stream operator generation currently depends on ToValue " +
          "serialization. Cannot set omit_to_value_serialization = true if " +
          "omit_stream_operators = false. Target: ${target_name}")

  assert(_generate_to_value || _generate_ostream || _generate_equality,
         "There must be one generation type enabled. Target: ${target_name}")

  _extras_deps = []
  if (defined(invoker.extras_deps)) {
    _extras_deps += invoker.extras_deps
  }

  _all_targets = []
  _to_value_target_name = "${target_name}_to_value"
  if (_generate_to_value) {
    _all_targets += [ _to_value_target_name ]
    proto_library(_to_value_target_name) {
      proto_in_dir = _proto_in_dir
      forward_variables_from(invoker,
                             [
                               "deps",
                               "defines",
                               "sources",
                               "visibility",
                             ])
      link_deps = [ "//components/proto_extras:proto_extras_lib" ]
      if (_protobuf_full_support) {
        link_deps += [ "//components/proto_extras:protobuf_full_support" ]
      }

      # Link the *_to_value targets for all extras_deps.
      _extras_deps_to_value = []
      foreach(_dep, _extras_deps) {
        _extras_deps_to_value += [ "${_dep}_to_value" ]
      }
      link_deps += _extras_deps_to_value

      generator_plugin_label = "//components/proto_extras:proto_extras_plugin"
      generator_plugin_suffix = ".to_value"
      generate_cc = false
      generate_python = false
      link_public_deps = [ "//base" ]
      _to_value_options_list = [ "generate_to_value_serialization" ]
      if (_protobuf_full_support) {
        _to_value_options_list += [ "protobuf_full_support" ]
      }
      generator_plugin_options = string_join(",", _to_value_options_list)
    }
  }

  if (_generate_ostream) {
    _ostream_target_name = "${target_name}_ostream"
    _all_targets += [ _ostream_target_name ]
    proto_library(_ostream_target_name) {
      proto_in_dir = _proto_in_dir
      forward_variables_from(invoker,
                             [
                               "defines",
                               "sources",
                               "visibility",
                             ])

      deps = [ ":$_to_value_target_name" ]
      if (defined(invoker.deps)) {
        deps += invoker.deps
      }
      link_deps = [ "//base" ]

      generator_plugin_label = "//components/proto_extras:proto_extras_plugin"
      generator_plugin_suffix = ".ostream"
      generate_cc = false
      generate_python = false
      generator_plugin_options = "generate_stream_operator"
    }
  }

  if (_generate_equality) {
    _equality_target_name = "${target_name}_equal"
    _all_targets += [ _equality_target_name ]
    proto_library(_equality_target_name) {
      proto_in_dir = _proto_in_dir
      forward_variables_from(invoker,
                             [
                               "deps",
                               "defines",
                               "sources",
                               "visibility",
                             ])

      # Link the *_to_value targets for all extras_deps.
      _extras_deps_equality = []
      foreach(_dep, _extras_deps) {
        _extras_deps_equality += [ "${_dep}_equal" ]
      }
      link_deps = _extras_deps_equality
      _equality_options_list = [ "generate_equality" ]
      if (_protobuf_full_support) {
        _equality_options_list += [ "protobuf_full_support" ]
        link_deps += [ "//components/proto_extras:protobuf_full_support" ]
      }

      generator_plugin_label = "//components/proto_extras:proto_extras_plugin"
      generator_plugin_suffix = ".equal"
      generate_cc = false
      generate_python = false
      generator_plugin_options = string_join(",", _equality_options_list)
    }
  }

  # Group all generated targets into one group for the target_name.
  # Users can techncally depend on the generated target names for a more
  # optimized build graph, but it is uncommon in the codebase to not depend on a
  # target that is specifically named, so this ensures that the normal behavior
  # works.
  group(target_name) {
    forward_variables_from(invoker,
                           [
                             "defines",
                             "visibility",
                           ])
    public_deps = []
    foreach(_target, _all_targets) {
      public_deps += [ ":$_target" ]
    }
  }
}

# Generate extra test functionality for protobuf messages. Similar to
# proto_extras, this does not generate protobuf bindings, but instead generates
# gtest matchers for the generated protobuf bindings.
#
# Features:
# - Gmock matchers for all messages, for verbose equality checking in tests
# - PrintTo implementations for gtest output.
#
# The functionality is output to a file named <name>.test.h.
#
# The proto_test_extras template supports the following other properties:
# - test_extras_deps: These are the proto_test_extras targets for any proto
#   dependencies.
# - extras_deps: These are the proto_extras targets for any proto dependencies.
# - sources: The .proto files to generate from.
# - deps: These should be proto_library targets.
# - defines: This is forwarded to all generated targets.
# - visibility: This is forwarded to all generated targets.
#
# The reason this target needs the proto_extras target is that the generated
# code uses the generated `Serialize` <name>.to_value.h serialization.
#
# Example usage:
# proto_test_extras("foo_test_extras") {
#   sources = [
#     "foo.proto",
#   ]
#   deps = [
#     ":foo",
#     ":foo_dependency",         # The target generating foo_dependency.pb.h
#   ]
#   test_extras_deps = [
#     ":foo_dependency_test_extras",
#   ]
#   extras_deps = [
#     ":foo_dependency_extras",
#   ]
# }
template("proto_test_extras") {
  testonly = true
  _test_extras_deps = []
  if (defined(invoker.test_extras_deps)) {
    _test_extras_deps += invoker.test_extras_deps
  }
  _extras_deps = []
  if (defined(invoker.extras_deps)) {
    _extras_deps += invoker.extras_deps
  }
  _proto_in_dir = "//"
  if (defined(invoker.proto_in_dir)) {
    _proto_in_dir = invoker.proto_in_dir
  }
  if (defined(invoker.deps) && invoker.deps != [] && _extras_deps == []) {
    assert(
        false,
        "The `deps` field is set, but the `extras_deps` field is not set. " +
        "Protobuf depependencies need to have a corresponding proto_extras " +
        " target so the generated matchers can use the `Serialize()` call.")
  }
  proto_library("${target_name}") {
    testonly = true
    proto_in_dir = _proto_in_dir
    forward_variables_from(invoker,
                           [
                             "defines",
                             "visibility",
                             "deps",
                             "sources",
                           ])
    generator_plugin_label =
        "//components/proto_extras:proto_test_extras_plugin"
    generator_plugin_suffix = ".test"
    generate_cc = false
    generate_python = false

    link_deps = []
    foreach(_dep, _extras_deps) {
      link_deps += [ "${_dep}_to_value" ]
    }

    # Due to gmock/gtest being an entirely header-based library, all
    # dependencies need to be publicly linked as there is no private
    # implementation.
    link_public_deps = [
      "//base",
      "//components/proto_extras:proto_matchers",
      "//testing/gmock",
    ]
    link_public_deps += _test_extras_deps
  }
}