mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
The Google C++ protobuf implementation has issues with dynamic linkage across DLL boundaries because it uses global variables. It also has a compile-time dependency because the protoc version must exactly match the libprotobuf version. Using nanopb with a customized generator fixes both of these issues. Co-authored-by: Gold856 <117957790+Gold856@users.noreply.github.com>
171 lines
6.5 KiB
Diff
171 lines
6.5 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Thad House <thadhouse1@gmail.com>
|
|
Date: Sat, 2 Nov 2024 20:25:45 -0700
|
|
Subject: [PATCH 4/4] Generate as cpp and add wpilib requirements
|
|
|
|
---
|
|
generator/nanopb_generator.py | 43 +++++++++++++++++++++++++++--------
|
|
pb.h | 23 +++++++++++++++----
|
|
2 files changed, 52 insertions(+), 14 deletions(-)
|
|
|
|
diff --git a/generator/nanopb_generator.py b/generator/nanopb_generator.py
|
|
index 3b59ba59e6fc997350b1368a2faebc051cd6176a..01fc349538aec0c67ec3fd9bfaf3a356adc08e96 100755
|
|
--- a/generator/nanopb_generator.py
|
|
+++ b/generator/nanopb_generator.py
|
|
@@ -1406,6 +1406,12 @@ class Message(ProtoElement):
|
|
|
|
result += '\n'
|
|
|
|
+ result += ' static const pb_msgdesc_t* msg_descriptor(void) noexcept;\n'
|
|
+ result += ' static std::string_view msg_name(void) noexcept;\n'
|
|
+ result += ' static pb_filedesc_t file_descriptor(void) noexcept;\n'
|
|
+
|
|
+ result += '\n'
|
|
+
|
|
if not self.fields:
|
|
# Empty structs are not allowed in C standard.
|
|
# Therefore add a dummy field if an empty message occurs.
|
|
@@ -2046,6 +2052,8 @@ class ProtoFile:
|
|
# no %s specified - use whatever was passed in as options.libformat
|
|
yield options.libformat
|
|
yield '\n'
|
|
+ yield "#include <span>\n"
|
|
+ yield "#include <string_view>\n"
|
|
|
|
for incfile in self.file_options.include:
|
|
# allow including system headers
|
|
@@ -2126,16 +2134,6 @@ class ProtoFile:
|
|
yield '/* Struct field encoding specification for nanopb */\n'
|
|
for msg in self.messages:
|
|
yield msg.fields_declaration(self.dependencies) + '\n'
|
|
- for msg in self.messages:
|
|
- yield 'extern const pb_msgdesc_t %s_msg;\n' % Globals.naming_style.type_name(msg.name)
|
|
- yield '\n'
|
|
-
|
|
- yield '/* Defines for backwards compatibility with code written before nanopb-0.4.0 */\n'
|
|
- for msg in self.messages:
|
|
- yield '#define %s &%s_msg\n' % (
|
|
- Globals.naming_style.define_name('%s_fields' % msg.name),
|
|
- Globals.naming_style.type_name(msg.name))
|
|
- yield '\n'
|
|
|
|
yield '/* Maximum encoded size of messages (where known) */\n'
|
|
messagesizes = []
|
|
@@ -2259,6 +2257,24 @@ class ProtoFile:
|
|
yield '#endif\n'
|
|
yield '\n'
|
|
|
|
+ yield "#include <span>\n"
|
|
+ yield "#include <string_view>\n"
|
|
+
|
|
+ yield "static const uint8_t file_descriptor[] {\n"
|
|
+
|
|
+ line_count = 0
|
|
+
|
|
+ for b in self.fdesc.SerializeToString():
|
|
+ yield '0x' + format(b, '02x') + ','
|
|
+ line_count += 1
|
|
+ if line_count == 10:
|
|
+ yield '\n'
|
|
+ line_count = 0
|
|
+ yield '\n'
|
|
+
|
|
+ yield "};\n"
|
|
+ yield 'static const char file_name[] = "%s";\n' % self.fdesc.name
|
|
+
|
|
# Check if any messages exceed the 64 kB limit of 16-bit pb_size_t
|
|
exceeds_64kB = []
|
|
for msg in self.messages:
|
|
@@ -2275,6 +2291,13 @@ class ProtoFile:
|
|
|
|
# Generate the message field definitions (PB_BIND() call)
|
|
for msg in self.messages:
|
|
+ if self.fdesc.package:
|
|
+ full_name = self.fdesc.package + '.' + msg.desc.name
|
|
+ else:
|
|
+ full_name = msg.desc.name
|
|
+ yield 'static const char %s_name[] = "%s";\n' % (msg.name, full_name)
|
|
+ yield 'std::string_view %s::msg_name(void) noexcept { return %s_name; }\n' % (msg.name, msg.name)
|
|
+ yield 'pb_filedesc_t %s::file_descriptor(void) noexcept { return {::file_name, ::file_descriptor}; }\n' % msg.name
|
|
yield msg.fields_definition(self.dependencies) + '\n\n'
|
|
|
|
# Generate pb_extension_type_t definitions if extensions are used in proto file
|
|
diff --git a/pb.h b/pb.h
|
|
index a7fd771f05d7182e73ab346b46294c6fc5ac44c7..832364a60900cbcb9134b6e122576436a6df6a00 100644
|
|
--- a/pb.h
|
|
+++ b/pb.h
|
|
@@ -89,6 +89,9 @@
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
+#include <span>
|
|
+#include <string_view>
|
|
+
|
|
#ifdef PB_ENABLE_MALLOC
|
|
#include <stdlib.h>
|
|
#endif
|
|
@@ -315,6 +318,12 @@ typedef struct pb_istream_s pb_istream_t;
|
|
typedef struct pb_ostream_s pb_ostream_t;
|
|
typedef struct pb_field_iter_s pb_field_iter_t;
|
|
|
|
+typedef struct pb_filedesc_s pb_filedesc_t;
|
|
+struct pb_filedesc_s {
|
|
+ std::string_view file_name;
|
|
+ std::span<const uint8_t> file_descriptor;
|
|
+};
|
|
+
|
|
/* This structure is used in auto-generated constants
|
|
* to specify struct fields.
|
|
*/
|
|
@@ -329,6 +338,9 @@ struct pb_msgdesc_s {
|
|
pb_size_t field_count;
|
|
pb_size_t required_field_count;
|
|
pb_size_t largest_tag;
|
|
+
|
|
+ pb_filedesc_t file_descriptor;
|
|
+ std::string_view proto_name;
|
|
};
|
|
|
|
/* Iterator for message descriptor */
|
|
@@ -501,17 +513,17 @@ struct pb_extension_s {
|
|
|
|
/* Binding of a message field set into a specific structure */
|
|
#define PB_BIND(msgname, structname, width) \
|
|
- const uint32_t structname ## _field_info[] PB_PROGMEM = \
|
|
+ static const uint32_t structname ## _field_info[] PB_PROGMEM = \
|
|
{ \
|
|
msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ ## width, structname) \
|
|
0 \
|
|
}; \
|
|
- const pb_msgdesc_t* const structname ## _submsg_info[] = \
|
|
+ static const pb_msgdesc_t* const structname ## _submsg_info[] = \
|
|
{ \
|
|
msgname ## _FIELDLIST(PB_GEN_SUBMSG_INFO, structname) \
|
|
NULL \
|
|
}; \
|
|
- const pb_msgdesc_t structname ## _msg = \
|
|
+ static const pb_msgdesc_t structname ## _msg = \
|
|
{ \
|
|
structname ## _field_info, \
|
|
structname ## _submsg_info, \
|
|
@@ -520,7 +532,10 @@ struct pb_extension_s {
|
|
0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \
|
|
0 msgname ## _FIELDLIST(PB_GEN_REQ_FIELD_COUNT, structname), \
|
|
0 msgname ## _FIELDLIST(PB_GEN_LARGEST_TAG, structname), \
|
|
+ structname::file_descriptor(), \
|
|
+ structname::msg_name(), \
|
|
}; \
|
|
+ const pb_msgdesc_t* structname::msg_descriptor(void) noexcept { return &(structname ## _msg); } \
|
|
msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ASSERT_ ## width, structname)
|
|
|
|
#define PB_GEN_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) +1
|
|
@@ -726,7 +741,7 @@ struct pb_extension_s {
|
|
#define PB_SI_PB_LTYPE_UINT64(t)
|
|
#define PB_SI_PB_LTYPE_EXTENSION(t)
|
|
#define PB_SI_PB_LTYPE_FIXED_LENGTH_BYTES(t)
|
|
-#define PB_SUBMSG_DESCRIPTOR(t) &(t ## _msg),
|
|
+#define PB_SUBMSG_DESCRIPTOR(t) (t::msg_descriptor()),
|
|
|
|
/* The field descriptors use a variable width format, with width of either
|
|
* 1, 2, 4 or 8 of 32-bit words. The two lowest bytes of the first byte always
|