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