xref: /aosp_15_r20/external/flatbuffers/scripts/generate_code.py (revision 890232f25432b36107d06881e0a25aaa6b473652)
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