Merge "shared_lib: Support extensions in the protoc macros" into main
diff --git a/include/perfetto/public/pb_macros.h b/include/perfetto/public/pb_macros.h
index 03724a5..ba12ed2 100644
--- a/include/perfetto/public/pb_macros.h
+++ b/include/perfetto/public/pb_macros.h
@@ -110,87 +110,87 @@
#define PERFETTO_I_PB_GET_MSG(C_TYPE) PERFETTO_I_PB_CONCAT_3(C_TYPE, _, get_msg)
-#define PERFETTO_I_PB_FIELD_STRING(PROTO, C_TYPE, NAME, NUM) \
- static inline void PERFETTO_I_PB_SETTER_CSTR_NAME(PROTO, NAME)( \
+#define PERFETTO_I_PB_FIELD_STRING(PREFIX, PROTO, C_TYPE, NAME, NUM) \
+ static inline void PERFETTO_I_PB_SETTER_CSTR_NAME(PREFIX, NAME)( \
struct PROTO * msg, const char* value) { \
PerfettoPbMsgAppendCStrField(&msg->msg, NUM, value); \
} \
- static inline void PERFETTO_I_PB_SETTER_NAME(PROTO, NAME)( \
+ static inline void PERFETTO_I_PB_SETTER_NAME(PREFIX, NAME)( \
struct PROTO * msg, const void* data, size_t len) { \
PerfettoPbMsgAppendType2Field( \
&msg->msg, NUM, PERFETTO_STATIC_CAST(const uint8_t*, data), len); \
} \
- static inline void PERFETTO_I_PB_SETTER_BEGIN_NAME(PROTO, NAME)( \
+ static inline void PERFETTO_I_PB_SETTER_BEGIN_NAME(PREFIX, NAME)( \
struct PROTO * msg, struct PerfettoPbMsg * nested) { \
PerfettoPbMsgBeginNested(&msg->msg, nested, NUM); \
} \
- static inline void PERFETTO_I_PB_SETTER_END_NAME(PROTO, NAME)( \
+ static inline void PERFETTO_I_PB_SETTER_END_NAME(PREFIX, NAME)( \
struct PROTO * msg, struct PerfettoPbMsg * nested) { \
(void)nested; \
PerfettoPbMsgEndNested(&msg->msg); \
}
-#define PERFETTO_I_PB_FIELD_VARINT(PROTO, C_TYPE, NAME, NUM) \
- static inline void PERFETTO_I_PB_SETTER_NAME(PROTO, NAME)( \
+#define PERFETTO_I_PB_FIELD_VARINT(PREFIX, PROTO, C_TYPE, NAME, NUM) \
+ static inline void PERFETTO_I_PB_SETTER_NAME(PREFIX, NAME)( \
struct PROTO * msg, C_TYPE value) { \
PerfettoPbMsgAppendType0Field(&msg->msg, NUM, \
PERFETTO_STATIC_CAST(uint64_t, value)); \
}
-#define PERFETTO_I_PB_FIELD_ZIGZAG(PROTO, C_TYPE, NAME, NUM) \
- static inline void PERFETTO_I_PB_SETTER_NAME(PROTO, NAME)( \
+#define PERFETTO_I_PB_FIELD_ZIGZAG(PREFIX, PROTO, C_TYPE, NAME, NUM) \
+ static inline void PERFETTO_I_PB_SETTER_NAME(PREFIX, NAME)( \
struct PROTO * msg, C_TYPE value) { \
uint64_t encoded = \
PerfettoPbZigZagEncode64(PERFETTO_STATIC_CAST(int64_t, value)); \
PerfettoPbMsgAppendType0Field(&msg->msg, NUM, encoded); \
}
-#define PERFETTO_I_PB_FIELD_FIXED64(PROTO, C_TYPE, NAME, NUM) \
- static inline void PERFETTO_I_PB_SETTER_NAME(PROTO, NAME)( \
- struct PROTO * msg, C_TYPE value) { \
- uint64_t val; \
- memcpy(&val, &value, sizeof val); \
- PerfettoPbMsgAppendFixed64Field(&msg->msg, NUM, val); \
+#define PERFETTO_I_PB_FIELD_FIXED64(PREFIX, PROTO, C_TYPE, NAME, NUM) \
+ static inline void PERFETTO_I_PB_SETTER_NAME(PREFIX, NAME)( \
+ struct PROTO * msg, C_TYPE value) { \
+ uint64_t val; \
+ memcpy(&val, &value, sizeof val); \
+ PerfettoPbMsgAppendFixed64Field(&msg->msg, NUM, val); \
}
-#define PERFETTO_I_PB_FIELD_FIXED32(PROTO, C_TYPE, NAME, NUM) \
- static inline void PERFETTO_I_PB_SETTER_NAME(PROTO, NAME)( \
- struct PROTO * msg, C_TYPE value) { \
- uint32_t val; \
- memcpy(&val, &value, sizeof val); \
- PerfettoPbMsgAppendFixed32Field(&msg->msg, NUM, val); \
+#define PERFETTO_I_PB_FIELD_FIXED32(PREFIX, PROTO, C_TYPE, NAME, NUM) \
+ static inline void PERFETTO_I_PB_SETTER_NAME(PREFIX, NAME)( \
+ struct PROTO * msg, C_TYPE value) { \
+ uint32_t val; \
+ memcpy(&val, &value, sizeof val); \
+ PerfettoPbMsgAppendFixed32Field(&msg->msg, NUM, val); \
}
-#define PERFETTO_I_PB_FIELD_MSG(PROTO, C_TYPE, NAME, NUM) \
- static inline void PERFETTO_I_PB_SETTER_BEGIN_NAME(PROTO, NAME)( \
- struct PROTO * msg, struct C_TYPE * nested) { \
- struct PerfettoPbMsg* nested_msg = \
- PERFETTO_REINTERPRET_CAST(struct PerfettoPbMsg*, nested); \
- PerfettoPbMsgBeginNested(&msg->msg, nested_msg, NUM); \
- } \
- static inline void PERFETTO_I_PB_SETTER_END_NAME(PROTO, NAME)( \
- struct PROTO * msg, struct C_TYPE * nested) { \
- (void)nested; \
- PerfettoPbMsgEndNested(&msg->msg); \
+#define PERFETTO_I_PB_FIELD_MSG(PREFIX, PROTO, C_TYPE, NAME, NUM) \
+ static inline void PERFETTO_I_PB_SETTER_BEGIN_NAME(PREFIX, NAME)( \
+ struct PROTO * msg, struct C_TYPE * nested) { \
+ struct PerfettoPbMsg* nested_msg = \
+ PERFETTO_REINTERPRET_CAST(struct PerfettoPbMsg*, nested); \
+ PerfettoPbMsgBeginNested(&msg->msg, nested_msg, NUM); \
+ } \
+ static inline void PERFETTO_I_PB_SETTER_END_NAME(PREFIX, NAME)( \
+ struct PROTO * msg, struct C_TYPE * nested) { \
+ (void)nested; \
+ PerfettoPbMsgEndNested(&msg->msg); \
}
-#define PERFETTO_I_PB_FIELD_PACKED(PROTO, C_TYPE, NAME, NUM) \
- static inline void PERFETTO_I_PB_SETTER_NAME(PROTO, NAME)( \
- struct PROTO * msg, const void* data, size_t len) { \
- PerfettoPbMsgAppendType2Field( \
- &msg->msg, NUM, PERFETTO_STATIC_CAST(const uint8_t*, data), len); \
- } \
- static inline void PERFETTO_I_PB_SETTER_BEGIN_NAME(PROTO, NAME)( \
- struct PROTO * msg, struct PerfettoPbPackedMsg##C_TYPE * nested) { \
- struct PerfettoPbMsg* nested_msg = \
- PERFETTO_REINTERPRET_CAST(struct PerfettoPbMsg*, nested); \
- PerfettoPbMsgBeginNested(&msg->msg, nested_msg, NUM); \
- } \
- static inline void PERFETTO_I_PB_SETTER_END_NAME(PROTO, NAME)( \
- struct PROTO * msg, struct PerfettoPbPackedMsg##C_TYPE * nested) { \
- (void)nested; \
- PerfettoPbMsgEndNested(&msg->msg); \
- } \
+#define PERFETTO_I_PB_FIELD_PACKED(PREFIX, PROTO, C_TYPE, NAME, NUM) \
+ static inline void PERFETTO_I_PB_SETTER_NAME(PREFIX, NAME)( \
+ struct PROTO * msg, const void* data, size_t len) { \
+ PerfettoPbMsgAppendType2Field( \
+ &msg->msg, NUM, PERFETTO_STATIC_CAST(const uint8_t*, data), len); \
+ } \
+ static inline void PERFETTO_I_PB_SETTER_BEGIN_NAME(PREFIX, NAME)( \
+ struct PROTO * msg, struct PerfettoPbPackedMsg##C_TYPE * nested) { \
+ struct PerfettoPbMsg* nested_msg = \
+ PERFETTO_REINTERPRET_CAST(struct PerfettoPbMsg*, nested); \
+ PerfettoPbMsgBeginNested(&msg->msg, nested_msg, NUM); \
+ } \
+ static inline void PERFETTO_I_PB_SETTER_END_NAME(PREFIX, NAME)( \
+ struct PROTO * msg, struct PerfettoPbPackedMsg##C_TYPE * nested) { \
+ (void)nested; \
+ PerfettoPbMsgEndNested(&msg->msg); \
+ }
#define PERFETTO_I_PB_NUM_FIELD(PROTO, NAME, NUM) \
enum { PERFETTO_I_PB_NUM_FIELD_NAME(PROTO, NAME) = NUM }
@@ -259,10 +259,20 @@
// nested): Begins (and ends) a packed helper nested submessage (of the
// right type) to allow users to push repeated entries one by one
// directly into the stream writer buffer.
-#define PERFETTO_PB_FIELD(PROTO, TYPE, C_TYPE, NAME, NUM) \
- PERFETTO_I_PB_FIELD_##TYPE(PROTO, C_TYPE, NAME, NUM) \
+#define PERFETTO_PB_FIELD(PROTO, TYPE, C_TYPE, NAME, NUM) \
+ PERFETTO_I_PB_FIELD_##TYPE(PROTO, PROTO, C_TYPE, NAME, NUM) \
PERFETTO_I_PB_NUM_FIELD(PROTO, NAME, NUM)
+// Defines accessors for a field of a message for an extension.
+// * `EXTENSION`: The name of the extension. it's going to be used as a prefix.
+// There doesn't need to be a PERFETTO_PB_MSG definition for this.
+// * `PROTO`: The (base) message that contains this field. This should be the
+// same identifier passed to PERFETTO_PB_MSG.
+// The rest of the params are the same as the PERFETTO_PB_FIELD macro.
+#define PERFETTO_PB_EXTENSION_FIELD(EXTENSION, PROTO, TYPE, C_TYPE, NAME, NUM) \
+ PERFETTO_I_PB_FIELD_##TYPE(EXTENSION, PROTO, C_TYPE, NAME, NUM) \
+ PERFETTO_I_PB_NUM_FIELD(EXTENSION, NAME, NUM)
+
// Defines an enum type nested inside a message (PROTO).
#define PERFETTO_PB_ENUM_IN_MSG(PROTO, ENUM) \
enum PERFETTO_I_PB_CONCAT_3(PROTO, _, ENUM)
diff --git a/src/protozero/protoc_plugin/protozero_c_plugin.cc b/src/protozero/protoc_plugin/protozero_c_plugin.cc
index 804968e..de3a99a 100644
--- a/src/protozero/protoc_plugin/protozero_c_plugin.cc
+++ b/src/protozero/protoc_plugin/protozero_c_plugin.cc
@@ -94,6 +94,8 @@
GenerateEnumDescriptor(enumeration);
for (const Descriptor* message : messages_)
GenerateMessageDescriptor(message);
+ for (const auto& [name, descriptors] : extensions_)
+ GenerateExtension(name, descriptors);
GenerateEpilogue();
return error_.empty();
}
@@ -240,7 +242,8 @@
// As the support for extensions in protozero is limited, the code
// assumes that extend blocks are located inside a wrapper message and
// name of this message is used to group them.
- std::string extension_name = extension->extension_scope()->name();
+ std::string extension_name =
+ GetCppClassName(extension->extension_scope());
extensions_[extension_name].push_back(extension);
}
} else {
@@ -449,7 +452,7 @@
// Packed repeated fields are encoded as a length-delimited field on the wire,
// where the payload is the concatenation of invidually encoded elements.
- void GeneratePackedRepeatedFieldDescriptor(
+ void GeneratePackedRepeatedFieldDescriptorArgs(
const std::string& message_cpp_type,
const FieldDescriptor* field) {
std::map<std::string, std::string> setter;
@@ -457,13 +460,29 @@
setter["name"] = field->lowercase_name();
setter["class"] = message_cpp_type;
setter["buffer_type"] = FieldTypeToPackedBufferType(field->type());
- stub_h_->Print(
- setter,
- "PERFETTO_PB_FIELD($class$, PACKED, $buffer_type$, $name$, $id$);\n");
+ stub_h_->Print(setter, "$class$, PACKED, $buffer_type$, $name$, $id$\n");
}
- void GenerateSimpleFieldDescriptor(const std::string& message_cpp_type,
- const FieldDescriptor* field) {
+ void GeneratePackedRepeatedFieldDescriptor(
+ const std::string& message_cpp_type,
+ const FieldDescriptor* field) {
+ stub_h_->Print("PERFETTO_PB_FIELD(");
+ GeneratePackedRepeatedFieldDescriptorArgs(message_cpp_type, field);
+ stub_h_->Print(");\n");
+ }
+
+ void GeneratePackedRepeatedFieldDescriptorForExtension(
+ const std::string& field_cpp_prefix,
+ const std::string& message_cpp_type,
+ const FieldDescriptor* field) {
+ stub_h_->Print("PERFETTO_PB_EXTENSION_FIELD($prefix$, ", "prefix",
+ field_cpp_prefix);
+ GeneratePackedRepeatedFieldDescriptorArgs(message_cpp_type, field);
+ stub_h_->Print(");\n");
+ }
+
+ void GenerateSimpleFieldDescriptorArgs(const std::string& message_cpp_type,
+ const FieldDescriptor* field) {
std::map<std::string, std::string> setter;
setter["id"] = std::to_string(field->number());
setter["name"] = field->lowercase_name();
@@ -473,9 +492,7 @@
switch (field->type()) {
case FieldDescriptor::TYPE_BYTES:
case FieldDescriptor::TYPE_STRING:
- stub_h_->Print(
- setter,
- "PERFETTO_PB_FIELD($class$, STRING, const char*, $name$, $id$);\n");
+ stub_h_->Print(setter, "$class$, STRING, const char*, $name$, $id$");
break;
case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_UINT32:
@@ -483,29 +500,21 @@
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_BOOL:
case FieldDescriptor::TYPE_ENUM:
- stub_h_->Print(
- setter,
- "PERFETTO_PB_FIELD($class$, VARINT, $ctype$, $name$, $id$);\n");
+ stub_h_->Print(setter, "$class$, VARINT, $ctype$, $name$, $id$");
break;
case FieldDescriptor::TYPE_SINT64:
case FieldDescriptor::TYPE_SINT32:
- stub_h_->Print(
- setter,
- "PERFETTO_PB_FIELD($class$, ZIGZAG, $ctype$, $name$, $id$);\n");
+ stub_h_->Print(setter, "$class$, ZIGZAG, $ctype$, $name$, $id$");
break;
case FieldDescriptor::TYPE_SFIXED32:
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_FLOAT:
- stub_h_->Print(
- setter,
- "PERFETTO_PB_FIELD($class$, FIXED32, $ctype$, $name$, $id$);\n");
+ stub_h_->Print(setter, "$class$, FIXED32, $ctype$, $name$, $id$");
break;
case FieldDescriptor::TYPE_SFIXED64:
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_DOUBLE:
- stub_h_->Print(
- setter,
- "PERFETTO_PB_FIELD($class$, FIXED64, $ctype$, $name$, $id$);\n");
+ stub_h_->Print(setter, "$class$, FIXED64, $ctype$, $name$, $id$");
break;
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
@@ -514,6 +523,23 @@
}
}
+ void GenerateSimpleFieldDescriptor(const std::string& message_cpp_type,
+ const FieldDescriptor* field) {
+ stub_h_->Print("PERFETTO_PB_FIELD(");
+ GenerateSimpleFieldDescriptorArgs(message_cpp_type, field);
+ stub_h_->Print(");\n");
+ }
+
+ void GenerateSimpleFieldDescriptorForExtension(
+ const std::string& field_cpp_prefix,
+ const std::string& message_cpp_type,
+ const FieldDescriptor* field) {
+ stub_h_->Print("PERFETTO_PB_EXTENSION_FIELD($prefix$, ", "prefix",
+ field_cpp_prefix);
+ GenerateSimpleFieldDescriptorArgs(message_cpp_type, field);
+ stub_h_->Print(");\n");
+ }
+
void GenerateNestedMessageFieldDescriptor(const std::string& message_cpp_type,
const FieldDescriptor* field) {
std::string inner_class = GetCppClassName(field->message_type());
@@ -523,6 +549,19 @@
"name", field->lowercase_name(), "inner_class", inner_class);
}
+ void GenerateNestedMessageFieldDescriptorForExtension(
+ const std::string& field_cpp_prefix,
+ const std::string& message_cpp_type,
+ const FieldDescriptor* field) {
+ std::string inner_class = GetCppClassName(field->message_type());
+ stub_h_->Print(
+ "PERFETTO_PB_EXTENSION_FIELD($prefix$, $class$, MSG, $inner_class$, "
+ "$name$, $id$);\n",
+ "prefix", field_cpp_prefix, "class", message_cpp_type, "id",
+ std::to_string(field->number()), "name", field->lowercase_name(),
+ "inner_class", inner_class);
+ }
+
void GenerateMessageDescriptor(const Descriptor* message) {
stub_h_->Print("PERFETTO_PB_MSG($name$);\n", "name",
GetCppClassName(message));
@@ -546,6 +585,60 @@
}
}
+ void GenerateExtensionFieldDescriptor(const std::string& field_cpp_prefix,
+ const std::string& message_cpp_type,
+ const FieldDescriptor* field) {
+ // GenerateFieldMetadata(message_cpp_type, field);
+ if (field->is_packed()) {
+ GeneratePackedRepeatedFieldDescriptorForExtension(
+ field_cpp_prefix, message_cpp_type, field);
+ } else if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+ GenerateSimpleFieldDescriptorForExtension(field_cpp_prefix,
+ message_cpp_type, field);
+ } else {
+ GenerateNestedMessageFieldDescriptorForExtension(field_cpp_prefix,
+ message_cpp_type, field);
+ }
+ }
+
+ // Generate extension class for a group of FieldDescriptor instances
+ // representing one "extend" block in proto definition. For example:
+ //
+ // message SpecificExtension {
+ // extend GeneralThing {
+ // optional Fizz fizz = 101;
+ // optional Buzz buzz = 102;
+ // }
+ // }
+ //
+ // This is going to be passed as a vector of two elements, "fizz" and
+ // "buzz". Wrapping message is used to provide a name for generated
+ // extension class.
+ //
+ // In the example above, generated code is going to look like:
+ //
+ // class SpecificExtension : public GeneralThing {
+ // Fizz* set_fizz();
+ // Buzz* set_buzz();
+ // }
+ void GenerateExtension(
+ const std::string& extension_name,
+ const std::vector<const FieldDescriptor*>& descriptors) {
+ // Use an arbitrary descriptor in order to get generic information not
+ // specific to any of them.
+ const FieldDescriptor* descriptor = descriptors[0];
+ const Descriptor* base_message = descriptor->containing_type();
+
+ for (const FieldDescriptor* field : descriptors) {
+ if (field->containing_type() != base_message) {
+ Abort("one wrapper should extend only one message");
+ return;
+ }
+ GenerateExtensionFieldDescriptor(extension_name,
+ GetCppClassName(base_message), field);
+ }
+ }
+
void GenerateEpilogue() {
stub_h_->Print("#endif // $guard$\n", "guard", GenerateGuard());
}
diff --git a/src/shared_lib/test/api_integrationtest.cc b/src/shared_lib/test/api_integrationtest.cc
index 975f001..802d54a 100644
--- a/src/shared_lib/test/api_integrationtest.cc
+++ b/src/shared_lib/test/api_integrationtest.cc
@@ -40,6 +40,7 @@
#include "test/gtest_and_gmock.h"
#include "src/shared_lib/reset_for_testing.h"
+#include "src/shared_lib/test/protos/extensions.pzc.h"
#include "src/shared_lib/test/protos/test_messages.pzc.h"
#include "src/shared_lib/test/utils.h"
@@ -396,6 +397,42 @@
VarIntField(1000)))))));
}
+TEST_F(SharedLibProtozeroSerializationTest, Extensions) {
+ struct protozero_test_protos_RealFakeEvent base;
+ PerfettoPbMsgInit(&base.msg, &writer);
+
+ {
+ struct protozero_test_protos_SystemA msg_a;
+ protozero_test_protos_BrowserExtension_begin_extension_a(&base, &msg_a);
+ protozero_test_protos_SystemA_set_cstr_string_a(&msg_a, "str_a");
+ protozero_test_protos_BrowserExtension_end_extension_a(&base, &msg_a);
+ }
+ {
+ struct protozero_test_protos_SystemB msg_b;
+ protozero_test_protos_BrowserExtension_begin_extension_b(&base, &msg_b);
+ protozero_test_protos_SystemB_set_cstr_string_b(&msg_b, "str_b");
+ protozero_test_protos_BrowserExtension_end_extension_b(&base, &msg_b);
+ }
+
+ protozero_test_protos_RealFakeEvent_set_cstr_base_string(&base, "str");
+
+ EXPECT_THAT(
+ FieldView(GetData()),
+ ElementsAre(
+ PbField(
+ protozero_test_protos_BrowserExtension_extension_a_field_number,
+ MsgField(ElementsAre(
+ PbField(protozero_test_protos_SystemA_string_a_field_number,
+ StringField("str_a"))))),
+ PbField(
+ protozero_test_protos_BrowserExtension_extension_b_field_number,
+ MsgField(ElementsAre(
+ PbField(protozero_test_protos_SystemB_string_b_field_number,
+ StringField("str_b"))))),
+ PbField(protozero_test_protos_RealFakeEvent_base_string_field_number,
+ StringField("str"))));
+}
+
TEST_F(SharedLibProtozeroSerializationTest, PackedRepeatedMsgVarInt) {
struct protozero_test_protos_PackedRepeatedFields msg;
PerfettoPbMsgInit(&msg.msg, &writer);
diff --git a/src/shared_lib/test/protos/BUILD.gn b/src/shared_lib/test/protos/BUILD.gn
index 434f4a5..21fdeaf 100644
--- a/src/shared_lib/test/protos/BUILD.gn
+++ b/src/shared_lib/test/protos/BUILD.gn
@@ -15,6 +15,7 @@
source_set("protos") {
testonly = true
sources = [
+ "extensions.pzc.h",
"library.pzc.h",
"library_internals/galaxies.pzc.h",
"test_messages.pzc.h",
diff --git a/src/shared_lib/test/protos/extensions.pzc.h b/src/shared_lib/test/protos/extensions.pzc.h
new file mode 100644
index 0000000..996a11a
--- /dev/null
+++ b/src/shared_lib/test/protos/extensions.pzc.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Autogenerated by the ProtoZero C compiler plugin.
+// Invoked by tools/gen_c_protos
+// DO NOT EDIT.
+#ifndef SRC_SHARED_LIB_TEST_PROTOS_EXTENSIONS_PZC_H_
+#define SRC_SHARED_LIB_TEST_PROTOS_EXTENSIONS_PZC_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "perfetto/public/pb_macros.h"
+
+PERFETTO_PB_MSG(protozero_test_protos_SystemB);
+PERFETTO_PB_FIELD(protozero_test_protos_SystemB, VARINT, uint32_t, int_b, 1);
+PERFETTO_PB_FIELD(protozero_test_protos_SystemB,
+ STRING,
+ const char*,
+ string_b,
+ 2);
+
+PERFETTO_PB_MSG(protozero_test_protos_SystemA);
+PERFETTO_PB_FIELD(protozero_test_protos_SystemA, VARINT, uint32_t, int_a, 1);
+PERFETTO_PB_FIELD(protozero_test_protos_SystemA,
+ STRING,
+ const char*,
+ string_a,
+ 2);
+
+PERFETTO_PB_MSG(protozero_test_protos_RealFakeEvent);
+PERFETTO_PB_FIELD(protozero_test_protos_RealFakeEvent,
+ VARINT,
+ uint32_t,
+ base_int,
+ 1);
+PERFETTO_PB_FIELD(protozero_test_protos_RealFakeEvent,
+ STRING,
+ const char*,
+ base_string,
+ 2);
+
+PERFETTO_PB_EXTENSION_FIELD(protozero_test_protos_BrowserExtension,
+ protozero_test_protos_RealFakeEvent,
+ MSG,
+ protozero_test_protos_SystemA,
+ extension_a,
+ 10);
+PERFETTO_PB_EXTENSION_FIELD(protozero_test_protos_BrowserExtension,
+ protozero_test_protos_RealFakeEvent,
+ MSG,
+ protozero_test_protos_SystemB,
+ extension_b,
+ 11);
+#endif // SRC_SHARED_LIB_TEST_PROTOS_EXTENSIONS_PZC_H_
diff --git a/tools/gen_c_protos b/tools/gen_c_protos
index cefc5e3..c62a48f 100755
--- a/tools/gen_c_protos
+++ b/tools/gen_c_protos
@@ -48,6 +48,7 @@
},
{
'files': [
+ 'src/protozero/test/example_proto/extensions.proto',
'src/protozero/test/example_proto/library.proto',
'src/protozero/test/example_proto/library_internals/galaxies.proto',
'src/protozero/test/example_proto/other_package/test_messages.proto',