Support multiple fbs files & no root types in static flatbuffers

In order to improve parity with the existing flatbuffer bazel rules, add
support for:
* Multiple srcs files.
* Generating code for files where no root_type has been specified.

Change-Id: I77d909978fd0bf5125b9e789162c7b629d0fe00d
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/events/BUILD b/aos/events/BUILD
index de380dc..4d76023 100644
--- a/aos/events/BUILD
+++ b/aos/events/BUILD
@@ -10,7 +10,7 @@
 
 static_flatbuffer(
     name = "test_message_fbs",
-    src = "test_message.fbs",
+    srcs = ["test_message.fbs"],
 )
 
 cc_static_flatbuffer(
@@ -35,7 +35,7 @@
 
 static_flatbuffer(
     name = "ping_fbs",
-    src = "ping.fbs",
+    srcs = ["ping.fbs"],
 )
 
 flatbuffer_ts_library(
@@ -64,7 +64,7 @@
 
 static_flatbuffer(
     name = "pong_fbs",
-    src = "pong.fbs",
+    srcs = ["pong.fbs"],
 )
 
 cc_library(
diff --git a/aos/flatbuffers/BUILD b/aos/flatbuffers/BUILD
index 51ba041..08d548f 100644
--- a/aos/flatbuffers/BUILD
+++ b/aos/flatbuffers/BUILD
@@ -155,7 +155,7 @@
 
 static_flatbuffer(
     name = "test_fbs",
-    src = "test.fbs",
+    srcs = ["test.fbs"],
     deps = ["//aos/flatbuffers/test_dir:include_fbs"],
 )
 
diff --git a/aos/flatbuffers/generate.bzl b/aos/flatbuffers/generate.bzl
index 8fef0ba..288b281 100644
--- a/aos/flatbuffers/generate.bzl
+++ b/aos/flatbuffers/generate.bzl
@@ -1,7 +1,7 @@
 load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_cc_library")
 load("@aspect_bazel_lib//lib:run_binary.bzl", "run_binary")
 
-def static_flatbuffer(name, src, visibility = None, deps = [], **kwargs):
+def static_flatbuffer(name, visibility = None, deps = [], srcs = [], **kwargs):
     """Generates the code for the static C++ flatbuffer API for the specified fbs file.
 
     Generates a cc_library of name name that can be depended on by C++ code and other
@@ -13,14 +13,15 @@
 
     Args:
       name: Target name.
-      src: .fbs file to generated code for.
+      srcs: List of fbs files to codegen.
       visibility: Desired rule visibility.
       deps: List of static_flatbuffer dependencies of this rule.
     """
     fbs_suffix = "_fbs"
+
     flatbuffer_cc_library(
         name = name + fbs_suffix,
-        srcs = [src],
+        srcs = srcs,
         deps = [dep + fbs_suffix for dep in deps],
         gen_reflections = True,
         visibility = visibility,
@@ -30,19 +31,23 @@
     # Until we make this a proper rule with providers or the such, we just manage headers
     # by having a strong convention where the header will be a function of the fbs name
     # rather than a function of the rule name.
-    header_name = src.removesuffix(".fbs") + "_static.h"
+    header_names = [file.removesuffix(".fbs") + "_static.h" for file in srcs]
     reflection_out = name + fbs_suffix + "_reflection_out"
 
     run_binary(
         name = name + "_gen",
         tool = "@org_frc971//aos/flatbuffers:generate_wrapper",
         srcs = [reflection_out],
-        outs = [header_name],
-        args = ["$(execpath %s)" % (reflection_out,), "$(execpath %s)" % (header_name,)],
+        outs = header_names,
+        env = {
+            "BFBS_FILES": "$(execpaths %s)" % (reflection_out,),
+            "BASE_FILES": " ".join(srcs),
+            "OUT_FILES": " ".join(["$(execpath %s)" % (name,) for name in header_names]),
+        },
     )
     native.cc_library(
         name = name,
-        hdrs = [header_name],
+        hdrs = header_names,
         deps = ["@org_frc971//aos/flatbuffers:static_table", "@org_frc971//aos/flatbuffers:static_vector", name + fbs_suffix] + deps,
         visibility = visibility,
     )
diff --git a/aos/flatbuffers/generate.cc b/aos/flatbuffers/generate.cc
index 2e081f3..030de35 100644
--- a/aos/flatbuffers/generate.cc
+++ b/aos/flatbuffers/generate.cc
@@ -8,13 +8,17 @@
 
 DEFINE_string(reflection_bfbs, "", "Path to the .bfbs reflection file.");
 DEFINE_string(output_file, "", "Path to the output header to write.");
+DEFINE_string(base_file_name, "",
+              "Name of the base file to generate code for as used by the "
+              "reflection::Schema object.");
 
 namespace aos::fbs {
 int Main() {
   aos::FlatbufferVector<reflection::Schema> schema =
       aos::FileToFlatbuffer<reflection::Schema>(FLAGS_reflection_bfbs);
   aos::util::WriteStringToFileOrDie(
-      FLAGS_output_file, GenerateCodeForRootTableFile(&schema.message()));
+      FLAGS_output_file,
+      GenerateCodeForRootTableFile(&schema.message(), FLAGS_base_file_name));
   return EXIT_SUCCESS;
 }
 }  // namespace aos::fbs
diff --git a/aos/flatbuffers/generate.sh b/aos/flatbuffers/generate.sh
index aecab26..09bb4dc 100755
--- a/aos/flatbuffers/generate.sh
+++ b/aos/flatbuffers/generate.sh
@@ -15,8 +15,16 @@
   { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
 # --- end runfiles.bash initialization v2 ---
 
-BFBS_FILE=$1
-OUT_FILE=$2
+INPUTS=($BFBS_FILES)
+SCHEMA_FILES=($BASE_FILES)
+OUTPUTS=($OUT_FILES)
 
-$(rlocation org_frc971/aos/flatbuffers/generate) --reflection_bfbs "${BFBS_FILE}" --output_file "${OUT_FILE}"
-$(rlocation llvm_k8/bin/clang-format) --style=file:"$(rlocation org_frc971/.clang-format)" -i "${OUT_FILE}"
+LEN=${#INPUTS[@]}
+
+for ((i = 0; i < $LEN; i++)); do
+  $(rlocation org_frc971/aos/flatbuffers/generate) \
+    --reflection_bfbs "${INPUTS[i]}" \
+    --output_file "${OUTPUTS[i]}" \
+    --base_file_name "$(basename ${SCHEMA_FILES[i]})"
+  $(rlocation llvm_k8/bin/clang-format) --style=file:"$(rlocation org_frc971/.clang-format)" -i "${OUTPUTS[i]}"
+done
diff --git a/aos/flatbuffers/static_flatbuffers.cc b/aos/flatbuffers/static_flatbuffers.cc
index 7b42ef6..019afda 100644
--- a/aos/flatbuffers/static_flatbuffers.cc
+++ b/aos/flatbuffers/static_flatbuffers.cc
@@ -807,12 +807,16 @@
 }
 }  // namespace
 
-std::string GenerateCodeForRootTableFile(const reflection::Schema *schema) {
-  const reflection::Object *root_object = CHECK_NOTNULL(GetObject(schema, -1));
+std::string GenerateCodeForRootTableFile(const reflection::Schema *schema,
+                                         std::string_view file_hint) {
+  const reflection::Object *root_object = GetObject(schema, -1);
   const std::string_view root_file =
-      root_object->declaration_file()->string_view();
-  std::vector<GeneratedObject> objects = {
-      GenerateCodeForObject(schema, root_object)};
+      (root_object == nullptr) ? file_hint
+                               : root_object->declaration_file()->string_view();
+  std::vector<GeneratedObject> objects;
+  if (root_object != nullptr) {
+    objects.push_back(GenerateCodeForObject(schema, root_object));
+  }
   for (const reflection::Object *object : *schema->objects()) {
     if (object->is_struct()) {
       continue;
diff --git a/aos/flatbuffers/static_flatbuffers.h b/aos/flatbuffers/static_flatbuffers.h
index 47d79e6..6a5f800 100644
--- a/aos/flatbuffers/static_flatbuffers.h
+++ b/aos/flatbuffers/static_flatbuffers.h
@@ -31,7 +31,11 @@
 
 // Produces generated code for all flatbuffer tables in the file corresponding
 // to the provided Schema object.
-std::string GenerateCodeForRootTableFile(const reflection::Schema *schema);
+// file_hint is the name of the file that we should be generating code for; this
+// is used if there is no root table specified for the fbs file so that we can
+// infer which objects to generate code for.
+std::string GenerateCodeForRootTableFile(const reflection::Schema *schema,
+                                         std::string_view file_hint);
 
 // Helper functions to generate the code for individual objects; primarily
 // exposed for testing.
diff --git a/aos/flatbuffers/test_dir/BUILD b/aos/flatbuffers/test_dir/BUILD
index 7015cc2..76f5fb4 100644
--- a/aos/flatbuffers/test_dir/BUILD
+++ b/aos/flatbuffers/test_dir/BUILD
@@ -2,13 +2,13 @@
 
 static_flatbuffer(
     name = "include_fbs",
-    src = "include.fbs",
+    srcs = ["include.fbs"],
     visibility = ["//visibility:public"],
 )
 
 static_flatbuffer(
     name = "type_coverage_fbs",
-    src = "type_coverage.fbs",
+    srcs = ["type_coverage.fbs"],
     visibility = ["//visibility:public"],
 )
 
diff --git a/aos/flatbuffers/test_dir/include.fbs b/aos/flatbuffers/test_dir/include.fbs
index 533db2b..df34259 100644
--- a/aos/flatbuffers/test_dir/include.fbs
+++ b/aos/flatbuffers/test_dir/include.fbs
@@ -8,5 +8,3 @@
  foo:TestEnum (id: 0);
 }
 
-root_type IncludedTable;
-