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