diff --git a/docs/reference/gio/gdbus-codegen.xml b/docs/reference/gio/gdbus-codegen.xml index b1145e5ef..3e1a9d668 100644 --- a/docs/reference/gio/gdbus-codegen.xml +++ b/docs/reference/gio/gdbus-codegen.xml @@ -39,6 +39,8 @@ FILE + + OUTFILE @@ -69,7 +71,11 @@ arguments on the command line and generates output files. It currently supports generating C source code (via ) or header (via ) - and Docbook XML (via ). + and Docbook XML (via ). Alternatively, + more restricted C source code and headers can be generated, which just + contain the interface information (as GDBusInterfaceInfo + structures) using and + . @@ -90,8 +96,11 @@ For C code generation either that - generates source code, or that - generates headers, can be used. These options must be used along with + generates source code, that + generates headers, that generates + interface information source code, or + that generates interface information + headers, can be used. These options must be used along with , which is used to specify the file to output to. @@ -282,8 +291,10 @@ Directory to output generated source to. Equivalent to changing directory before generation. - This option cannot be used with neither nor - , and must be used. + This option cannot be used with , + , or + ; and + must be used. @@ -321,12 +332,52 @@ + + + + + If this option is passed, it will generate the header code for the + GDBusInterfaceInfo structures only and will write it to + the disk by using the path and file name provided by + . + + + Using , or + are not allowed to be used along with + the and + options, because these options + are used to generate only one file. + + + + + + + + + If this option is passed, it will generate the source code for the + GDBusInterfaceInfo structures only and will write it to + the disk by using the path and file name provided by + . + + + Using , or + are not allowed to be used along with + the and + options, because these options + are used to generate only one file. + + + + OUTFILE - The full path where the header () or the source code - () will be written, using the path and filename provided by + The full path where the header (, + ) or the source code + (, ) will + be written, using the path and filename provided by . The full path could be something like $($OUTFILE).{c,h}. diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py index 032a29ed5..307018571 100644 --- a/gio/gdbus-2.0/codegen/codegen.py +++ b/gio/gdbus-2.0/codegen/codegen.py @@ -613,6 +613,286 @@ class HeaderCodeGenerator: # ---------------------------------------------------------------------------------------------------- +class InterfaceInfoHeaderCodeGenerator: + def __init__(self, ifaces, namespace, header_name, use_pragma, outfile): + self.ifaces = ifaces + self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace) + self.header_guard = header_name.upper().replace('.', '_').replace('-', '_').replace('/', '_').replace(':', '_') + self.use_pragma = use_pragma + self.outfile = outfile + + # ---------------------------------------------------------------------------------------------------- + + def generate_header_preamble(self): + self.outfile.write(LICENSE_STR.format(config.VERSION)) + self.outfile.write('\n') + + if self.use_pragma: + self.outfile.write('#pragma once\n') + else: + self.outfile.write('#ifndef __{!s}__\n'.format(self.header_guard)) + self.outfile.write('#define __{!s}__\n'.format(self.header_guard)) + + self.outfile.write('\n') + self.outfile.write('#include \n') + self.outfile.write('\n') + self.outfile.write('G_BEGIN_DECLS\n') + self.outfile.write('\n') + + # ---------------------------------------------------------------------------------------------------- + + def declare_infos(self): + for i in self.ifaces: + self.outfile.write('extern const GDBusInterfaceInfo %s_interface;\n' % i.name_lower) + + # ---------------------------------------------------------------------------------------------------- + + def generate_header_postamble(self): + self.outfile.write('\n') + self.outfile.write('G_END_DECLS\n') + + if not self.use_pragma: + self.outfile.write('\n') + self.outfile.write('#endif /* __{!s}__ */\n'.format(self.header_guard)) + + # ---------------------------------------------------------------------------------------------------- + + def generate(self): + self.generate_header_preamble() + self.declare_infos() + self.generate_header_postamble() + +# ---------------------------------------------------------------------------------------------------- + +class InterfaceInfoBodyCodeGenerator: + def __init__(self, ifaces, namespace, header_name, outfile): + self.ifaces = ifaces + self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace) + self.header_name = header_name + self.outfile = outfile + + # ---------------------------------------------------------------------------------------------------- + + def generate_body_preamble(self): + self.outfile.write(LICENSE_STR.format(config.VERSION)) + self.outfile.write('\n') + self.outfile.write('#ifdef HAVE_CONFIG_H\n' + '# include "config.h"\n' + '#endif\n' + '\n' + '#include "%s"\n' + '\n' + '#include \n' + % (self.header_name)) + self.outfile.write('\n') + + # ---------------------------------------------------------------------------------------------------- + + def generate_array(self, array_name_lower, element_type, elements): + self.outfile.write('const %s * const %s[] =\n' % (element_type, array_name_lower)) + self.outfile.write('{\n') + for (_, name) in sorted(elements, key=utils.version_cmp_key): + self.outfile.write(' &%s,\n' % name) + self.outfile.write(' NULL,\n') + self.outfile.write('};\n') + self.outfile.write('\n') + + def define_annotations(self, array_name_lower, annotations): + if len(annotations) == 0: + return + + annotation_pointers = [] + + for a in annotations: + # Skip internal annotations. + if a.key.startswith('org.gtk.GDBus'): + continue + + self.define_annotations('%s__%s_annotations' % (array_name_lower, a.key_lower), a.annotations) + + self.outfile.write('const GDBusAnnotationInfo %s__%s_annotation =\n' % (array_name_lower, a.key_lower)) + self.outfile.write('{\n') + self.outfile.write(' -1, /* ref count */\n') + self.outfile.write(' (gchar *) "%s",\n' % a.key) + self.outfile.write(' (gchar *) "%s",\n' % a.value) + if len(a.annotations) > 0: + self.outfile.write(' (GDBusAnnotationInfo **) %s__%s_annotations,\n' % (array_name_lower, a.key_lower)) + else: + self.outfile.write(' NULL, /* no annotations */\n') + self.outfile.write('};\n') + self.outfile.write('\n') + + key = (a.since, '%s__%s_annotation' % (array_name_lower, a.key_lower)) + annotation_pointers.append(key) + + self.generate_array(array_name_lower, 'GDBusAnnotationInfo', + annotation_pointers) + + def define_args(self, array_name_lower, args): + if len(args) == 0: + return + + arg_pointers = [] + + for a in args: + self.define_annotations('%s__%s_arg_annotations' % (array_name_lower, a.name), a.annotations) + + self.outfile.write('const GDBusArgInfo %s__%s_arg =\n' % (array_name_lower, a.name)) + self.outfile.write('{\n') + self.outfile.write(' -1, /* ref count */\n') + self.outfile.write(' (gchar *) "%s",\n' % a.name) + self.outfile.write(' (gchar *) "%s",\n' % a.signature) + if len(a.annotations) > 0: + self.outfile.write(' (GDBusAnnotationInfo **) %s__%s_arg_annotations,\n' % (array_name_lower, a.name)) + else: + self.outfile.write(' NULL, /* no annotations */\n') + self.outfile.write('};\n') + self.outfile.write('\n') + + key = (a.since, '%s__%s_arg' % (array_name_lower, a.name)) + arg_pointers.append(key) + + self.generate_array(array_name_lower, 'GDBusArgInfo', arg_pointers) + + def define_infos(self): + for i in self.ifaces: + self.outfile.write('/* ------------------------------------------------------------------------ */\n') + self.outfile.write('/* Definitions for %s */\n' % i.name) + self.outfile.write('\n') + + # GDBusMethodInfos. + if len(i.methods) > 0: + method_pointers = [] + + for m in i.methods: + self.define_args('%s_interface__%s_method_in_args' % (i.name_lower, m.name_lower), m.in_args) + self.define_args('%s_interface__%s_method_out_args' % (i.name_lower, m.name_lower), m.out_args) + self.define_annotations('%s_interface__%s_method_annotations' % (i.name_lower, m.name_lower), m.annotations) + + self.outfile.write('const GDBusMethodInfo %s_interface__%s_method =\n' % (i.name_lower, m.name_lower)) + self.outfile.write('{\n') + self.outfile.write(' -1, /* ref count */\n') + self.outfile.write(' (gchar *) "%s",\n' % m.name) + if len(m.in_args) > 0: + self.outfile.write(' (GDBusArgInfo **) %s_interface__%s_method_in_args,\n' % (i.name_lower, m.name_lower)) + else: + self.outfile.write(' NULL, /* no in args */\n') + if len(m.out_args) > 0: + self.outfile.write(' (GDBusArgInfo **) %s_interface__%s_method_out_args,\n' % (i.name_lower, m.name_lower)) + else: + self.outfile.write(' NULL, /* no out args */\n') + if len(m.annotations) > 0: + self.outfile.write(' (GDBusAnnotationInfo **) %s_interface__%s_method_annotations,\n' % (i.name_lower, m.name_lower)) + else: + self.outfile.write(' NULL, /* no annotations */\n') + self.outfile.write('};\n') + self.outfile.write('\n') + + key = (m.since, '%s_interface__%s_method' % (i.name_lower, m.name_lower)) + method_pointers.append(key) + + self.generate_array('%s_interface_methods' % i.name_lower, + 'GDBusMethodInfo', method_pointers) + + # GDBusSignalInfos. + if len(i.signals) > 0: + signal_pointers = [] + + for s in i.signals: + self.define_args('%s_interface__%s_signal_args' % (i.name_lower, s.name_lower), s.args) + self.define_annotations('%s_interface__%s_signal_annotations' % (i.name_lower, s.name_lower), s.annotations) + + self.outfile.write('const GDBusSignalInfo %s_interface__%s_signal =\n' % (i.name_lower, s.name_lower)) + self.outfile.write('{\n') + self.outfile.write(' -1, /* ref count */\n') + self.outfile.write(' (gchar *) "%s",\n' % s.name) + if len(s.args) > 0: + self.outfile.write(' (GDBusArgInfo **) %s_interface__%s_signal_args,\n' % (i.name_lower, s.name_lower)) + else: + self.outfile.write(' NULL, /* no args */\n') + if len(s.annotations) > 0: + self.outfile.write(' (GDBusAnnotationInfo **) %s_interface__%s_signal_annotations,\n' % (i.name_lower, s.name_lower)) + else: + self.outfile.write(' NULL, /* no annotations */\n') + self.outfile.write('};\n') + self.outfile.write('\n') + + key = (m.since, '%s_interface__%s_signal' % (i.name_lower, s.name_lower)) + signal_pointers.append(key) + + self.generate_array('%s_interface_signals' % i.name_lower, + 'GDBusSignalInfo', signal_pointers) + + # GDBusPropertyInfos. + if len(i.properties) > 0: + property_pointers = [] + + for p in i.properties: + if p.readable and p.writable: + flags = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE' + elif p.readable: + flags = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE' + elif p.writable: + flags = 'G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE' + else: + flags = 'G_DBUS_PROPERTY_INFO_FLAGS_NONE' + + self.define_annotations('%s_interface__%s_property_annotations' % (i.name_lower, p.name_lower), p.annotations) + + self.outfile.write('const GDBusPropertyInfo %s_interface__%s_property =\n' % (i.name_lower, p.name_lower)) + self.outfile.write('{\n') + self.outfile.write(' -1, /* ref count */\n') + self.outfile.write(' (gchar *) "%s",\n' % p.name) + self.outfile.write(' (gchar *) "%s",\n' % p.signature) + self.outfile.write(' %s,\n' % flags) + if len(p.annotations) > 0: + self.outfile.write(' (GDBusAnnotationInfo **) %s_interface__%s_property_annotations,\n' % (i.name_lower, p.name_lower)) + else: + self.outfile.write(' NULL, /* no annotations */\n') + self.outfile.write('};\n') + self.outfile.write('\n') + + key = (m.since, '%s_interface__%s_property' % (i.name_lower, p.name_lower)) + property_pointers.append(key) + + self.generate_array('%s_interface_properties' % i.name_lower, + 'GDBusPropertyInfo', property_pointers) + + # Finally the GDBusInterfaceInfo. + self.define_annotations('%s_interface_annotations' % i.name_lower, + i.annotations) + + self.outfile.write('const GDBusInterfaceInfo %s_interface =\n' % i.name_lower) + self.outfile.write('{\n') + self.outfile.write(' -1, /* ref count */\n') + self.outfile.write(' (gchar *) "%s",\n' % i.name) + if len(i.methods) > 0: + self.outfile.write(' (GDBusMethodInfo **) %s_interface_methods,\n' % i.name_lower) + else: + self.outfile.write(' NULL, /* no methods */\n') + if len(i.signals) > 0: + self.outfile.write(' (GDBusSignalInfo **) %s_interface_signals,\n' % i.name_lower) + else: + self.outfile.write(' NULL, /* no signals */\n') + if len(i.properties) > 0: + self.outfile.write(' (GDBusPropertyInfo **) %s_interface_properties,\n' % i.name_lower) + else: + self.outfile.write( 'NULL, /* no properties */\n') + if len(i.annotations) > 0: + self.outfile.write(' (GDBusAnnotationInfo **) %s_interface_annotations,\n' % i.name_lower) + else: + self.outfile.write(' NULL, /* no annotations */\n') + self.outfile.write('};\n') + self.outfile.write('\n') + + # ---------------------------------------------------------------------------------------------------- + + def generate(self): + self.generate_body_preamble() + self.define_infos() + +# ---------------------------------------------------------------------------------------------------- + class CodeGenerator: def __init__(self, ifaces, namespace, generate_objmanager, header_name, input_files_basenames, docbook_gen, outfile): diff --git a/gio/gdbus-2.0/codegen/codegen_main.py b/gio/gdbus-2.0/codegen/codegen_main.py index 65876a2e8..10ecf7785 100755 --- a/gio/gdbus-2.0/codegen/codegen_main.py +++ b/gio/gdbus-2.0/codegen/codegen_main.py @@ -152,7 +152,7 @@ def codegen_main(): arg_parser.add_argument('files', metavar='FILE', nargs='*', help='D-Bus introspection XML file') arg_parser.add_argument('--xml-files', metavar='FILE', action='append', default=[], - help='D-Bus introspection XML file') + help=argparse.SUPPRESS) arg_parser.add_argument('--interface-prefix', metavar='PREFIX', default='', help='String to strip from D-Bus interface names for code and docs') arg_parser.add_argument('--c-namespace', metavar='NAMESPACE', default='', @@ -175,6 +175,10 @@ def codegen_main(): help='Generate C headers') group.add_argument('--body', action='store_true', help='Generate C code') + group.add_argument('--interface-info-header', action='store_true', + help='Generate GDBusInterfaceInfo C header') + group.add_argument('--interface-info-body', action='store_true', + help='Generate GDBusInterfaceInfo C code') group = arg_parser.add_mutually_exclusive_group() group.add_argument('--output', metavar='FILE', @@ -210,6 +214,24 @@ def codegen_main(): c_file = args.output header_name = os.path.splitext(os.path.basename(c_file))[0] + '.h' + elif args.interface_info_header: + if args.output is None: + print_error('Using --interface-info-header requires --output') + if args.c_generate_object_manager: + print_error('--c-generate-object-manager is incompatible with ' + '--interface-info-header') + + h_file = args.output + header_name = os.path.basename(h_file) + elif args.interface_info_body: + if args.output is None: + print_error('Using --interface-info-body requires --output') + if args.c_generate_object_manager: + print_error('--c-generate-object-manager is incompatible with ' + '--interface-info-body') + + c_file = args.output + header_name = os.path.splitext(os.path.basename(c_file))[0] + '.h' all_ifaces = [] input_files_basenames = [] @@ -220,7 +242,7 @@ def codegen_main(): all_ifaces.extend(parsed_ifaces) input_files_basenames.append(os.path.basename(fname)) - if args.annotate != None: + if args.annotate is not None: apply_annotations(all_ifaces, args.annotate) for i in all_ifaces: @@ -254,6 +276,23 @@ def codegen_main(): outfile) gen.generate() + if args.interface_info_header: + with open(h_file, 'w') as outfile: + gen = codegen.InterfaceInfoHeaderCodeGenerator(all_ifaces, + args.c_namespace, + header_name, + args.pragma_once, + outfile) + gen.generate() + + if args.interface_info_body: + with open(c_file, 'w') as outfile: + gen = codegen.InterfaceInfoBodyCodeGenerator(all_ifaces, + args.c_namespace, + header_name, + outfile) + gen.generate() + sys.exit(0) if __name__ == "__main__": diff --git a/gio/gdbus-2.0/codegen/dbustypes.py b/gio/gdbus-2.0/codegen/dbustypes.py index bfc69f596..2b721bfbf 100644 --- a/gio/gdbus-2.0/codegen/dbustypes.py +++ b/gio/gdbus-2.0/codegen/dbustypes.py @@ -27,6 +27,25 @@ class Annotation: self.key = key self.value = value self.annotations = [] + self.since = '' + + def post_process(self, interface_prefix, cns, cns_upper, cns_lower, container): + key = self.key + overridden_key = utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.Name') + if utils.is_ugly_case(overridden_key): + self.key_lower = overridden_key.lower() + else: + if overridden_key: + key = overridden_key + self.key_lower = utils.camel_case_to_uscore(key).lower().replace('-', '_').replace('.', '_') + + if len(self.since) == 0: + self.since = utils.lookup_since(self.annotations) + if len(self.since) == 0: + self.since = container.since + + for a in self.annotations: + a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) class Arg: def __init__(self, name, signature): @@ -229,6 +248,8 @@ class Arg: self.gvalue_get = 'g_value_get_boxed' self.array_annotation = '(array zero-terminated=1)' + for a in self.annotations: + a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) class Method: def __init__(self, name): @@ -270,6 +291,9 @@ class Method: if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true': self.deprecated = True + for a in self.annotations: + a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) + class Signal: def __init__(self, name): self.name = name @@ -305,6 +329,9 @@ class Signal: if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true': self.deprecated = True + for a in self.annotations: + a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) + class Property: def __init__(self, name, signature, access): self.name = name @@ -356,6 +383,9 @@ class Property: if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true': self.deprecated = True + for a in self.annotations: + a.post_process(interface_prefix, cns, cns_upper, cns_lower, self) + class Interface: def __init__(self, name): self.name = name @@ -429,3 +459,6 @@ class Interface: for p in self.properties: p.post_process(interface_prefix, cns, cns_upper, cns_lower, self) + + for a in self.annotations: + a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)