1# Description:
2#   BUILD rules for generating flatbuffer files in various languages.
3
4flatc_path = "@com_github_google_flatbuffers//:flatc"
5
6DEFAULT_INCLUDE_PATHS = [
7    "./",
8    "$(GENDIR)",
9    "$(BINDIR)",
10]
11
12DEFAULT_FLATC_ARGS = [
13    "--gen-object-api",
14    "--gen-compare",
15    "--no-includes",
16    "--gen-mutable",
17    "--reflect-names",
18    "--cpp-ptr-type flatbuffers::unique_ptr",
19]
20
21def flatbuffer_library_public(
22        name,
23        srcs,
24        outs,
25        language_flag,
26        out_prefix = "",
27        includes = [],
28        include_paths = DEFAULT_INCLUDE_PATHS,
29        flatc_args = DEFAULT_FLATC_ARGS,
30        reflection_name = "",
31        reflection_visiblity = None,
32        output_to_bindir = False):
33    """Generates code files for reading/writing the given flatbuffers in the requested language using the public compiler.
34
35    Args:
36      name: Rule name.
37      srcs: Source .fbs files. Sent in order to the compiler.
38      outs: Output files from flatc.
39      language_flag: Target language flag. One of [-c, -j, -js].
40      out_prefix: Prepend this path to the front of all generated files except on
41          single source targets. Usually is a directory name.
42      includes: Optional, list of filegroups of schemas that the srcs depend on.
43      include_paths: Optional, list of paths the includes files can be found in.
44      flatc_args: Optional, list of additional arguments to pass to flatc.
45      reflection_name: Optional, if set this will generate the flatbuffer
46        reflection binaries for the schemas.
47      reflection_visiblity: The visibility of the generated reflection Fileset.
48      output_to_bindir: Passed to genrule for output to bin directory.
49    Outs:
50      filegroup(name): all generated source files.
51      Fileset([reflection_name]): (Optional) all generated reflection binaries.
52    """
53    include_paths_cmd = ["-I %s" % (s) for s in include_paths]
54
55    # '$(@D)' when given a single source target will give the appropriate
56    # directory. Appending 'out_prefix' is only necessary when given a build
57    # target with multiple sources.
58    output_directory = (
59        ("-o $(@D)/%s" % (out_prefix)) if len(srcs) > 1 else ("-o $(@D)")
60    )
61    genrule_cmd = " ".join([
62        "SRCS=($(SRCS));",
63        "for f in $${SRCS[@]:0:%s}; do" % len(srcs),
64        "$(location %s)" % (flatc_path),
65        " ".join(include_paths_cmd),
66        " ".join(flatc_args),
67        language_flag,
68        output_directory,
69        "$$f;",
70        "done",
71    ])
72    native.genrule(
73        name = name,
74        srcs = srcs + includes,
75        outs = outs,
76        output_to_bindir = output_to_bindir,
77        tools = [flatc_path],
78        cmd = genrule_cmd,
79        message = "Generating flatbuffer files for %s:" % (name),
80    )
81    if reflection_name:
82        reflection_genrule_cmd = " ".join([
83            "SRCS=($(SRCS));",
84            "for f in $${SRCS[@]:0:%s}; do" % len(srcs),
85            "$(location %s)" % (flatc_path),
86            "-b --schema",
87            " ".join(flatc_args),
88            " ".join(include_paths_cmd),
89            language_flag,
90            output_directory,
91            "$$f;",
92            "done",
93        ])
94        reflection_outs = [
95            (out_prefix + "%s.bfbs") % (s.replace(".fbs", "").split("/")[-1])
96            for s in srcs
97        ]
98        native.genrule(
99            name = "%s_srcs" % reflection_name,
100            srcs = srcs + includes,
101            outs = reflection_outs,
102            output_to_bindir = output_to_bindir,
103            tools = [flatc_path],
104            cmd = reflection_genrule_cmd,
105            message = "Generating flatbuffer reflection binary for %s:" % (name),
106        )
107        native.Fileset(
108            name = reflection_name,
109            out = "%s_out" % reflection_name,
110            entries = [
111                native.FilesetEntry(files = reflection_outs),
112            ],
113            visibility = reflection_visiblity,
114        )
115
116def flatbuffer_cc_library(
117        name,
118        srcs,
119        srcs_filegroup_name = "",
120        out_prefix = "",
121        includes = [],
122        include_paths = DEFAULT_INCLUDE_PATHS,
123        flatc_args = DEFAULT_FLATC_ARGS,
124        visibility = None,
125        srcs_filegroup_visibility = None,
126        gen_reflections = False):
127    '''A cc_library with the generated reader/writers for the given flatbuffer definitions.
128
129    Args:
130      name: Rule name.
131      srcs: Source .fbs files. Sent in order to the compiler.
132      srcs_filegroup_name: Name of the output filegroup that holds srcs. Pass this
133          filegroup into the `includes` parameter of any other
134          flatbuffer_cc_library that depends on this one's schemas.
135      out_prefix: Prepend this path to the front of all generated files. Usually
136          is a directory name.
137      includes: Optional, list of filegroups of schemas that the srcs depend on.
138          ** SEE REMARKS BELOW **
139      include_paths: Optional, list of paths the includes files can be found in.
140      flatc_args: Optional list of additional arguments to pass to flatc
141          (e.g. --gen-mutable).
142      visibility: The visibility of the generated cc_library. By default, use the
143          default visibility of the project.
144      srcs_filegroup_visibility: The visibility of the generated srcs filegroup.
145          By default, use the value of the visibility parameter above.
146      gen_reflections: Optional, if true this will generate the flatbuffer
147        reflection binaries for the schemas.
148    Outs:
149      filegroup([name]_srcs): all generated .h files.
150      filegroup(srcs_filegroup_name if specified, or [name]_includes if not):
151          Other flatbuffer_cc_library's can pass this in for their `includes`
152          parameter, if they depend on the schemas in this library.
153      Fileset([name]_reflection): (Optional) all generated reflection binaries.
154      cc_library([name]): library with sources and flatbuffers deps.
155
156    Remarks:
157      ** Because the genrule used to call flatc does not have any trivial way of
158        computing the output list of files transitively generated by includes and
159        --gen-includes (the default) being defined for flatc, the --gen-includes
160        flag will not work as expected. The way around this is to add a dependency
161        to the flatbuffer_cc_library defined alongside the flatc included Fileset.
162        For example you might define:
163
164        flatbuffer_cc_library(
165            name = "my_fbs",
166            srcs = [ "schemas/foo.fbs" ],
167            includes = [ "//third_party/bazz:bazz_fbs_includes" ],
168        )
169
170        In which foo.fbs includes a few files from the Fileset defined at
171        //third_party/bazz:bazz_fbs_includes. When compiling the library that
172        includes foo_generated.h, and therefore has my_fbs as a dependency, it
173        will fail to find any of the bazz *_generated.h files unless you also
174        add bazz's flatbuffer_cc_library to your own dependency list, e.g.:
175
176        cc_library(
177            name = "my_lib",
178            deps = [
179                ":my_fbs",
180                "//third_party/bazz:bazz_fbs"
181            ],
182        )
183
184        Happy dependent Flatbuffering!
185    '''
186    output_headers = [
187        (out_prefix + "%s_generated.h") % (s.replace(".fbs", "").split("/")[-1])
188        for s in srcs
189    ]
190    reflection_name = "%s_reflection" % name if gen_reflections else ""
191
192    srcs_lib = "%s_srcs" % (name)
193    flatbuffer_library_public(
194        name = srcs_lib,
195        srcs = srcs,
196        outs = output_headers,
197        language_flag = "-c",
198        out_prefix = out_prefix,
199        includes = includes,
200        include_paths = include_paths,
201        flatc_args = flatc_args,
202        reflection_name = reflection_name,
203        reflection_visiblity = visibility,
204    )
205    native.cc_library(
206        name = name,
207        hdrs = [
208            ":" + srcs_lib,
209        ],
210        srcs = [
211            ":" + srcs_lib,
212        ],
213        features = [
214            "-parse_headers",
215        ],
216        deps = [
217            "@com_github_google_flatbuffers//:runtime_cc",
218        ],
219        includes = [],
220        linkstatic = 1,
221        visibility = visibility,
222    )
223
224    # A filegroup for the `srcs`. That is, all the schema files for this
225    # Flatbuffer set.
226    native.filegroup(
227        name = srcs_filegroup_name if srcs_filegroup_name else "%s_includes" % (name),
228        srcs = srcs,
229        visibility = srcs_filegroup_visibility if srcs_filegroup_visibility != None else visibility,
230    )
231