1 #!/usr/bin/env @PYTHON@
3 # pylint: disable=too-many-lines, missing-docstring, invalid-name
5 # This file is part of GLib
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 VERSION_STR = '''glib-genmarshal version @VERSION@
26 glib-genmarshal comes with ABSOLUTELY NO WARRANTY.
27 You may redistribute copies of glib-genmarshal under the terms of
28 the GNU General Public License which can be found in the
29 GLib source package. Sources, examples and contact
30 information are available at http://www.gtk.org'''
32 GETTERS_STR = '''#ifdef G_ENABLE_DEBUG
33 #define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
34 #define g_marshal_value_peek_char(v) g_value_get_schar (v)
35 #define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
36 #define g_marshal_value_peek_int(v) g_value_get_int (v)
37 #define g_marshal_value_peek_uint(v) g_value_get_uint (v)
38 #define g_marshal_value_peek_long(v) g_value_get_long (v)
39 #define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
40 #define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
41 #define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
42 #define g_marshal_value_peek_enum(v) g_value_get_enum (v)
43 #define g_marshal_value_peek_flags(v) g_value_get_flags (v)
44 #define g_marshal_value_peek_float(v) g_value_get_float (v)
45 #define g_marshal_value_peek_double(v) g_value_get_double (v)
46 #define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
47 #define g_marshal_value_peek_param(v) g_value_get_param (v)
48 #define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
49 #define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
50 #define g_marshal_value_peek_object(v) g_value_get_object (v)
51 #define g_marshal_value_peek_variant(v) g_value_get_variant (v)
52 #else /* !G_ENABLE_DEBUG */
53 /* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
54 * Do not access GValues directly in your code. Instead, use the
55 * g_value_get_*() functions
57 #define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
58 #define g_marshal_value_peek_char(v) (v)->data[0].v_int
59 #define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
60 #define g_marshal_value_peek_int(v) (v)->data[0].v_int
61 #define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
62 #define g_marshal_value_peek_long(v) (v)->data[0].v_long
63 #define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
64 #define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
65 #define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
66 #define g_marshal_value_peek_enum(v) (v)->data[0].v_long
67 #define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
68 #define g_marshal_value_peek_float(v) (v)->data[0].v_float
69 #define g_marshal_value_peek_double(v) (v)->data[0].v_double
70 #define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
71 #define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
72 #define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
73 #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
74 #define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
75 #define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer
76 #endif /* !G_ENABLE_DEBUG */'''
78 DEPRECATED_MSG_STR = 'The token "{}" is deprecated; use "{}" instead'
81 ' arg{:d} = ({:s}) va_arg (args_copy, {:s});'
83 '(param_types[{:d}] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && '
85 ' arg{idx:d} = {box_func} (param_types[{idx:d}] & ~G_SIGNAL_TYPE_STATIC_SCOPE, arg{idx:d});'
87 ' arg{idx:d} = {box_func} (arg{idx:d});'
89 ' {unbox_func} (param_types[{idx:d}] & ~G_SIGNAL_TYPE_STATIC_SCOPE, arg{idx:d});'
91 ' {unbox_func} (arg{idx:d});'
93 STD_PREFIX = 'g_cclosure_marshal'
95 # These are part of our ABI; keep this in sync with gmarshal.h
96 GOBJECT_MARSHALLERS = {
97 'g_cclosure_marshal_VOID__VOID',
98 'g_cclosure_marshal_VOID__BOOLEAN',
99 'g_cclosure_marshal_VOID__CHAR',
100 'g_cclosure_marshal_VOID__UCHAR',
101 'g_cclosure_marshal_VOID__INT',
102 'g_cclosure_marshal_VOID__UINT',
103 'g_cclosure_marshal_VOID__LONG',
104 'g_cclosure_marshal_VOID__ULONG',
105 'g_cclosure_marshal_VOID__ENUM',
106 'g_cclosure_marshal_VOID__FLAGS',
107 'g_cclosure_marshal_VOID__FLOAT',
108 'g_cclosure_marshal_VOID__DOUBLE',
109 'g_cclosure_marshal_VOID__STRING',
110 'g_cclosure_marshal_VOID__PARAM',
111 'g_cclosure_marshal_VOID__BOXED',
112 'g_cclosure_marshal_VOID__POINTER',
113 'g_cclosure_marshal_VOID__OBJECT',
114 'g_cclosure_marshal_VOID__VARIANT',
115 'g_cclosure_marshal_VOID__UINT_POINTER',
116 'g_cclosure_marshal_BOOLEAN__FLAGS',
117 'g_cclosure_marshal_STRING__OBJECT_POINTER',
118 'g_cclosure_marshal_BOOLEAN__BOXED_BOXED',
122 # pylint: disable=too-few-public-methods
124 '''ANSI Terminal colors'''
127 YELLOW = '\033[1;33m'
132 def print_color(msg, color=Color.END, prefix='MESSAGE'):
133 '''Print a string with a color prefix'''
134 if os.isatty(sys.stderr.fileno()):
135 real_prefix = '{start}{prefix}{end}'.format(start=color, prefix=prefix, end=Color.END)
138 sys.stderr.write('{prefix}: {msg}\n'.format(prefix=real_prefix, msg=msg))
141 def print_error(msg):
142 '''Print an error, and terminate'''
143 print_color(msg, color=Color.RED, prefix='ERROR')
147 def print_warning(msg, fatal=False):
148 '''Print a warning, and optionally terminate'''
155 print_color(msg, color, prefix)
161 '''Print a message'''
162 print_color(msg, color=Color.GREEN, prefix='INFO')
165 def generate_licensing_comment(outfile):
166 outfile.write('/* This file is generated by glib-genmarshal, do not '
167 'modify it. This code is licensed under the same license as '
168 'the containing project. Note that it links to GLib, so '
169 'must comply with the LGPL linking clauses. */\n')
172 def generate_header_preamble(outfile, prefix='', std_includes=True, use_pragma=False):
173 '''Generate the preamble for the marshallers header file'''
174 generate_licensing_comment(outfile)
177 outfile.write('#pragma once\n')
180 outfile.write('#ifndef __{}_MARSHAL_H__\n'.format(prefix.upper()))
181 outfile.write('#define __{}_MARSHAL_H__\n'.format(prefix.upper()))
183 # Maintain compatibility with the old C-based tool
185 outfile.write('#include <glib-object.h>\n')
188 outfile.write('G_BEGIN_DECLS\n')
192 def generate_header_postamble(outfile, prefix='', use_pragma=False):
193 '''Generate the postamble for the marshallers header file'''
195 outfile.write('G_END_DECLS\n')
199 outfile.write('#endif /* __{}_MARSHAL_H__ */\n'.format(prefix.upper()))
202 def generate_body_preamble(outfile, std_includes=True, include_headers=None, cpp_defines=None, cpp_undefines=None):
203 '''Generate the preamble for the marshallers source file'''
204 generate_licensing_comment(outfile)
206 for header in (include_headers or []):
207 outfile.write('#include "{}"\n'.format(header))
211 for define in (cpp_defines or []):
212 s = define.split('=')
214 value = s[1] if len(s) > 1 else '1'
215 outfile.write('#define {} {}\n'.format(symbol, value))
219 for undefine in (cpp_undefines or []):
220 outfile.write('#undef {}\n'.format(undefine))
225 outfile.write('#include <glib-object.h>\n')
228 outfile.write(GETTERS_STR)
229 outfile.write('\n\n')
232 # Marshaller arguments, as a dictionary where the key is the token used in
233 # the source file, and the value is another dictionary with the following
236 # - signal: the token used in the marshaller prototype (mandatory)
237 # - ctype: the C type for the marshaller argument (mandatory)
238 # - getter: the function used to retrieve the argument from the GValue
239 # array when invoking the callback (optional)
240 # - promoted: the C type used by va_arg() to retrieve the argument from
241 # the va_list when invoking the callback (optional, only used when
242 # generating va_list marshallers)
243 # - box: an array of two elements, containing the boxing and unboxing
244 # functions for the given type (optional, only used when generating
245 # va_list marshallers)
246 # - static-check: a boolean value, if the given type should perform
247 # a static type check before boxing or unboxing the argument (optional,
248 # only used when generating va_list marshallers)
249 # - takes-type: a boolean value, if the boxing and unboxing functions
250 # for the given type require the type (optional, only used when
251 # generating va_list marshallers)
252 # - deprecated: whether the token has been deprecated (optional)
253 # - replaced-by: the token used to replace a deprecated token (optional,
254 # only used if deprecated is True)
263 'getter': 'g_marshal_value_peek_boolean',
269 'getter': 'g_marshal_value_peek_char',
275 'getter': 'g_marshal_value_peek_uchar',
280 'getter': 'g_marshal_value_peek_int',
285 'getter': 'g_marshal_value_peek_uint',
290 'getter': 'g_marshal_value_peek_long',
295 'getter': 'g_marshal_value_peek_ulong',
300 'getter': 'g_marshal_value_peek_int64',
305 'getter': 'g_marshal_value_peek_uint64',
310 'getter': 'g_marshal_value_peek_enum',
315 'getter': 'g_marshal_value_peek_flags',
320 'promoted': 'gdouble',
321 'getter': 'g_marshal_value_peek_float',
326 'getter': 'g_marshal_value_peek_double',
331 'getter': 'g_marshal_value_peek_string',
332 'box': ['g_strdup', 'g_free'],
337 'getter': 'g_marshal_value_peek_param',
338 'box': ['g_param_spec_ref', 'g_param_spec_unref'],
343 'getter': 'g_marshal_value_peek_boxed',
344 'box': ['g_boxed_copy', 'g_boxed_free'],
345 'static-check': True,
351 'getter': 'g_marshal_value_peek_pointer',
356 'getter': 'g_marshal_value_peek_object',
357 'box': ['g_object_ref', 'g_object_unref'],
362 'getter': 'g_marshal_value_peek_variant',
363 'box': ['g_variant_ref', 'g_variant_unref'],
364 'static-check': True,
373 'replaced_by': 'VOID'
378 'getter': 'g_marshal_value_peek_boolean',
380 'replaced_by': 'BOOLEAN'
385 # Marshaller return values, as a dictionary where the key is the token used
386 # in the source file, and the value is another dictionary with the following
389 # - signal: the token used in the marshaller prototype (mandatory)
390 # - ctype: the C type for the marshaller argument (mandatory)
391 # - setter: the function used to set the return value of the callback
392 # into a GValue (optional)
393 # - deprecated: whether the token has been deprecated (optional)
394 # - replaced-by: the token used to replace a deprecated token (optional,
395 # only used if deprecated is True)
404 'setter': 'g_value_set_boolean',
409 'setter': 'g_value_set_char',
414 'setter': 'g_value_set_uchar',
419 'setter': 'g_value_set_int',
424 'setter': 'g_value_set_uint',
429 'setter': 'g_value_set_long',
434 'setter': 'g_value_set_ulong',
439 'setter': 'g_value_set_int64',
444 'setter': 'g_value_set_uint64',
449 'setter': 'g_value_set_enum',
454 'setter': 'g_value_set_flags',
459 'setter': 'g_value_set_float',
464 'setter': 'g_value_set_double',
469 'setter': 'g_value_take_string',
473 'ctype': 'GParamSpec*',
474 'setter': 'g_value_take_param',
479 'setter': 'g_value_take_boxed',
484 'setter': 'g_value_set_pointer',
489 'setter': 'g_value_take_object',
493 'ctype': 'GVariant*',
494 'setter': 'g_value_take_variant',
503 'replaced_by': 'VOID',
508 'setter': 'g_value_set_boolean',
510 'replaced_by': 'BOOLEAN',
515 def check_args(retval, params, fatal_warnings=False):
516 '''Check the @retval and @params tokens for invalid and deprecated symbols.'''
517 if retval not in OUT_ARGS:
518 print_error('Unknown return value type "{}"'.format(retval))
520 if OUT_ARGS[retval].get('deprecated', False):
521 replaced_by = OUT_ARGS[retval]['replaced_by']
522 print_warning(DEPRECATED_MSG_STR.format(retval, replaced_by), fatal_warnings)
525 if param not in IN_ARGS:
526 print_error('Unknown parameter type "{}"'.format(param))
528 if IN_ARGS[param].get('deprecated', False):
529 replaced_by = IN_ARGS[param]['replaced_by']
530 print_warning(DEPRECATED_MSG_STR.format(param, replaced_by), fatal_warnings)
533 def indent(text, level=0, fill=' '):
534 '''Indent @text by @level columns, using the @fill character'''
535 return ''.join([fill for x in range(level)]) + text
538 # pylint: disable=too-few-public-methods
540 '''Symbol visibility options'''
546 def generate_marshaller_name(prefix, retval, params, replace_deprecated=True):
547 '''Generate a marshaller name for the given @prefix, @retval, and @params.
548 If @replace_deprecated is True, the generated name will replace deprecated
550 if replace_deprecated:
551 real_retval = OUT_ARGS[retval]['signal']
554 real_params.append(IN_ARGS[param]['signal'])
558 return '{prefix}_{retval}__{args}'.format(prefix=prefix,
560 args='_'.join(real_params))
563 def generate_prototype(retval, params,
564 prefix='g_cclosure_user_marshal',
565 visibility=Visibility.NONE,
567 '''Generate a marshaller declaration with the given @visibility. If @va_marshal
568 is True, the marshaller will use variadic arguments in place of a GValue array.'''
571 if visibility == Visibility.INTERNAL:
572 signature += ['G_GNUC_INTERNAL']
573 elif visibility == Visibility.EXTERN:
574 signature += ['extern']
576 function_name = generate_marshaller_name(prefix, retval, params)
579 signature += ['void ' + function_name + ' (GClosure *closure,']
580 width = len('void ') + len(function_name) + 2
582 signature += [indent('GValue *return_value,', level=width, fill=' ')]
583 signature += [indent('guint n_param_values,', level=width, fill=' ')]
584 signature += [indent('const GValue *param_values,', level=width, fill=' ')]
585 signature += [indent('gpointer invocation_hint,', level=width, fill=' ')]
586 signature += [indent('gpointer marshal_data);', level=width, fill=' ')]
588 signature += ['void ' + function_name + 'v (GClosure *closure,']
589 width = len('void ') + len(function_name) + 3
591 signature += [indent('GValue *return_value,', level=width, fill=' ')]
592 signature += [indent('gpointer instance,', level=width, fill=' ')]
593 signature += [indent('va_list args,', level=width, fill=' ')]
594 signature += [indent('gpointer marshal_data,', level=width, fill=' ')]
595 signature += [indent('int n_params,', level=width, fill=' ')]
596 signature += [indent('GType *param_types);', level=width, fill=' ')]
601 # pylint: disable=too-many-statements, too-many-locals, too-many-branches
602 def generate_body(retval, params, prefix, va_marshal=False):
603 '''Generate a marshaller definition. If @va_marshal is True, the marshaller
604 will use va_list and variadic arguments in place of a GValue array.'''
605 retval_setter = OUT_ARGS[retval].get('setter', None)
606 # If there's no return value then we can mark the retval argument as unused
607 # and get a minor optimisation, as well as avoid a compiler warning
608 if not retval_setter:
609 unused = ' G_GNUC_UNUSED'
615 function_name = generate_marshaller_name(prefix, retval, params)
618 body += [function_name + ' (GClosure *closure,']
619 width = len(function_name) + 2
621 body += [indent('GValue *return_value{},'.format(unused), level=width, fill=' ')]
622 body += [indent('guint n_param_values,', level=width, fill=' ')]
623 body += [indent('const GValue *param_values,', level=width, fill=' ')]
624 body += [indent('gpointer invocation_hint G_GNUC_UNUSED,', level=width, fill=' ')]
625 body += [indent('gpointer marshal_data)', level=width, fill=' ')]
627 body += [function_name + 'v (GClosure *closure,']
628 width = len(function_name) + 3
630 body += [indent('GValue *return_value{},'.format(unused), level=width, fill=' ')]
631 body += [indent('gpointer instance,', level=width, fill=' ')]
632 body += [indent('va_list args,', level=width, fill=' ')]
633 body += [indent('gpointer marshal_data,', level=width, fill=' ')]
634 body += [indent('int n_params,', level=width, fill=' ')]
635 body += [indent('GType *param_types)', level=width, fill=' ')]
637 # Filter the arguments that have a getter
638 get_args = [x for x in params if IN_ARGS[x].get('getter', None) is not None]
642 # Generate the type of the marshaller function
643 typedef_marshal = generate_marshaller_name('GMarshalFunc', retval, params)
645 typedef = ' typedef {ctype} (*{func_name}) ('.format(ctype=OUT_ARGS[retval]['ctype'],
646 func_name=typedef_marshal)
648 typedef += 'gpointer data1,'
651 for idx, in_arg in enumerate(get_args):
652 body += [indent('{} arg{:d},'.format(IN_ARGS[in_arg]['ctype'], idx + 1), level=pad)]
654 body += [indent('gpointer data2);', level=pad)]
656 # Variable declarations
657 body += [' GCClosure *cc = (GCClosure *) closure;']
658 body += [' gpointer data1, data2;']
659 body += [' {} callback;'.format(typedef_marshal)]
662 body += [' {} v_return;'.format(OUT_ARGS[retval]['ctype'])]
665 for idx, arg in enumerate(get_args):
666 body += [' {} arg{:d};'.format(IN_ARGS[arg]['ctype'], idx)]
669 body += [' va_list args_copy;']
672 body += [' G_VA_COPY (args_copy, args);']
674 for idx, arg in enumerate(get_args):
675 ctype = IN_ARGS[arg]['ctype']
676 promoted_ctype = IN_ARGS[arg].get('promoted', ctype)
677 body += [VA_ARG_STR.format(idx, ctype, promoted_ctype)]
678 if IN_ARGS[arg].get('box', None):
679 box_func = IN_ARGS[arg]['box'][0]
680 if IN_ARGS[arg].get('static-check', False):
681 static_check = STATIC_CHECK_STR.format(idx)
684 arg_check = 'arg{:d} != NULL'.format(idx)
685 body += [' if ({}{})'.format(static_check, arg_check)]
686 if IN_ARGS[arg].get('takes-type', False):
687 body += [BOX_TYPED_STR.format(idx=idx, box_func=box_func)]
689 body += [BOX_UNTYPED_STR.format(idx=idx, box_func=box_func)]
691 body += [' va_end (args_copy);']
695 # Preconditions check
697 body += [' g_return_if_fail (return_value != NULL);']
700 body += [' g_return_if_fail (n_param_values == {:d});'.format(len(get_args) + 1)]
704 # Marshal instance, data, and callback set up
705 body += [' if (G_CCLOSURE_SWAP_DATA (closure))']
707 body += [' data1 = closure->data;']
709 body += [' data2 = instance;']
711 body += [' data2 = g_value_peek_pointer (param_values + 0);']
716 body += [' data1 = instance;']
718 body += [' data1 = g_value_peek_pointer (param_values + 0);']
719 body += [' data2 = closure->data;']
721 # pylint: disable=line-too-long
722 body += [' callback = ({}) (marshal_data ? marshal_data : cc->callback);'.format(typedef_marshal)]
725 # Marshal callback action
727 callback = ' {} callback ('.format(' v_return =')
729 callback = ' callback ('
732 body += [callback + 'data1,']
735 for idx, arg in enumerate(get_args):
736 body += [indent('arg{:d},'.format(idx), level=pad)]
738 for idx, arg in enumerate(get_args):
739 arg_getter = IN_ARGS[arg]['getter']
740 body += [indent('{} (param_values + {:d}),'.format(arg_getter, idx + 1), level=pad)]
742 body += [indent('data2);', level=pad)]
745 boxed_args = [x for x in get_args if IN_ARGS[x].get('box', None) is not None]
749 for idx, arg in enumerate(get_args):
750 if not IN_ARGS[arg].get('box', None):
752 unbox_func = IN_ARGS[arg]['box'][1]
753 if IN_ARGS[arg].get('static-check', False):
754 static_check = STATIC_CHECK_STR.format(idx)
757 arg_check = 'arg{:d} != NULL'.format(idx)
758 body += [' if ({}{})'.format(static_check, arg_check)]
759 if IN_ARGS[arg].get('takes-type', False):
760 body += [UNBOX_TYPED_STR.format(idx=idx, unbox_func=unbox_func)]
762 body += [UNBOX_UNTYPED_STR.format(idx=idx, unbox_func=unbox_func)]
766 body += [' {} (return_value, v_return);'.format(retval_setter)]
773 def generate_marshaller_alias(outfile, marshaller, real_marshaller,
775 source_location=None):
776 '''Generate an alias between @marshaller and @real_marshaller, including
777 an optional alias for va_list marshallers'''
779 outfile.write('/* {} */\n'.format(source_location))
781 outfile.write('#define {}\t{}\n'.format(marshaller, real_marshaller))
784 outfile.write('#define {}v\t{}v\n'.format(marshaller, real_marshaller))
789 def generate_marshallers_header(outfile, retval, params,
790 prefix='g_cclosure_user_marshal',
792 include_va=False, source_location=None):
793 '''Generate a declaration for a marshaller function, to be used in the header,
794 with the given @retval, @params, and @prefix. An optional va_list marshaller
795 for the same arguments is also generated. The generated buffer is written to
796 the @outfile stream object.'''
798 outfile.write('/* {} */\n'.format(source_location))
801 visibility = Visibility.INTERNAL
803 visibility = Visibility.EXTERN
805 signature = generate_prototype(retval, params, prefix, visibility, False)
807 signature += generate_prototype(retval, params, prefix, visibility, True)
810 outfile.write('\n'.join(signature))
814 def generate_marshallers_body(outfile, retval, params,
815 prefix='g_cclosure_user_marshal',
816 include_prototype=True,
818 include_va=False, source_location=None):
819 '''Generate a definition for a marshaller function, to be used in the source,
820 with the given @retval, @params, and @prefix. An optional va_list marshaller
821 for the same arguments is also generated. The generated buffer is written to
822 the @outfile stream object.'''
824 outfile.write('/* {} */\n'.format(source_location))
826 if include_prototype:
827 # Declaration visibility
829 decl_visibility = Visibility.INTERNAL
831 decl_visibility = Visibility.EXTERN
832 proto = ['/* Prototype for -Wmissing-prototypes */']
833 # Add C++ guards in case somebody compiles the generated code
834 # with a C++ compiler
835 proto += ['G_BEGIN_DECLS']
836 proto += generate_prototype(retval, params, prefix, decl_visibility, False)
837 proto += ['G_END_DECLS']
838 outfile.write('\n'.join(proto))
841 body = generate_body(retval, params, prefix, False)
842 outfile.write('\n'.join(body))
843 outfile.write('\n\n')
846 if include_prototype:
847 # Declaration visibility
849 decl_visibility = Visibility.INTERNAL
851 decl_visibility = Visibility.EXTERN
852 proto = ['/* Prototype for -Wmissing-prototypes */']
853 # Add C++ guards here as well
854 proto += ['G_BEGIN_DECLS']
855 proto += generate_prototype(retval, params, prefix, decl_visibility, True)
856 proto += ['G_END_DECLS']
857 outfile.write('\n'.join(proto))
860 body = generate_body(retval, params, prefix, True)
861 outfile.write('\n'.join(body))
862 outfile.write('\n\n')
865 if __name__ == '__main__':
866 arg_parser = argparse.ArgumentParser(description='Generate signal marshallers for GObject')
867 arg_parser.add_argument('--prefix', metavar='STRING',
868 default='g_cclosure_user_marshal',
869 help='Specify marshaller prefix')
870 arg_parser.add_argument('--output', metavar='FILE',
871 type=argparse.FileType('w'),
873 help='Write output into the specified file')
874 arg_parser.add_argument('--skip-source',
876 help='Skip source location comments')
877 arg_parser.add_argument('--internal',
879 help='Mark generated functions as internal')
880 arg_parser.add_argument('--valist-marshallers',
882 help='Generate va_list marshallers')
883 arg_parser.add_argument('-v', '--version',
886 help='Print version information, and exit')
887 arg_parser.add_argument('--g-fatal-warnings',
889 dest='fatal_warnings',
890 help='Make warnings fatal')
891 arg_parser.add_argument('--include-header', metavar='HEADER', nargs='?',
893 dest='include_headers',
894 help='Include the specified header in the body')
895 arg_parser.add_argument('--pragma-once',
897 help='Use "pragma once" as the inclusion guard')
898 arg_parser.add_argument('-D',
902 help='Pre-processor define')
903 arg_parser.add_argument('-U',
905 dest='cpp_undefines',
907 help='Pre-processor undefine')
908 arg_parser.add_argument('files', metavar='FILE', nargs='*',
909 type=argparse.FileType('r'),
910 help='Files with lists of marshallers to generate, ' +
911 'or "-" for standard input')
912 arg_parser.add_argument('--prototypes',
914 help='Generate the marshallers prototype in the C code')
915 arg_parser.add_argument('--header',
917 help='Generate C headers')
918 arg_parser.add_argument('--body',
920 help='Generate C code')
922 group = arg_parser.add_mutually_exclusive_group()
923 group.add_argument('--stdinc',
925 dest='stdinc', default=True,
926 help='Include standard marshallers')
927 group.add_argument('--nostdinc',
928 action='store_false',
929 dest='stdinc', default=True,
930 help='Use standard marshallers')
932 group = arg_parser.add_mutually_exclusive_group()
933 group.add_argument('--quiet',
935 help='Only print warnings and errors')
936 group.add_argument('--verbose',
938 help='Be verbose, and include debugging information')
940 args = arg_parser.parse_args()
942 if args.show_version:
946 # Backward compatibility hack; some projects use both arguments to
947 # generate the marshallers prototype in the C source, even though
948 # it's not really a supported use case. We keep this behaviour by
949 # forcing the --prototypes and --body arguments instead. We make this
950 # warning non-fatal even with --g-fatal-warnings, as it's a deprecation
951 compatibility_mode = False
952 if args.header and args.body:
953 print_warning('Using --header and --body at the same time time is deprecated; ' +
954 'use --body --prototypes instead', False)
955 args.prototypes = True
957 compatibility_mode = True
960 generate_header_preamble(args.output,
962 std_includes=args.stdinc,
963 use_pragma=args.pragma_once)
965 generate_body_preamble(args.output,
966 std_includes=args.stdinc,
967 include_headers=args.include_headers,
968 cpp_defines=args.cpp_defines,
969 cpp_undefines=args.cpp_undefines)
971 seen_marshallers = set()
973 for infile in args.files:
975 print_info('Reading {}...'.format(infile.name))
981 if line == '\n' or line.startswith('#'):
984 matches = re.match(r'^([A-Z0-9]+)\s?:\s?([A-Z0-9,\s]+)$', line.strip())
985 if not matches or len(matches.groups()) != 2:
986 print_warning('Invalid entry: "{}"'.format(line.strip()), args.fatal_warnings)
989 if not args.skip_source:
990 location = '{} ({}:{:d})'.format(line.strip(), infile.name, line_count)
994 retval = matches.group(1).strip()
995 params = [x.strip() for x in matches.group(2).split(',')]
996 check_args(retval, params, args.fatal_warnings)
998 raw_marshaller = generate_marshaller_name(args.prefix, retval, params, False)
999 if raw_marshaller in seen_marshallers:
1001 print_info('Skipping repeated marshaller {}'.format(line.strip()))
1006 print_info('Generating declaration for {}'.format(line.strip()))
1007 generate_std_alias = False
1009 std_marshaller = generate_marshaller_name(STD_PREFIX, retval, params)
1010 if std_marshaller in GOBJECT_MARSHALLERS:
1012 print_info('Skipping default marshaller {}'.format(line.strip()))
1013 generate_std_alias = True
1015 marshaller = generate_marshaller_name(args.prefix, retval, params)
1016 if generate_std_alias:
1017 generate_marshaller_alias(args.output, marshaller, std_marshaller,
1018 source_location=location,
1019 include_va=args.valist_marshallers)
1021 generate_marshallers_header(args.output, retval, params,
1023 internal=args.internal,
1024 include_va=args.valist_marshallers,
1025 source_location=location)
1026 # If the marshaller is defined using a deprecated token, we want to maintain
1027 # compatibility and generate an alias for the old name pointing to the new
1029 if marshaller != raw_marshaller:
1031 print_info('Generating alias for deprecated tokens')
1032 generate_marshaller_alias(args.output, raw_marshaller, marshaller,
1033 include_va=args.valist_marshallers)
1036 print_info('Generating definition for {}'.format(line.strip()))
1037 generate_std_alias = False
1039 std_marshaller = generate_marshaller_name(STD_PREFIX, retval, params)
1040 if std_marshaller in GOBJECT_MARSHALLERS:
1042 print_info('Skipping default marshaller {}'.format(line.strip()))
1043 generate_std_alias = True
1044 marshaller = generate_marshaller_name(args.prefix, retval, params)
1045 if generate_std_alias:
1046 # We need to generate the alias if we are in compatibility mode
1047 if compatibility_mode:
1048 generate_marshaller_alias(args.output, marshaller, std_marshaller,
1049 source_location=location,
1050 include_va=args.valist_marshallers)
1052 generate_marshallers_body(args.output, retval, params,
1054 internal=args.internal,
1055 include_prototype=args.prototypes,
1056 include_va=args.valist_marshallers,
1057 source_location=location)
1058 if compatibility_mode and marshaller != raw_marshaller:
1060 print_info('Generating alias for deprecated tokens')
1061 generate_marshaller_alias(args.output, raw_marshaller, marshaller,
1062 include_va=args.valist_marshallers)
1064 seen_marshallers.add(raw_marshaller)
1067 generate_header_postamble(args.output, prefix=args.prefix, use_pragma=args.pragma_once)