Emit size_union only once, with guards (#692)
Previously there could be double definition errors at compile time.
diff --git a/generator/nanopb_generator.py b/generator/nanopb_generator.py
index 3efdd71..d27b732 100755
--- a/generator/nanopb_generator.py
+++ b/generator/nanopb_generator.py
@@ -1804,14 +1804,29 @@
# If we require a symbol from another file, put a preprocessor if statement
# around it to prevent compilation errors if the symbol is not actually available.
local_defines = [identifier for identifier, msize in messagesizes if msize is not None]
+
+ # emit size_unions, if any
+ oneof_sizes = []
+ for msg in self.messages:
+ for f in msg.fields:
+ if isinstance(f, OneOf):
+ msize = f.encoded_size(self.dependencies)
+ if msize is not None:
+ oneof_sizes.append(msize)
+ for msize in oneof_sizes:
+ guard = msize.get_cpp_guard(local_defines)
+ if guard:
+ yield guard
+ yield msize.get_declarations()
+ if guard:
+ yield '#endif\n'
+
guards = {}
for identifier, msize in messagesizes:
if msize is not None:
cpp_guard = msize.get_cpp_guard(local_defines)
if cpp_guard not in guards:
guards[cpp_guard] = set()
- for decl in msize.get_declarations().splitlines():
- guards[cpp_guard].add(decl)
guards[cpp_guard].add('#define %-40s %s' % (identifier, msize))
else:
yield '/* %s depends on runtime parameters */\n' % identifier
diff --git a/tests/regression/issue_692/SConscript b/tests/regression/issue_692/SConscript
new file mode 100644
index 0000000..11f07ca
--- /dev/null
+++ b/tests/regression/issue_692/SConscript
@@ -0,0 +1,9 @@
+# Regression test for #693:
+# Duplicate declarations of size_unions with repeated fields inside a oneof
+
+Import("env")
+
+env.NanopbProto("other.proto")
+env.NanopbProto(["oneof.proto", "other.proto"])
+env.Object("oneof.pb.c")
+env.Object("test.c")
diff --git a/tests/regression/issue_692/oneof.proto b/tests/regression/issue_692/oneof.proto
new file mode 100644
index 0000000..7f7baaf
--- /dev/null
+++ b/tests/regression/issue_692/oneof.proto
@@ -0,0 +1,19 @@
+syntax = "proto3";
+
+import "other.proto";
+
+message FirstOneof {}
+
+message Bar {
+ oneof content {
+ FirstOneof first = 1;
+ SecondOneof second = 2; // unknown size if no options are considered
+ }
+}
+
+message Foo {
+ AnotherList foo = 1; // again, unknown size
+ Bar bar = 2; // no duplicate size_union shall be generated anymore
+}
+
+
diff --git a/tests/regression/issue_692/other.proto b/tests/regression/issue_692/other.proto
new file mode 100644
index 0000000..733103c
--- /dev/null
+++ b/tests/regression/issue_692/other.proto
@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+message SecondOneof {
+ repeated int32 foo = 1;
+}
+
+message AnotherList {
+ repeated int32 bar = 1;
+}
\ No newline at end of file
diff --git a/tests/regression/issue_692/test.c b/tests/regression/issue_692/test.c
new file mode 100644
index 0000000..95281b7
--- /dev/null
+++ b/tests/regression/issue_692/test.c
@@ -0,0 +1,7 @@
+/* This fakes the situation where other.proto was not found at generation time,
+ so size_union declarations are generated. */
+
+#define SecondOneof_size 88
+#define AnotherList_size 88
+
+#include "oneof.pb.h"