xref: /qemu/scripts/qapi/main.py (revision dde279925c97b614e45351400bfcf9efaf732f9d)
1a76ab215SJohn Snow# This work is licensed under the terms of the GNU GPL, version 2 or later.
2a76ab215SJohn Snow# See the COPYING file in the top-level directory.
3a76ab215SJohn Snow
4a76ab215SJohn Snow"""
5a76ab215SJohn SnowQAPI Generator
6a76ab215SJohn Snow
7a76ab215SJohn SnowThis is the main entry point for generating C code from the QAPI schema.
8a76ab215SJohn Snow"""
9a76ab215SJohn Snow
10a76ab215SJohn Snowimport argparse
11*dde27992SDaniel P. Berrangéfrom importlib import import_module
12a76ab215SJohn Snowimport sys
13a76ab215SJohn Snowfrom typing import Optional
14a76ab215SJohn Snow
15*dde27992SDaniel P. Berrangéfrom .backend import QAPIBackend, QAPICBackend
16e0e8a0acSJohn Snowfrom .common import must_match
177137a960SJohn Snowfrom .error import QAPIError
187137a960SJohn Snowfrom .schema import QAPISchema
19a76ab215SJohn Snow
20a76ab215SJohn Snow
21a76ab215SJohn Snowdef invalid_prefix_char(prefix: str) -> Optional[str]:
22e0e8a0acSJohn Snow    match = must_match(r'([A-Za-z_.-][A-Za-z0-9_.-]*)?', prefix)
23a76ab215SJohn Snow    if match.end() != len(prefix):
24a76ab215SJohn Snow        return prefix[match.end()]
25a76ab215SJohn Snow    return None
26a76ab215SJohn Snow
27a76ab215SJohn Snow
28*dde27992SDaniel P. Berrangédef create_backend(path: str) -> QAPIBackend:
29*dde27992SDaniel P. Berrangé    if path is None:
30*dde27992SDaniel P. Berrangé        return QAPICBackend()
31a76ab215SJohn Snow
32*dde27992SDaniel P. Berrangé    module_path, dot, class_name = path.rpartition('.')
33*dde27992SDaniel P. Berrangé    if not dot:
34*dde27992SDaniel P. Berrangé        print("argument of -B must be of the form MODULE.CLASS",
35*dde27992SDaniel P. Berrangé              file=sys.stderr)
36*dde27992SDaniel P. Berrangé        sys.exit(1)
37a76ab215SJohn Snow
38*dde27992SDaniel P. Berrangé    try:
39*dde27992SDaniel P. Berrangé        mod = import_module(module_path)
40*dde27992SDaniel P. Berrangé    except Exception as ex:
41*dde27992SDaniel P. Berrangé        print(f"unable to import '{module_path}': {ex}", file=sys.stderr)
42*dde27992SDaniel P. Berrangé        sys.exit(1)
43a76ab215SJohn Snow
44*dde27992SDaniel P. Berrangé    try:
45*dde27992SDaniel P. Berrangé        klass = getattr(mod, class_name)
46*dde27992SDaniel P. Berrangé    except AttributeError:
47*dde27992SDaniel P. Berrangé        print(f"module '{module_path}' has no class '{class_name}'",
48*dde27992SDaniel P. Berrangé              file=sys.stderr)
49*dde27992SDaniel P. Berrangé        sys.exit(1)
50*dde27992SDaniel P. Berrangé
51*dde27992SDaniel P. Berrangé    try:
52*dde27992SDaniel P. Berrangé        backend = klass()
53*dde27992SDaniel P. Berrangé    except Exception as ex:
54*dde27992SDaniel P. Berrangé        print(f"backend '{path}' cannot be instantiated: {ex}",
55*dde27992SDaniel P. Berrangé              file=sys.stderr)
56*dde27992SDaniel P. Berrangé        sys.exit(1)
57*dde27992SDaniel P. Berrangé
58*dde27992SDaniel P. Berrangé    if not isinstance(backend, QAPIBackend):
59*dde27992SDaniel P. Berrangé        print(f"backend '{path}' must be an instance of QAPIBackend",
60*dde27992SDaniel P. Berrangé              file=sys.stderr)
61*dde27992SDaniel P. Berrangé        sys.exit(1)
62*dde27992SDaniel P. Berrangé
63*dde27992SDaniel P. Berrangé    return backend
64a76ab215SJohn Snow
65a76ab215SJohn Snow
66a76ab215SJohn Snowdef main() -> int:
67a76ab215SJohn Snow    """
68a76ab215SJohn Snow    gapi-gen executable entry point.
69a76ab215SJohn Snow    Expects arguments via sys.argv, see --help for details.
70a76ab215SJohn Snow
71a76ab215SJohn Snow    :return: int, 0 on success, 1 on failure.
72a76ab215SJohn Snow    """
73a76ab215SJohn Snow    parser = argparse.ArgumentParser(
74a76ab215SJohn Snow        description='Generate code from a QAPI schema')
75a76ab215SJohn Snow    parser.add_argument('-b', '--builtins', action='store_true',
76a76ab215SJohn Snow                        help="generate code for built-in types")
77a76ab215SJohn Snow    parser.add_argument('-o', '--output-dir', action='store',
78a76ab215SJohn Snow                        default='',
79a76ab215SJohn Snow                        help="write output to directory OUTPUT_DIR")
80a76ab215SJohn Snow    parser.add_argument('-p', '--prefix', action='store',
81a76ab215SJohn Snow                        default='',
82a76ab215SJohn Snow                        help="prefix for symbols")
83a76ab215SJohn Snow    parser.add_argument('-u', '--unmask-non-abi-names', action='store_true',
84a76ab215SJohn Snow                        dest='unmask',
85a76ab215SJohn Snow                        help="expose non-ABI names in introspection")
86*dde27992SDaniel P. Berrangé    parser.add_argument('-B', '--backend', default=None,
87*dde27992SDaniel P. Berrangé                        help="Python module name for code generator")
88bd2017bcSVladimir Sementsov-Ogievskiy
89761a1a48SVladimir Sementsov-Ogievskiy    # Option --suppress-tracing exists so we can avoid solving build system
90bd2017bcSVladimir Sementsov-Ogievskiy    # problems.  TODO Drop it when we no longer need it.
91761a1a48SVladimir Sementsov-Ogievskiy    parser.add_argument('--suppress-tracing', action='store_true',
92761a1a48SVladimir Sementsov-Ogievskiy                        help="suppress adding trace events to qmp marshals")
93bd2017bcSVladimir Sementsov-Ogievskiy
94a76ab215SJohn Snow    parser.add_argument('schema', action='store')
95a76ab215SJohn Snow    args = parser.parse_args()
96a76ab215SJohn Snow
97a76ab215SJohn Snow    funny_char = invalid_prefix_char(args.prefix)
98a76ab215SJohn Snow    if funny_char:
99a76ab215SJohn Snow        msg = f"funny character '{funny_char}' in argument of --prefix"
100a76ab215SJohn Snow        print(f"{sys.argv[0]}: {msg}", file=sys.stderr)
101a76ab215SJohn Snow        return 1
102a76ab215SJohn Snow
103a76ab215SJohn Snow    try:
104*dde27992SDaniel P. Berrangé        schema = QAPISchema(args.schema)
105*dde27992SDaniel P. Berrangé        backend = create_backend(args.backend)
106*dde27992SDaniel P. Berrangé        backend.generate(schema,
107a76ab215SJohn Snow                         output_dir=args.output_dir,
108a76ab215SJohn Snow                         prefix=args.prefix,
109a76ab215SJohn Snow                         unmask=args.unmask,
110bd2017bcSVladimir Sementsov-Ogievskiy                         builtins=args.builtins,
111761a1a48SVladimir Sementsov-Ogievskiy                         gen_tracing=not args.suppress_tracing)
112a76ab215SJohn Snow    except QAPIError as err:
113bc5d3031SMarkus Armbruster        print(err, file=sys.stderr)
114a76ab215SJohn Snow        return 1
115a76ab215SJohn Snow    return 0
116