xref: /openbmc/qemu/scripts/qapi-gen.py (revision 52a47418)
13d004a37SPhilippe Mathieu-Daudé#!/usr/bin/env python3
2*52a47418SJohn Snow
3fb0bc835SMarkus Armbruster# This work is licensed under the terms of the GNU GPL, version 2 or later.
4fb0bc835SMarkus Armbruster# See the COPYING file in the top-level directory.
5fb0bc835SMarkus Armbruster
6*52a47418SJohn Snow"""
7*52a47418SJohn SnowQAPI Generator
8*52a47418SJohn Snow
9*52a47418SJohn SnowThis is the main entry point for generating C code from the QAPI schema.
10*52a47418SJohn Snow"""
11e6c42b96SMarkus Armbruster
123b446a18SMarkus Armbrusterimport argparse
133b446a18SMarkus Armbrusterimport re
14fb0bc835SMarkus Armbrusterimport sys
15*52a47418SJohn Snowfrom typing import Optional
16e6c42b96SMarkus Armbruster
17fb0bc835SMarkus Armbrusterfrom qapi.commands import gen_commands
18*52a47418SJohn Snowfrom qapi.error import QAPIError
19fb0bc835SMarkus Armbrusterfrom qapi.events import gen_events
20fb0bc835SMarkus Armbrusterfrom qapi.introspect import gen_introspect
21*52a47418SJohn Snowfrom qapi.schema import QAPISchema
22e6c42b96SMarkus Armbrusterfrom qapi.types import gen_types
23e6c42b96SMarkus Armbrusterfrom qapi.visit import gen_visit
24fb0bc835SMarkus Armbruster
25fb0bc835SMarkus Armbruster
26*52a47418SJohn Snowdef invalid_prefix_char(prefix: str) -> Optional[str]:
27*52a47418SJohn Snow    match = re.match(r'([A-Za-z_.-][A-Za-z0-9_.-]*)?', prefix)
28*52a47418SJohn Snow    if match.end() != len(prefix):
29*52a47418SJohn Snow        return prefix[match.end()]
30*52a47418SJohn Snow    return None
31*52a47418SJohn Snow
32*52a47418SJohn Snow
33*52a47418SJohn Snowdef generate(schema_file: str,
34*52a47418SJohn Snow             output_dir: str,
35*52a47418SJohn Snow             prefix: str,
36*52a47418SJohn Snow             unmask: bool = False,
37*52a47418SJohn Snow             builtins: bool = False) -> None:
38*52a47418SJohn Snow    """
39*52a47418SJohn Snow    Generate C code for the given schema into the target directory.
40*52a47418SJohn Snow
41*52a47418SJohn Snow    :param schema_file: The primary QAPI schema file.
42*52a47418SJohn Snow    :param output_dir: The output directory to store generated code.
43*52a47418SJohn Snow    :param prefix: Optional C-code prefix for symbol names.
44*52a47418SJohn Snow    :param unmask: Expose non-ABI names through introspection?
45*52a47418SJohn Snow    :param builtins: Generate code for built-in types?
46*52a47418SJohn Snow
47*52a47418SJohn Snow    :raise QAPIError: On failures.
48*52a47418SJohn Snow    """
49*52a47418SJohn Snow    assert invalid_prefix_char(prefix) is None
50*52a47418SJohn Snow
51*52a47418SJohn Snow    schema = QAPISchema(schema_file)
52*52a47418SJohn Snow    gen_types(schema, output_dir, prefix, builtins)
53*52a47418SJohn Snow    gen_visit(schema, output_dir, prefix, builtins)
54*52a47418SJohn Snow    gen_commands(schema, output_dir, prefix)
55*52a47418SJohn Snow    gen_events(schema, output_dir, prefix)
56*52a47418SJohn Snow    gen_introspect(schema, output_dir, prefix, unmask)
57*52a47418SJohn Snow
58*52a47418SJohn Snow
59*52a47418SJohn Snowdef main() -> int:
60*52a47418SJohn Snow    """
61*52a47418SJohn Snow    gapi-gen executable entry point.
62*52a47418SJohn Snow    Expects arguments via sys.argv, see --help for details.
63*52a47418SJohn Snow
64*52a47418SJohn Snow    :return: int, 0 on success, 1 on failure.
65*52a47418SJohn Snow    """
663b446a18SMarkus Armbruster    parser = argparse.ArgumentParser(
673b446a18SMarkus Armbruster        description='Generate code from a QAPI schema')
683b446a18SMarkus Armbruster    parser.add_argument('-b', '--builtins', action='store_true',
693b446a18SMarkus Armbruster                        help="generate code for built-in types")
70*52a47418SJohn Snow    parser.add_argument('-o', '--output-dir', action='store',
71*52a47418SJohn Snow                        default='',
723b446a18SMarkus Armbruster                        help="write output to directory OUTPUT_DIR")
73*52a47418SJohn Snow    parser.add_argument('-p', '--prefix', action='store',
74*52a47418SJohn Snow                        default='',
753b446a18SMarkus Armbruster                        help="prefix for symbols")
763b446a18SMarkus Armbruster    parser.add_argument('-u', '--unmask-non-abi-names', action='store_true',
773b446a18SMarkus Armbruster                        dest='unmask',
783b446a18SMarkus Armbruster                        help="expose non-ABI names in introspection")
793b446a18SMarkus Armbruster    parser.add_argument('schema', action='store')
803b446a18SMarkus Armbruster    args = parser.parse_args()
81fb0bc835SMarkus Armbruster
82*52a47418SJohn Snow    funny_char = invalid_prefix_char(args.prefix)
83*52a47418SJohn Snow    if funny_char:
84*52a47418SJohn Snow        msg = f"funny character '{funny_char}' in argument of --prefix"
85*52a47418SJohn Snow        print(f"{sys.argv[0]}: {msg}", file=sys.stderr)
86*52a47418SJohn Snow        return 1
87fb0bc835SMarkus Armbruster
88181feaf3SMarkus Armbruster    try:
89*52a47418SJohn Snow        generate(args.schema,
90*52a47418SJohn Snow                 output_dir=args.output_dir,
91*52a47418SJohn Snow                 prefix=args.prefix,
92*52a47418SJohn Snow                 unmask=args.unmask,
93*52a47418SJohn Snow                 builtins=args.builtins)
94181feaf3SMarkus Armbruster    except QAPIError as err:
95*52a47418SJohn Snow        print(f"{sys.argv[0]}: {str(err)}", file=sys.stderr)
96*52a47418SJohn Snow        return 1
97*52a47418SJohn Snow    return 0
98fb0bc835SMarkus Armbruster
99fb0bc835SMarkus Armbruster
100fb0bc835SMarkus Armbrusterif __name__ == '__main__':
101*52a47418SJohn Snow    sys.exit(main())
102