Merge branch 'test-ip_mreq_source-android-only' into 'master'
[glib.git] / gio / gdbus-2.0 / codegen / codegen_main.py
blob03de1d107ec031fee8b8d878c9228ef3ba90761d
1 # -*- Mode: Python -*-
2 # coding=utf-8
4 # GDBus - GLib D-Bus Library
6 # Copyright (C) 2008-2011 Red Hat, Inc.
7 # Copyright (C) 2018 Iñigo Martínez <inigomartinez@gmail.com>
9 # This library is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public
11 # License as published by the Free Software Foundation; either
12 # version 2.1 of the License, or (at your option) any later version.
14 # This library is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 # Lesser General Public License for more details.
19 # You should have received a copy of the GNU Lesser General
20 # Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 # Author: David Zeuthen <davidz@redhat.com>
24 import argparse
25 import os
26 import sys
28 from . import config
29 from . import dbustypes
30 from . import parser
31 from . import codegen
32 from . import codegen_docbook
33 from .utils import print_error, print_warning
35 def find_arg(arg_list, arg_name):
36 for a in arg_list:
37 if a.name == arg_name:
38 return a
39 return None
41 def find_method(iface, method):
42 for m in iface.methods:
43 if m.name == method:
44 return m
45 return None
47 def find_signal(iface, signal):
48 for m in iface.signals:
49 if m.name == signal:
50 return m
51 return None
53 def find_prop(iface, prop):
54 for m in iface.properties:
55 if m.name == prop:
56 return m
57 return None
59 def apply_annotation(iface_list, iface, method, signal, prop, arg, key, value):
60 iface_obj = None
61 for i in iface_list:
62 if i.name == iface:
63 iface_obj = i
64 break
66 if iface_obj is None:
67 print_error('No interface "{}"'.format(iface))
69 target_obj = None
71 if method:
72 method_obj = find_method(iface_obj, method)
73 if method_obj is None:
74 print_error('No method "{}" on interface "{}"'.format(method, iface))
75 if arg:
76 arg_obj = find_arg(method_obj.in_args, arg)
77 if (arg_obj is None):
78 arg_obj = find_arg(method_obj.out_args, arg)
79 if (arg_obj is None):
80 print_error('No arg "{}" on method "{}" on interface "{}"'.format(arg, method, iface))
81 target_obj = arg_obj
82 else:
83 target_obj = method_obj
84 elif signal:
85 signal_obj = find_signal(iface_obj, signal)
86 if signal_obj is None:
87 print_error('No signal "{}" on interface "{}"'.format(signal, iface))
88 if arg:
89 arg_obj = find_arg(signal_obj.args, arg)
90 if (arg_obj is None):
91 print_error('No arg "{}" on signal "{}" on interface "{}"'.format(arg, signal, iface))
92 target_obj = arg_obj
93 else:
94 target_obj = signal_obj
95 elif prop:
96 prop_obj = find_prop(iface_obj, prop)
97 if prop_obj is None:
98 print_error('No property "{}" on interface "{}"'.format(prop, iface))
99 target_obj = prop_obj
100 else:
101 target_obj = iface_obj
102 target_obj.annotations.insert(0, dbustypes.Annotation(key, value))
105 def apply_annotations(iface_list, annotation_list):
106 # apply annotations given on the command line
107 for (what, key, value) in annotation_list:
108 pos = what.find('::')
109 if pos != -1:
110 # signal
111 iface = what[0:pos];
112 signal = what[pos + 2:]
113 pos = signal.find('[')
114 if pos != -1:
115 arg = signal[pos + 1:]
116 signal = signal[0:pos]
117 pos = arg.find(']')
118 arg = arg[0:pos]
119 apply_annotation(iface_list, iface, None, signal, None, arg, key, value)
120 else:
121 apply_annotation(iface_list, iface, None, signal, None, None, key, value)
122 else:
123 pos = what.find(':')
124 if pos != -1:
125 # property
126 iface = what[0:pos];
127 prop = what[pos + 1:]
128 apply_annotation(iface_list, iface, None, None, prop, None, key, value)
129 else:
130 pos = what.find('()')
131 if pos != -1:
132 # method
133 combined = what[0:pos]
134 pos = combined.rfind('.')
135 iface = combined[0:pos]
136 method = combined[pos + 1:]
137 pos = what.find('[')
138 if pos != -1:
139 arg = what[pos + 1:]
140 pos = arg.find(']')
141 arg = arg[0:pos]
142 apply_annotation(iface_list, iface, method, None, None, arg, key, value)
143 else:
144 apply_annotation(iface_list, iface, method, None, None, None, key, value)
145 else:
146 # must be an interface
147 iface = what
148 apply_annotation(iface_list, iface, None, None, None, None, key, value)
150 def codegen_main():
151 arg_parser = argparse.ArgumentParser(description='D-Bus code and documentation generator')
152 arg_parser.add_argument('files', metavar='FILE', nargs='*',
153 help='D-Bus introspection XML file')
154 arg_parser.add_argument('--xml-files', metavar='FILE', action='append', default=[],
155 help=argparse.SUPPRESS)
156 arg_parser.add_argument('--interface-prefix', metavar='PREFIX', default='',
157 help='String to strip from D-Bus interface names for code and docs')
158 arg_parser.add_argument('--c-namespace', metavar='NAMESPACE', default='',
159 help='The namespace to use for generated C code')
160 arg_parser.add_argument('--c-generate-object-manager', action='store_true',
161 help='Generate a GDBusObjectManagerClient subclass when generating C code')
162 arg_parser.add_argument('--c-generate-autocleanup', choices=['none', 'objects', 'all'], default='objects',
163 help='Generate autocleanup support')
164 arg_parser.add_argument('--generate-docbook', metavar='OUTFILES',
165 help='Generate Docbook in OUTFILES-org.Project.IFace.xml')
166 arg_parser.add_argument('--pragma-once', action='store_true',
167 help='Use "pragma once" as the inclusion guard')
168 arg_parser.add_argument('--annotate', nargs=3, action='append', metavar='WHAT KEY VALUE',
169 help='Add annotation (may be used several times)')
171 group = arg_parser.add_mutually_exclusive_group()
172 group.add_argument('--generate-c-code', metavar='OUTFILES',
173 help='Generate C code in OUTFILES.[ch]')
174 group.add_argument('--header', action='store_true',
175 help='Generate C headers')
176 group.add_argument('--body', action='store_true',
177 help='Generate C code')
178 group.add_argument('--interface-info-header', action='store_true',
179 help='Generate GDBusInterfaceInfo C header')
180 group.add_argument('--interface-info-body', action='store_true',
181 help='Generate GDBusInterfaceInfo C code')
183 group = arg_parser.add_mutually_exclusive_group()
184 group.add_argument('--output', metavar='FILE',
185 help='Write output into the specified file')
186 group.add_argument('--output-directory', metavar='OUTDIR', default='',
187 help='Location to output generated files')
189 args = arg_parser.parse_args();
191 if len(args.xml_files) > 0:
192 print_warning('The "--xml-files" option is deprecated; use positional arguments instead')
194 if ((args.generate_c_code is not None or args.generate_docbook is not None) and
195 args.output is not None):
196 print_error('Using --generate-c-code or --generate-docbook and '
197 '--output at the same time is not allowed')
199 if args.generate_c_code:
200 header_name = args.generate_c_code + '.h'
201 h_file = os.path.join(args.output_directory, header_name)
202 args.header = True
203 c_file = os.path.join(args.output_directory, args.generate_c_code + '.c')
204 args.body = True
205 elif args.header:
206 if args.output is None:
207 print_error('Using --header requires --output')
209 h_file = args.output
210 header_name = os.path.basename(h_file)
211 elif args.body:
212 if args.output is None:
213 print_error('Using --body requires --output')
215 c_file = args.output
216 header_name = os.path.splitext(os.path.basename(c_file))[0] + '.h'
217 elif args.interface_info_header:
218 if args.output is None:
219 print_error('Using --interface-info-header requires --output')
220 if args.c_generate_object_manager:
221 print_error('--c-generate-object-manager is incompatible with '
222 '--interface-info-header')
224 h_file = args.output
225 header_name = os.path.basename(h_file)
226 elif args.interface_info_body:
227 if args.output is None:
228 print_error('Using --interface-info-body requires --output')
229 if args.c_generate_object_manager:
230 print_error('--c-generate-object-manager is incompatible with '
231 '--interface-info-body')
233 c_file = args.output
234 header_name = os.path.splitext(os.path.basename(c_file))[0] + '.h'
236 all_ifaces = []
237 input_files_basenames = []
238 for fname in args.files + args.xml_files:
239 with open(fname, 'rb') as f:
240 xml_data = f.read()
241 parsed_ifaces = parser.parse_dbus_xml(xml_data)
242 all_ifaces.extend(parsed_ifaces)
243 input_files_basenames.append(os.path.basename(fname))
245 if args.annotate is not None:
246 apply_annotations(all_ifaces, args.annotate)
248 for i in all_ifaces:
249 i.post_process(args.interface_prefix, args.c_namespace)
251 docbook = args.generate_docbook
252 docbook_gen = codegen_docbook.DocbookCodeGenerator(all_ifaces);
253 if docbook:
254 ret = docbook_gen.generate(docbook, args.output_directory)
256 if args.header:
257 with open(h_file, 'w') as outfile:
258 gen = codegen.HeaderCodeGenerator(all_ifaces,
259 args.c_namespace,
260 args.c_generate_object_manager,
261 args.c_generate_autocleanup,
262 header_name,
263 input_files_basenames,
264 args.pragma_once,
265 outfile)
266 gen.generate()
268 if args.body:
269 with open(c_file, 'w') as outfile:
270 gen = codegen.CodeGenerator(all_ifaces,
271 args.c_namespace,
272 args.c_generate_object_manager,
273 header_name,
274 input_files_basenames,
275 docbook_gen,
276 outfile)
277 gen.generate()
279 if args.interface_info_header:
280 with open(h_file, 'w') as outfile:
281 gen = codegen.InterfaceInfoHeaderCodeGenerator(all_ifaces,
282 args.c_namespace,
283 header_name,
284 args.pragma_once,
285 outfile)
286 gen.generate()
288 if args.interface_info_body:
289 with open(c_file, 'w') as outfile:
290 gen = codegen.InterfaceInfoBodyCodeGenerator(all_ifaces,
291 args.c_namespace,
292 header_name,
293 outfile)
294 gen.generate()
296 sys.exit(0)
298 if __name__ == "__main__":
299 codegen_main()