1#!/usr/bin/env python3 2# 3# Copyright 2021 Google Inc. All rights reserved. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import argparse 18import filecmp 19import glob 20import platform 21import shutil 22import subprocess 23import generate_grpc_examples 24from pathlib import Path 25 26parser = argparse.ArgumentParser() 27parser.add_argument( 28 "--flatc", 29 help="path of the Flat C compiler relative to the root directory", 30) 31parser.add_argument("--cpp-0x", action="store_true", help="use --cpp-std c++ox") 32parser.add_argument( 33 "--skip-monster-extra", 34 action="store_true", 35 help="skip generating tests involving monster_extra.fbs", 36) 37parser.add_argument( 38 "--skip-gen-reflection", 39 action="store_true", 40 help="skip generating the reflection.fbs files", 41) 42args = parser.parse_args() 43 44# Get the path where this script is located so we can invoke the script from 45# any directory and have the paths work correctly. 46script_path = Path(__file__).parent.resolve() 47 48# Get the root path as an absolute path, so all derived paths are absolute. 49root_path = script_path.parent.absolute() 50 51# Get the location of the flatc executable, reading from the first command line 52# argument or defaulting to default names. 53flatc_exe = Path( 54 ("flatc" if not platform.system() == "Windows" else "flatc.exe") 55 if not args.flatc 56 else args.flatc 57) 58 59# Find and assert flatc compiler is present. 60if root_path in flatc_exe.parents: 61 flatc_exe = flatc_exe.relative_to(root_path) 62flatc_path = Path(root_path, flatc_exe) 63assert flatc_path.exists(), "Cannot find the flatc compiler " + str(flatc_path) 64 65# Specify the other paths that will be referenced 66tests_path = Path(root_path, "tests") 67swift_code_gen = Path(root_path, "tests/FlatBuffers.Test.Swift/CodeGenerationTests") 68samples_path = Path(root_path, "samples") 69reflection_path = Path(root_path, "reflection") 70 71# Execute the flatc compiler with the specified parameters 72def flatc(options, schema, prefix=None, include=None, data=None, cwd=tests_path): 73 cmd = [str(flatc_path)] + options 74 if prefix: 75 cmd += ["-o"] + [prefix] 76 if include: 77 cmd += ["-I"] + [include] 78 cmd += [schema] if isinstance(schema, str) else schema 79 if data: 80 cmd += [data] if isinstance(data, str) else data 81 result = subprocess.run(cmd, cwd=str(cwd), check=True) 82 83 84# Generate the code for flatbuffers reflection schema 85def flatc_reflection(options, location, target): 86 full_options = ["--no-prefix"] + options 87 temp_dir = ".tmp" 88 flatc( 89 full_options, 90 prefix=temp_dir, 91 schema="reflection.fbs", 92 cwd=reflection_path, 93 ) 94 new_reflection_path = Path(reflection_path, temp_dir, target) 95 original_reflection_path = Path(root_path, location, target) 96 if not filecmp.cmp(str(new_reflection_path), str(original_reflection_path)): 97 shutil.rmtree(str(original_reflection_path), ignore_errors=True) 98 shutil.move(str(new_reflection_path), str(original_reflection_path)) 99 shutil.rmtree(str(Path(reflection_path, temp_dir))) 100 101def flatc_annotate(schema, file, include=None, cwd=tests_path): 102 cmd = [str(flatc_path)] 103 if include: 104 cmd += ["-I"] + [include] 105 cmd += ["--annotate", schema, file] 106 result = subprocess.run(cmd, cwd=str(cwd), check=True) 107 108# Glob a pattern relative to file path 109def glob(path, pattern): 110 return [str(p) for p in path.glob(pattern)] 111 112 113# flatc options that are shared 114BASE_OPTS = ["--reflect-names", "--gen-mutable", "--gen-object-api"] 115NO_INCL_OPTS = BASE_OPTS + ["--no-includes"] 116 117# Language specific options 118CS_OPTS = ["--csharp", "--cs-gen-json-serializer"] 119CPP_OPTS = [ 120 "--cpp", 121 "--gen-compare", 122 "--cpp-ptr-type", 123 "flatbuffers::unique_ptr", 124] + (["--cpp-std", "c++0x"] if args.cpp_0x else []) 125 126CPP_17_OPTS = NO_INCL_OPTS + [ 127 "--cpp", 128 "--cpp-std", 129 "c++17", 130 "--cpp-static-reflection", 131 "--gen-object-api", 132] 133RUST_OPTS = BASE_OPTS + [ 134 "--rust", 135 "--gen-all", 136 "--gen-name-strings", 137 "--rust-module-root-file", 138] 139RUST_SERIALIZE_OPTS = BASE_OPTS + [ 140 "--rust", 141 "--gen-all", 142 "--gen-name-strings", 143 "--rust-serialize", 144 "--rust-module-root-file", 145] 146TS_OPTS = ["--ts", "--gen-name-strings"] 147LOBSTER_OPTS = ["--lobster"] 148SWIFT_OPTS = ["--swift", "--gen-json-emit", "--bfbs-filenames", str(tests_path)] 149SWIFT_OPTS_CODE_GEN = [ 150 "--swift", 151 "--gen-json-emit", 152 "--bfbs-filenames", 153 swift_code_gen 154] 155JAVA_OPTS = ["--java"] 156KOTLIN_OPTS = ["--kotlin"] 157PHP_OPTS = ["--php"] 158DART_OPTS = ["--dart"] 159PYTHON_OPTS = ["--python"] 160BINARY_OPTS = ["-b", "--schema", "--bfbs-comments", "--bfbs-builtins"] 161 162# Basic Usage 163 164flatc( 165 NO_INCL_OPTS 166 + CPP_OPTS 167 + CS_OPTS 168 + TS_OPTS 169 + [ 170 "--binary", 171 "--java", 172 "--kotlin", 173 "--dart", 174 "--go", 175 "--lobster", 176 "--php", 177 ], 178 schema="monster_test.fbs", 179 include="include_test", 180 data="monsterdata_test.json", 181) 182 183flatc( 184 ["--lua", "--bfbs-filenames", str(tests_path)], 185 schema="monster_test.fbs", 186 include="include_test", 187) 188 189flatc( 190 NO_INCL_OPTS + CPP_OPTS + ["--grpc"], 191 schema="monster_test.fbs", 192 include="include_test", 193 data="monsterdata_test.json", 194) 195 196flatc( 197 RUST_OPTS, 198 schema="monster_test.fbs", 199 include="include_test", 200 prefix="monster_test", 201 data="monsterdata_test.json", 202) 203 204flatc( 205 RUST_SERIALIZE_OPTS, 206 schema="monster_test.fbs", 207 include="include_test", 208 prefix="monster_test_serialize", 209 data="monsterdata_test.json", 210) 211 212flatc( 213 options=BASE_OPTS + ["--python"], 214 schema="monster_test.fbs", 215 include="include_test", 216 data="monsterdata_test.json", 217) 218 219flatc( 220 options=BASE_OPTS + ["--python", "--gen-onefile"], 221 schema="monster_test.fbs", 222 include="include_test", 223 data="monsterdata_test.json", 224) 225 226# For Rust we currently generate two independent schemas, with namespace_test2 227# duplicating the types in namespace_test1 228flatc( 229 RUST_OPTS, 230 prefix="namespace_test", 231 schema=[ 232 "namespace_test/namespace_test1.fbs", 233 "namespace_test/namespace_test2.fbs", 234 ], 235) 236 237flatc( 238 BASE_OPTS + CPP_OPTS + CS_OPTS + TS_OPTS + JAVA_OPTS + KOTLIN_OPTS + PHP_OPTS, 239 prefix="union_vector", 240 schema="union_vector/union_vector.fbs", 241) 242 243flatc( 244 BASE_OPTS + TS_OPTS + ["--gen-name-strings", "--gen-mutable"], 245 include="include_test", 246 schema="monster_test.fbs", 247) 248 249# Generate the complete flat file TS of monster. 250flatc( 251 ["--ts", "--gen-all", "--ts-flat-files"], 252 include="include_test", 253 schema="monster_test.fbs", 254 prefix="ts/ts-flat-files" 255) 256 257flatc( 258 BASE_OPTS + TS_OPTS + ["-b"], 259 include="include_test", 260 schema="monster_test.fbs", 261 data="unicode_test.json", 262) 263 264flatc( 265 BASE_OPTS + TS_OPTS + ["--gen-name-strings"], 266 prefix="union_vector", 267 schema="union_vector/union_vector.fbs", 268) 269 270flatc( 271 RUST_OPTS, 272 prefix="include_test1", 273 include="include_test", 274 schema="include_test/include_test1.fbs", 275) 276 277flatc( 278 RUST_OPTS, 279 prefix="include_test2", 280 include="include_test", 281 schema="include_test/sub/include_test2.fbs", 282) 283 284flatc( 285 BINARY_OPTS + ["--bfbs-filenames", str(tests_path)], 286 include="include_test", 287 schema="monster_test.fbs", 288) 289 290# Generate the annotated binary of the monster_test binary schema. 291flatc_annotate( 292 schema="../reflection/reflection.fbs", 293 file="monster_test.bfbs", 294 include="include_test" 295) 296 297flatc_annotate( 298 schema="monster_test.fbs", 299 file="monsterdata_test.mon", 300 include="include_test" 301) 302 303flatc( 304 CPP_OPTS 305 + NO_INCL_OPTS 306 + [ 307 "--bfbs-comments", 308 "--bfbs-builtins", 309 "--bfbs-gen-embed", 310 "--bfbs-filenames", 311 str(tests_path), 312 ], 313 include="include_test", 314 schema="monster_test.fbs", 315) 316 317flatc( 318 BINARY_OPTS + ["--bfbs-filenames", str(tests_path)], 319 include="include_test", 320 schema="arrays_test.fbs", 321) 322 323flatc( 324 ["--jsonschema", "--schema"], 325 include="include_test", 326 schema="monster_test.fbs", 327) 328 329if not args.skip_monster_extra: 330 flatc( 331 CPP_OPTS + CS_OPTS + NO_INCL_OPTS + JAVA_OPTS + KOTLIN_OPTS + PYTHON_OPTS, 332 schema="monster_extra.fbs", 333 data="monsterdata_extra.json", 334 ) 335 336 flatc( 337 DART_OPTS + ["--gen-object-api"], 338 schema="monster_extra.fbs", 339 ) 340 341flatc( 342 CPP_OPTS + CS_OPTS + NO_INCL_OPTS + JAVA_OPTS + ["--jsonschema", "--scoped-enums"], 343 schema="arrays_test.fbs", 344) 345 346flatc( 347 RUST_OPTS, 348 prefix="arrays_test", 349 schema="arrays_test.fbs", 350) 351 352flatc( 353 BASE_OPTS + PYTHON_OPTS, 354 schema="arrays_test.fbs", 355) 356 357 358# Optional Scalars 359optional_scalars_schema = "optional_scalars.fbs" 360flatc(["--java", "--kotlin", "--lobster", "--ts"], schema=optional_scalars_schema) 361 362flatc(["--csharp", "--python", "--gen-object-api"], schema=optional_scalars_schema) 363 364flatc(RUST_OPTS, prefix="optional_scalars", schema=optional_scalars_schema) 365 366flatc(NO_INCL_OPTS + CPP_OPTS, schema=optional_scalars_schema) 367 368# Type / field collsion 369type_field_collsion_schema = "type_field_collsion.fbs" 370 371flatc(["--csharp", "--gen-object-api"], schema=type_field_collsion_schema) 372 373# Generate string/vector default code for tests 374flatc(RUST_OPTS, prefix="more_defaults", schema="more_defaults.fbs") 375 376# Generate the schema evolution tests 377flatc( 378 CPP_OPTS + ["--scoped-enums"], 379 prefix="evolution_test", 380 schema=glob(tests_path, "evolution_test/evolution_v*.fbs"), 381) 382 383# Generate the keywords tests 384flatc(BASE_OPTS + CS_OPTS, schema="keyword_test.fbs") 385flatc(RUST_OPTS, prefix="keyword_test", schema="keyword_test.fbs") 386flatc( 387 BASE_OPTS + CS_OPTS + ["--cs-global-alias", "--gen-onefile"], 388 prefix="nested_namespace_test", 389 schema=glob(tests_path, "nested_namespace_test/nested_namespace_test*.fbs"), 390) 391flatc(BASE_OPTS + DART_OPTS, prefix="../dart/test/", schema="keyword_test.fbs") 392 393# Field key lookup with default value test 394dictionary_lookup_schema = "dictionary_lookup.fbs" 395flatc(["--java", "--kotlin"], schema=dictionary_lookup_schema) 396 397# Swift Tests 398swift_prefix = "FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests" 399flatc( 400 SWIFT_OPTS + BASE_OPTS + ["--grpc"], 401 schema="monster_test.fbs", 402 include="include_test", 403 prefix=swift_prefix, 404) 405flatc( 406 SWIFT_OPTS + BASE_OPTS, 407 schema="union_vector/union_vector.fbs", 408 prefix=swift_prefix, 409) 410flatc(SWIFT_OPTS, schema="optional_scalars.fbs", prefix=swift_prefix) 411flatc(SWIFT_OPTS, schema="vector_has_test.fbs", prefix=swift_prefix) 412flatc( 413 SWIFT_OPTS + ["--gen-object-api"], 414 schema="more_defaults.fbs", 415 prefix=swift_prefix, 416) 417flatc( 418 SWIFT_OPTS + BASE_OPTS, 419 schema="MutatingBool.fbs", 420 prefix=swift_prefix, 421) 422 423flatc( 424 SWIFT_OPTS_CODE_GEN + BASE_OPTS + ["--grpc", "--swift-implementation-only"], 425 schema="test_import.fbs", 426 cwd=swift_code_gen 427) 428 429flatc( 430 SWIFT_OPTS_CODE_GEN + NO_INCL_OPTS + ["--grpc"], 431 schema="test_no_include.fbs", 432 cwd=swift_code_gen 433) 434 435# --filename-suffix and --filename-ext tests 436flatc( 437 CPP_OPTS + NO_INCL_OPTS + ["--grpc", "--filename-ext", "hpp"], 438 include="include_test", 439 prefix="monster_test_suffix/ext_only", 440 schema="monster_test.fbs", 441) 442flatc( 443 CPP_OPTS + NO_INCL_OPTS + ["--grpc", "--filename-suffix", "_suffix"], 444 include="include_test", 445 prefix="monster_test_suffix/filesuffix_only", 446 schema="monster_test.fbs", 447) 448flatc( 449 CPP_OPTS + NO_INCL_OPTS + ["--grpc", "--filename-suffix", "_suffix", "--filename-ext", "hpp"], 450 include="include_test", 451 prefix="monster_test_suffix", 452 schema="monster_test.fbs", 453) 454 455# Flag c++17 requires Clang6, GCC7, MSVC2017 (_MSC_VER >= 1914) or higher. 456cpp_17_prefix = "cpp17/generated_cpp17" 457flatc( 458 CPP_17_OPTS, 459 schema="monster_test.fbs", 460 include="include_test", 461 prefix=cpp_17_prefix, 462) 463flatc( 464 CPP_17_OPTS, 465 schema="optional_scalars.fbs", 466 prefix=cpp_17_prefix, 467) 468flatc( 469 CPP_17_OPTS, 470 schema="union_vector/union_vector.fbs", 471 prefix=cpp_17_prefix, 472) 473 474# Private annotations 475annotations_test_schema = "private_annotation_test.fbs" 476 477flatc(RUST_OPTS + ["--no-leak-private-annotation", "--gen-object-api"], prefix="private_annotation_test", schema=annotations_test_schema) 478 479# Sample files 480samples_schema = "monster.fbs" 481flatc(BASE_OPTS + CPP_OPTS + LOBSTER_OPTS, schema=samples_schema, cwd=samples_path) 482flatc(RUST_OPTS, prefix="rust_generated", schema=samples_schema, cwd=samples_path) 483flatc( 484 BINARY_OPTS + ["--bfbs-filenames", str(samples_path)], 485 schema=samples_schema, 486 cwd=samples_path, 487) 488 489# Reflection 490 491# Skip generating the reflection if told too, as we run this script after 492# building flatc which uses the reflection_generated.h itself. 493if not args.skip_gen_reflection: 494 # C++ Reflection 495 flatc_reflection( 496 ["-c", "--cpp-std", "c++0x"], "include/flatbuffers", "reflection_generated.h" 497 ) 498 499# Python Reflection 500flatc_reflection(["-p"], "python/flatbuffers", "reflection") 501 502# Annotation 503 504 505def flatc_annotate(schema, include=None, data=None, cwd=tests_path): 506 cmd = [str(flatc_path)] 507 if include: 508 cmd += ["-I"] + [include] 509 cmd += ["--annotate", schema] 510 if data: 511 cmd += [data] if isinstance(data, str) else data 512 subprocess.run(cmd, cwd=str(cwd), check=True) 513 514 515flatc_annotate( 516 schema="monster_test.fbs", include="include_test", data="monsterdata_test.mon" 517) 518 519# Run the generate_grpc_examples script 520generate_grpc_examples.GenerateGRPCExamples() 521