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"