• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Description:
2#   BUILD rules for generating flatbuffer files in various languages.
3
4"""
5Rules for building C++ flatbuffers with Bazel.
6"""
7
8load("@rules_cc//cc:defs.bzl", "cc_library")
9
10TRUE_FLATC_PATH = Label("//:flatc")
11
12DEFAULT_INCLUDE_PATHS = [
13    "./",
14    "$(GENDIR)",
15    "$(BINDIR)",
16    "$(execpath %s).runfiles/%s" % (TRUE_FLATC_PATH, TRUE_FLATC_PATH.repo_name),
17]
18
19def default_include_paths(flatc_path):
20    return [
21        "./",
22        "$(GENDIR)",
23        "$(BINDIR)",
24        "$(execpath %s).runfiles/%s" % (flatc_path, flatc_path.repo_name),
25    ]
26
27DEFAULT_FLATC_ARGS = [
28    "--gen-object-api",
29    "--gen-compare",
30    "--no-includes",
31    "--gen-mutable",
32    "--reflect-names",
33    "--cpp-ptr-type flatbuffers::unique_ptr",
34]
35
36def flatbuffer_library_public(
37        name,
38        srcs,
39        outs,
40        language_flag,
41        out_prefix = "",
42        includes = [],
43        include_paths = None,
44        flatc_args = DEFAULT_FLATC_ARGS,
45        reflection_name = "",
46        reflection_visibility = None,
47        compatible_with = None,
48        restricted_to = None,
49        target_compatible_with = None,
50        flatc_path = None,
51        output_to_bindir = False,
52        tools = None,
53        extra_env = None,
54        **kwargs):
55    """Generates code files for reading/writing the given flatbuffers in the requested language using the public compiler.
56
57    Args:
58      name: Rule name.
59      srcs: Source .fbs files. Sent in order to the compiler.
60      outs: Output files from flatc.
61      language_flag: Target language flag. One of [-c, -j, -js].
62      out_prefix: Prepend this path to the front of all generated files except on
63          single source targets. Usually is a directory name.
64      includes: Optional, list of filegroups of schemas that the srcs depend on.
65      include_paths: Optional, list of paths the includes files can be found in.
66      flatc_args: Optional, list of additional arguments to pass to flatc.
67      reflection_name: Optional, if set this will generate the flatbuffer
68        reflection binaries for the schemas.
69      reflection_visibility: The visibility of the generated reflection Fileset.
70      output_to_bindir: Passed to genrule for output to bin directory.
71      compatible_with: Optional, The list of environments this rule can be
72        built for, in addition to default-supported environments.
73      restricted_to: Optional, The list of environments this rule can be built
74        for, instead of default-supported environments.
75      target_compatible_with: Optional, The list of target platform constraints
76        to use.
77      flatc_path: Bazel target corresponding to the flatc compiler to use.
78      output_to_bindir: Passed to genrule for output to bin directory.
79      tools: Optional, passed to genrule for list of tools to make available
80        during the action.
81      extra_env: Optional, must be a string of "VAR1=VAL1 VAR2=VAL2". These get
82        set as environment variables that "flatc_path" sees.
83      **kwargs: Passed to the underlying genrule.
84
85
86    This rule creates a filegroup(name) with all generated source files, and
87    optionally a Fileset([reflection_name]) with all generated reflection
88    binaries.
89    """
90    if flatc_path == None:
91        flatc_path = TRUE_FLATC_PATH
92    else:
93        flatc_path = native.package_relative_label(flatc_path)
94
95    reflection_include_paths = include_paths
96    if include_paths == None:
97        include_paths = default_include_paths(flatc_path)
98    include_paths_cmd = ["-I %s" % (s) for s in include_paths]
99
100    extra_env = extra_env or ""
101
102    # '$(@D)' when given a single source target will give the appropriate
103    # directory. Appending 'out_prefix' is only necessary when given a build
104    # target with multiple sources.
105    output_directory = (
106        ("-o $(@D)/%s" % (out_prefix)) if len(srcs) > 1 else ("-o $(@D)")
107    )
108    genrule_cmd = " ".join([
109        "SRCS=($(SRCS));",
110        "for f in $${SRCS[@]:0:%s}; do" % len(srcs),
111        "OUTPUT_FILE=\"$(OUTS)\" %s $(location %s)" % (extra_env, flatc_path),
112        " ".join(include_paths_cmd),
113        " ".join(flatc_args),
114        language_flag,
115        output_directory,
116        "$$f;",
117        "done",
118    ])
119    native.genrule(
120        name = name,
121        srcs = srcs + includes,
122        outs = outs,
123        output_to_bindir = output_to_bindir,
124        tools = (tools or []) + [flatc_path],
125        cmd = genrule_cmd,
126        compatible_with = compatible_with,
127        target_compatible_with = target_compatible_with,
128        restricted_to = restricted_to,
129        message = "Generating flatbuffer files for %s:" % (name),
130        **kwargs
131    )
132    if reflection_name:
133        if reflection_include_paths == None:
134            reflection_include_paths = default_include_paths(TRUE_FLATC_PATH)
135        reflection_include_paths_cmd = ["-I %s" % (s) for s in reflection_include_paths]
136        reflection_genrule_cmd = " ".join([
137            "SRCS=($(SRCS));",
138            "for f in $${SRCS[@]:0:%s}; do" % len(srcs),
139            # Move the .fbs file into the current package if it is not there already
140            'if [[ $$(dirname $$f) != "{0}" ]]; then s="$$f"; f="{0}/$$(basename "$$f")"; mkdir -p "{0}"; mv "$$s" "$$f"; fi;'.format(native.package_relative_label(":invalid").package),
141            "$(location %s)" % (TRUE_FLATC_PATH),
142            "-b --schema",
143            " ".join(flatc_args),
144            " ".join(reflection_include_paths_cmd),
145            language_flag,
146            output_directory,
147            "$$f;",
148            "done",
149        ])
150        reflection_outs = [
151            (out_prefix + "%s.bfbs") % (native.package_relative_label(s).name.removesuffix(".fbs"))
152            for s in srcs
153        ]
154
155        native.genrule(
156            name = "%s_srcs" % reflection_name,
157            srcs = srcs + includes,
158            outs = reflection_outs,
159            output_to_bindir = output_to_bindir,
160            tools = [TRUE_FLATC_PATH],
161            compatible_with = compatible_with,
162            restricted_to = restricted_to,
163            target_compatible_with = target_compatible_with,
164            cmd = reflection_genrule_cmd,
165            message = "Generating flatbuffer reflection binary for %s:" % (name),
166            visibility = reflection_visibility,
167        )
168        native.filegroup(
169            name = "%s_out" % reflection_name,
170            srcs = reflection_outs,
171            visibility = reflection_visibility,
172            compatible_with = compatible_with,
173            restricted_to = restricted_to,
174        )
175
176def flatbuffer_cc_library(
177        name,
178        srcs,
179        srcs_filegroup_name = "",
180        outs = [],
181        out_prefix = "",
182        deps = [],
183        includes = [],
184        include_paths = None,
185        cc_include_paths = [],
186        flatc_args = DEFAULT_FLATC_ARGS,
187        visibility = None,
188        compatible_with = None,
189        restricted_to = None,
190        target_compatible_with = None,
191        srcs_filegroup_visibility = None,
192        gen_reflections = False):
193    """A cc_library with the generated reader/writers for the given flatbuffer definitions.
194
195    Args:
196      name: Rule name.
197      srcs: Source .fbs files. Sent in order to the compiler.
198      srcs_filegroup_name: Name of the output filegroup that holds srcs. Pass this
199          filegroup into the `includes` parameter of any other
200          flatbuffer_cc_library that depends on this one's schemas.
201      outs: Additional outputs expected to be generated by flatc.
202      out_prefix: Prepend this path to the front of all generated files. Usually
203          is a directory name.
204      deps: Optional, list of other flatbuffer_cc_library's to depend on. Cannot be specified
205          alongside includes.
206      includes: Optional, list of filegroups of schemas that the srcs depend on.
207          Use of this is discouraged, and may be deprecated.
208      include_paths: Optional, list of paths the includes files can be found in.
209      cc_include_paths: Optional, list of paths to add to the cc_library includes attribute.
210      flatc_args: Optional list of additional arguments to pass to flatc
211          (e.g. --gen-mutable).
212      visibility: The visibility of the generated cc_library. By default, use the
213          default visibility of the project.
214      srcs_filegroup_visibility: The visibility of the generated srcs filegroup.
215          By default, use the value of the visibility parameter above.
216      gen_reflections: Optional, if true this will generate the flatbuffer
217        reflection binaries for the schemas.
218      compatible_with: Optional, The list of environments this rule can be built
219        for, in addition to default-supported environments.
220      restricted_to: Optional, The list of environments this rule can be built
221        for, instead of default-supported environments.
222      target_compatible_with: Optional, The list of target platform constraints
223        to use.
224
225    This produces:
226      filegroup([name]_srcs): all generated .h files.
227      filegroup(srcs_filegroup_name if specified, or [name]_includes if not):
228          Other flatbuffer_cc_library's can pass this in for their `includes`
229          parameter, if they depend on the schemas in this library.
230      Fileset([name]_reflection): (Optional) all generated reflection binaries.
231      cc_library([name]): library with sources and flatbuffers deps.
232    """
233    output_headers = [
234        (out_prefix + "%s_generated.h") % (s.replace(".fbs", "").split("/")[-1].split(":")[-1])
235        for s in srcs
236    ]
237    if deps and includes:
238        # There is no inherent reason we couldn't support both, but this discourages
239        # use of includes without good reason.
240        fail("Cannot specify both deps and include in flatbuffer_cc_library.")
241    if deps:
242        includes = [d + "_includes" for d in deps]
243    reflection_name = "%s_reflection" % name if gen_reflections else ""
244
245    srcs_lib = "%s_srcs" % (name)
246    flatbuffer_library_public(
247        name = srcs_lib,
248        srcs = srcs,
249        outs = outs + output_headers,
250        language_flag = "-c",
251        out_prefix = out_prefix,
252        includes = includes,
253        include_paths = include_paths,
254        flatc_args = flatc_args,
255        compatible_with = compatible_with,
256        restricted_to = restricted_to,
257        target_compatible_with = target_compatible_with,
258        reflection_name = reflection_name,
259        reflection_visibility = visibility,
260    )
261    cc_library(
262        name = name,
263        hdrs = [
264            ":" + srcs_lib,
265        ],
266        srcs = [
267            ":" + srcs_lib,
268        ],
269        features = [
270            "-parse_headers",
271        ],
272        deps = [
273            Label("//:runtime_cc"),
274            Label("//:flatbuffers"),
275        ] + deps,
276        includes = cc_include_paths,
277        compatible_with = compatible_with,
278        restricted_to = restricted_to,
279        target_compatible_with = target_compatible_with,
280        linkstatic = 1,
281        visibility = visibility,
282    )
283
284    # A filegroup for the `srcs`. That is, all the schema files for this
285    # Flatbuffer set.
286    native.filegroup(
287        name = srcs_filegroup_name if srcs_filegroup_name else "%s_includes" % (name),
288        srcs = srcs + includes,
289        compatible_with = compatible_with,
290        restricted_to = restricted_to,
291        visibility = srcs_filegroup_visibility if srcs_filegroup_visibility != None else visibility,
292    )
293