1 # The MIT License (MIT)
3 # Copyright (c) 2014 Philippe Proulx <philippe.proulx@efficios.com>
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 from termcolor
import cprint
, colored
32 def _perror(msg
, exit_code
=1):
33 cprint('Error: {}'.format(msg
), 'red', attrs
=['bold'], file=sys
.stderr
)
38 cprint(':: {}'.format(msg
), 'blue', attrs
=['bold'], file=sys
.stderr
)
42 ap
= argparse
.ArgumentParser()
44 ap
.add_argument('-O', '--output', metavar
='OUTPUT', action
='store',
46 help='output directory of C files')
47 ap
.add_argument('-p', '--prefix', metavar
='PREFIX', action
='store',
49 help='custom prefix for C function and structure names')
50 ap
.add_argument('-s', '--static-inline', action
='store_true',
51 help='generate static inline C functions')
52 ap
.add_argument('-c', '--manual-clock', action
='store_true',
53 help='do not use a clock callback: pass clock value to tracing functions')
54 ap
.add_argument('metadata', metavar
='METADATA', action
='store',
55 help='CTF metadata input file')
58 args
= ap
.parse_args()
60 # validate output directory
61 if not os
.path
.isdir(args
.output
):
62 _perror('"{}" is not an existing directory'.format(args
.output
))
65 if not re
.match(r
'^[a-zA-Z_][a-zA-Z0-9_]*$', args
.prefix
):
66 _perror('"{}" is not a valid C identifier'.format(args
.prefix
))
68 # validate that metadata file exists
69 if not os
.path
.isfile(args
.metadata
):
70 _perror('"{}" is not an existing file'.format(args
.metadata
))
75 # TODO: prettify this function
76 def _validate_struct(struct
):
77 # just in case we call this with the wrong type
78 if type(struct
) is not pytsdl
.tsdl
.Struct
:
79 raise RuntimeError('expecting a struct')
81 # make sure inner structures are at least byte-aligned
82 if _get_obj_alignment(struct
) < 8:
83 raise RuntimeError('inner struct must be at least byte-aligned')
86 for name
, ftype
in struct
.fields
.items():
87 if type(ftype
) is pytsdl
.tsdl
.Sequence
:
88 raise RuntimeError('field "{}" is a dynamic array (not allowed here)'.format(name
))
89 elif type(ftype
) is pytsdl
.tsdl
.Array
:
90 # we need to check every element type until we find a terminal one
92 element
= ftype
.element
95 if type(element
) is pytsdl
.tsdl
.Sequence
:
96 raise RuntimeError('field "{}" contains a dynamic array (not allowed here)'.format(name
))
97 elif type(element
) is pytsdl
.tsdl
.Variant
:
98 raise RuntimeError('field "{}" contains a variant (unsupported)'.format(name
))
99 elif type(element
) is pytsdl
.tsdl
.String
:
100 raise RuntimeError('field "{}" contains a string (not allowed here)'.format(name
))
101 elif type(element
) is pytsdl
.tsdl
.Struct
:
102 _validate_struct(element
)
103 elif type(element
) is pytsdl
.tsdl
.Integer
:
104 if _get_integer_size(element
) > 64:
105 raise RuntimeError('integer field "{}" larger than 64-bit'.format(name
))
106 elif type(element
) is pytsdl
.tsdl
.FloatingPoint
:
107 if _get_floating_point_size(element
) > 64:
108 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(name
))
109 elif type(element
) is pytsdl
.tsdl
.Enum
:
110 if _get_enum_size(element
) > 64:
111 raise RuntimeError('enum field "{}" larger than 64-bit'.format(name
))
113 if type(element
) is pytsdl
.tsdl
.Array
:
114 # still an array, continue
115 element
= element
.element
117 # found the terminal element
119 elif type(ftype
) is pytsdl
.tsdl
.Variant
:
120 raise RuntimeError('field "{}" is a variant (unsupported)'.format(name
))
121 elif type(ftype
) is pytsdl
.tsdl
.String
:
122 raise RuntimeError('field "{}" is a string (not allowed here)'.format(name
))
123 elif type(ftype
) is pytsdl
.tsdl
.Struct
:
124 _validate_struct(ftype
)
125 elif type(ftype
) is pytsdl
.tsdl
.Integer
:
126 if _get_integer_size(ftype
) > 64:
127 raise RuntimeError('integer field "{}" larger than 64-bit'.format(name
))
128 elif type(ftype
) is pytsdl
.tsdl
.FloatingPoint
:
129 if _get_floating_point_size(ftype
) > 64:
130 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(name
))
131 elif type(ftype
) is pytsdl
.tsdl
.Enum
:
132 if _get_enum_size(ftype
) > 64:
133 raise RuntimeError('enum field "{}" larger than 64-bit'.format(name
))
136 def _validate_context_field(struct
):
137 if type(struct
) is not pytsdl
.tsdl
.Struct
:
138 raise RuntimeError('expecting a struct')
140 for name
, ftype
in struct
.fields
.items():
141 if type(ftype
) is pytsdl
.tsdl
.Variant
:
142 raise RuntimeError('field "{}" is a variant (unsupported)'.format(name
))
143 elif type(ftype
) is pytsdl
.tsdl
.Struct
:
144 # validate inner structure against barectf constraints
145 _validate_struct(ftype
)
148 def _validate_integer(integer
, size
=None, align
=None, signed
=None):
149 if type(integer
) is not pytsdl
.tsdl
.Integer
:
150 raise RuntimeError('expected integer')
153 if integer
.size
!= size
:
154 raise RuntimeError('expected {}-bit integer'.format(size
))
156 if align
is not None:
157 if integer
.align
!= align
:
158 raise RuntimeError('expected integer with {}-bit alignment'.format(align
))
160 if signed
is not None:
161 if integer
.signed
!= signed
:
162 raise RuntimeError('expected {} integer'.format('signed' if signed
else 'unsigned'))
165 def _validate_packet_header(packet_header
):
167 _validate_struct(packet_header
)
168 except RuntimeError as e
:
169 _perror('packet header: {}'.format(e
))
171 # magic must be the first field
172 if 'magic' in packet_header
.fields
:
173 if list(packet_header
.fields
.keys())[0] != 'magic':
174 _perror('packet header: "magic" must be the first field')
176 _perror('packet header: missing "magic" field')
178 # magic must be a 32-bit unsigned integer, 32-bit aligned
180 _validate_integer(packet_header
['magic'], 32, 32, False)
181 except RuntimeError as e
:
182 _perror('packet header: "magic": {}'.format(e
))
184 # mandatory stream_id
185 if 'stream_id' not in packet_header
.fields
:
186 _perror('packet header: missing "stream_id" field')
188 # stream_id must be an unsigned integer
190 _validate_integer(packet_header
['stream_id'], signed
=False)
191 except RuntimeError as e
:
192 _perror('packet header: "stream_id": {}'.format(e
))
195 def _dot_name_to_str(name
):
196 return '.'.join(name
)
199 def _compare_integers(int1
, int2
):
200 if type(int1
) is not pytsdl
.tsdl
.Integer
:
203 if type(int2
) is not pytsdl
.tsdl
.Integer
:
206 size
= int1
.size
== int2
.size
207 align
= int1
.align
== int2
.align
208 cmap
= int1
.map == int2
.map
209 base
= int1
.base
== int2
.base
210 encoding
= int1
.encoding
== int2
.encoding
211 signed
= int1
.signed
== int2
.signed
212 comps
= (size
, align
, cmap
, base
, encoding
, signed
)
214 # True means 1 for sum()
215 return sum(comps
) == len(comps
)
218 def _validate_packet_context(doc
, stream
):
219 packet_context
= stream
.packet_context
223 _validate_struct(packet_context
)
224 except RuntimeError as e
:
225 _perror('stream {}: packet context: {}'.format(sid
, e
))
227 fields
= packet_context
.fields
229 # if timestamp_begin exists, timestamp_end must exist
230 if 'timestamp_begin' in fields
or 'timestamp_end' in fields
:
231 if 'timestamp_begin' not in fields
or 'timestamp_end' not in fields
:
232 _perror('stream {}: packet context: "timestamp_begin" must exist if "timestamp_end" exists'.format(sid
))
234 # timestamp_begin and timestamp_end must have the same integer
235 # as the event header's timestamp field (should exist by now)
236 timestamp
= stream
.event_header
['timestamp']
238 if not _compare_integers(fields
['timestamp_begin'], timestamp
):
239 _perror('stream {}: packet context: "timestamp_begin": integer type different from event header\'s "timestamp" field'.format(sid
))
241 if not _compare_integers(fields
['timestamp_end'], timestamp
):
242 _perror('stream {}: packet context: "timestamp_end": integer type different from event header\'s "timestamp" field'.format(sid
))
244 # content_size must exist and be an unsigned integer
245 if 'content_size' not in fields
:
246 _perror('stream {}: packet context: missing "content_size" field'.format(sid
))
249 _validate_integer(fields
['content_size'], 32, 32, False)
252 _validate_integer(fields
['content_size'], 64, 64, False)
254 _perror('stream {}: packet context: "content_size": expecting unsigned 32-bit/64-bit integer'.format(sid
))
256 # packet_size must exist and be an unsigned integer
257 if 'packet_size' not in fields
:
258 _perror('stream {}: packet context: missing "packet_size" field'.format(sid
))
261 _validate_integer(fields
['packet_size'], 32, 32, False)
264 _validate_integer(fields
['packet_size'], 64, 64, False)
266 _perror('stream {}: packet context: "packet_size": expecting unsigned 32-bit/64-bit integer'.format(sid
))
268 # if cpu_id exists, must be an unsigned integer
269 if 'cpu_id' in fields
:
271 _validate_integer(fields
['cpu_id'], signed
=False)
272 except RuntimeError as e
:
273 _perror('stream {}: packet context: "cpu_id": {}'.format(sid
, e
))
276 def _validate_event_header(doc
, stream
):
277 event_header
= stream
.event_header
281 _validate_struct(event_header
)
282 except RuntimeError as e
:
283 _perror('stream {}: event header: {}'.format(sid
, e
))
285 fields
= event_header
.fields
287 # id must exist and be an unsigned integer
288 if 'id' not in fields
:
289 _perror('stream {}: event header: missing "id" field'.format(sid
))
292 _validate_integer(fields
['id'], signed
=False)
293 except RuntimeError as e
:
294 _perror('stream {}: "id": {}'.format(sid
, format(e
)))
297 # timestamp must exist, be an unsigned integer and be mapped to a valid clock
298 if 'timestamp' not in fields
:
299 _perror('stream {}: event header: missing "timestamp" field'.format(sid
))
302 _validate_integer(fields
['timestamp'], signed
=False)
303 except RuntimeError as e
:
304 _perror('stream {}: "timestamp": {}'.format(sid
, format(e
)))
307 def _validate_stream_event_context(doc
, stream
):
308 stream_event_context
= stream
.event_context
311 if stream_event_context
is None:
315 _validate_context_field(stream_event_context
)
316 except RuntimeError as e
:
317 _perror('stream {}: event context: {}'.format(sid
, e
))
320 def _validate_all_scopes(doc
):
322 _validate_packet_header(doc
.trace
.packet_header
)
325 for stream_id
, stream
in doc
.streams
.items():
326 _validate_event_header(doc
, stream
)
327 _validate_packet_context(doc
, stream
)
328 _validate_stream_event_context(doc
, stream
)
331 def _validate_metadata(doc
):
332 _validate_all_scopes(doc
)
342 def _get_alignment(at
, align
):
343 return (at
+ align
- 1) & -align
346 def _offset_vars_tree_to_vars(offset_vars_tree
, prefix
='',
347 offset_vars
=collections
.OrderedDict()):
348 for name
, offset
in offset_vars_tree
.items():
349 varname
= '{}_{}'.format(prefix
, name
)
351 if isinstance(offset
, dict):
352 _offset_vars_tree_to_vars(offset
, varname
, offset_vars
)
354 offset_vars
[varname
] = offset
359 # returns the size of a struct with _static size_
360 def _get_struct_size(struct
, offset_vars_tree
=collections
.OrderedDict(),
364 for fname
, ftype
in struct
.fields
.items():
365 field_alignment
= _get_obj_alignment(ftype
)
366 offset
= _get_alignment(offset
, field_alignment
)
368 if type(ftype
) is pytsdl
.tsdl
.Struct
:
369 offset_vars_tree
[fname
] = collections
.OrderedDict()
370 sz
= _get_struct_size(ftype
, offset_vars_tree
[fname
],
371 base_offset
+ offset
)
373 # only integers may act as sequence lengths
374 if type(ftype
) is pytsdl
.tsdl
.Integer
:
375 offset_vars_tree
[fname
] = base_offset
+ offset
377 sz
= _get_obj_size(ftype
)
384 def _get_array_size(array
):
385 element
= array
.element
387 # effective size of one element includes its alignment after its size
388 size
= _get_obj_size(element
)
389 align
= _get_obj_alignment(element
)
391 return _get_alignment(size
, align
) * array
.length
394 def _get_enum_size(enum
):
395 return _get_obj_size(enum
.integer
)
398 def _get_floating_point_size(floating_point
):
399 return floating_point
.exp_dig
+ floating_point
.mant_dig
402 def _get_integer_size(integer
):
407 pytsdl
.tsdl
.Integer
: _get_integer_size
,
408 pytsdl
.tsdl
.Enum
: _get_enum_size
,
409 pytsdl
.tsdl
.FloatingPoint
: _get_floating_point_size
,
410 pytsdl
.tsdl
.Array
: _get_array_size
,
414 def _get_obj_size(obj
):
415 return _obj_size_cb
[type(obj
)](obj
)
418 def _get_struct_alignment(struct
):
419 if struct
.align
is not None:
424 for fname
, ftype
in struct
.fields
.items():
425 cur_align
= max(_get_obj_alignment(ftype
), cur_align
)
430 def _get_integer_alignment(integer
):
434 def _get_floating_point_alignment(floating_point
):
435 return floating_point
.align
438 def _get_enum_alignment(enum
):
439 return _get_obj_alignment(enum
.integer
)
442 def _get_string_alignment(string
):
445 def _get_array_alignment(array
):
446 return _get_obj_alignment(array
.element
)
449 def _get_sequence_alignment(sequence
):
450 return _get_obj_alignment(sequence
.element
)
453 _obj_alignment_cb
= {
454 pytsdl
.tsdl
.Struct
: _get_struct_alignment
,
455 pytsdl
.tsdl
.Integer
: _get_integer_alignment
,
456 pytsdl
.tsdl
.Enum
: _get_enum_alignment
,
457 pytsdl
.tsdl
.FloatingPoint
: _get_floating_point_alignment
,
458 pytsdl
.tsdl
.Array
: _get_array_alignment
,
459 pytsdl
.tsdl
.Sequence
: _get_sequence_alignment
,
460 pytsdl
.tsdl
.String
: _get_string_alignment
,
464 def _get_obj_alignment(obj
):
465 return _obj_alignment_cb
[type(obj
)](obj
)
469 _CTX_BUF
= 'ctx->buf'
470 _CTX_BUF_AT
= '{}[{} >> 3]'.format(_CTX_BUF
, _CTX_AT
)
471 _CTX_BUF_AT_ADDR
= '&{}'.format(_CTX_BUF_AT
)
472 _ALIGN_OFFSET
= 'ALIGN_OFFSET'
475 def _field_name_to_param_name(fname
):
476 return 'param_{}'.format(fname
)
479 def _get_integer_param_type(integer
):
480 signed
= 'u' if not integer
.signed
else ''
482 if integer
.size
== 8:
484 elif integer
.size
== 16:
486 elif integer
.size
== 32:
488 elif integer
.size
== 64:
491 # if the integer is signed and of uncommon size, the sign bit is
492 # at a custom position anyway so we use a 64-bit unsigned
498 if integer
.size
< 16:
500 elif integer
.size
< 32:
502 elif integer
.size
< 64:
507 return '{}int{}_t'.format(signed
, sz
)
510 def _get_enum_param_type(enum
):
511 return _get_obj_param_type(enum
.integer
)
514 def _get_floating_point_param_type(fp
):
515 if fp
.exp_dig
== 8 and fp
.mant_dig
== 24 and fp
.align
== 32:
517 elif fp
.exp_dig
== 11 and fp
.mant_dig
== 53 and fp
.align
== 64:
523 _obj_param_type_cb
= {
524 pytsdl
.tsdl
.Struct
: lambda obj
: 'const void*',
525 pytsdl
.tsdl
.Integer
: _get_integer_param_type
,
526 pytsdl
.tsdl
.Enum
: _get_enum_param_type
,
527 pytsdl
.tsdl
.FloatingPoint
: _get_floating_point_param_type
,
528 pytsdl
.tsdl
.Array
: lambda obj
: 'const void*',
529 pytsdl
.tsdl
.Sequence
: lambda obj
: 'const void*',
530 pytsdl
.tsdl
.String
: lambda obj
: 'const char*',
534 def _get_obj_param_type(obj
):
535 return _obj_param_type_cb
[type(obj
)](obj
)
546 def _write_field_struct(doc
, fname
, struct
):
547 size
= _get_struct_size(struct
)
548 size_bytes
= _get_alignment(size
, 8) // 8
550 dst
= _CTX_BUF_AT_ADDR
551 src
= _field_name_to_param_name(fname
)
554 # memcpy() is safe since barectf requires inner structures
556 _CLine('memcpy({}, {}, {});'.format(dst
, src
, size_bytes
)),
557 _CLine('{} += {};'.format(_CTX_AT
, size
)),
562 pytsdl
.tsdl
.ByteOrder
.BE
: 'be',
563 pytsdl
.tsdl
.ByteOrder
.LE
: 'le',
567 def _write_field_integer(doc
, fname
, integer
):
568 bo
= _bo_suffixes_map
[integer
.byte_order
]
570 t
= _get_obj_param_type(integer
)
572 length
= _get_obj_size(integer
)
573 value
= _field_name_to_param_name(fname
)
574 fmt
= 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
577 _CLine(fmt
.format(bo
, ptr
, t
, start
, length
, value
)),
578 _CLine('{} += {};'.format(_CTX_AT
, length
))
582 def _write_field_enum(doc
, fname
, enum
):
583 return _write_field_obj(doc
, fname
, enum
.integer
)
586 def _write_field_floating_point(doc
, fname
, floating_point
):
587 bo
= _bo_suffixes_map
[floating_point
.byte_order
]
589 t
= _get_obj_param_type(floating_point
)
591 length
= _get_obj_size(floating_point
)
592 value
= _field_name_to_param_name(fname
)
593 fmt
= 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
596 _CLine(fmt
.format(bo
, ptr
, t
, start
, length
, value
)),
597 _CLine('{} += {};'.format(_CTX_AT
, length
))
601 def _write_field_array(doc
, fname
, array
):
604 # array index variable declaration
605 iv
= 'ia_{}'.format(fname
)
606 lines
.append(_CLine('uint32_t {};'.format(iv
)))
608 # for loop using array's static length
609 line
= 'for ({iv} = 0; {iv} < {l}; ++{iv}) {{'.format(iv
=iv
, l
=array
.length
)
610 lines
.append(_CLine(line
))
612 # for loop statements
613 for_block
= _CBlock()
615 # align bit index before writing to the buffer
616 element_align
= _get_obj_alignment(array
.element
)
617 line
= '{}({}, {});'.format(_ALIGN_OFFSET
, _CTX_AT
, element_align
)
618 for_block
.append(_CLine(line
))
620 # write element to the buffer
621 for_block
+= _write_field_obj(doc
, fname
, array
.element
)
622 lines
.append(for_block
)
625 lines
.append(_CLine('}'))
630 def _write_field_sequence(doc
, fname
, sequence
):
632 _CLine('would write sequence here;'),
636 def _write_field_string(doc
, fname
, string
):
639 # source pointer (function parameter)
640 src
= _field_name_to_param_name(fname
)
642 # string index variable declaration
643 iv
= 'is_{}'.format(fname
)
644 lines
.append(_CLine('uint32_t {};'.format(iv
)))
646 # for loop; loop until the end of the source string is reached
647 fmt
= "for ({iv} = 0; {src}[{iv}] != '\\0'; ++{iv}, {ctxat} += 8) {{"
648 lines
.append(_CLine(fmt
.format(iv
=iv
, src
=src
, ctxat
=_CTX_AT
)))
650 # for loop statements
651 for_block
= _CBlock()
653 # write byte to the buffer
654 line
= '{} = {}[{}]'.format(_CTX_BUF_AT
, src
, iv
)
655 for_block
.append(_CLine(line
))
658 lines
.append(for_block
)
659 lines
.append(_CLine('}'))
661 # write NULL character to the buffer
662 lines
.append(_CLine("{} = '\\0';".format(_CTX_BUF_AT
)))
663 lines
.append(_CLine('{} += 8;'.format(_CTX_AT
)))
668 _write_field_obj_cb
= {
669 pytsdl
.tsdl
.Struct
: _write_field_struct
,
670 pytsdl
.tsdl
.Integer
: _write_field_integer
,
671 pytsdl
.tsdl
.Enum
: _write_field_enum
,
672 pytsdl
.tsdl
.FloatingPoint
: _write_field_floating_point
,
673 pytsdl
.tsdl
.Array
: _write_field_array
,
674 pytsdl
.tsdl
.Sequence
: _write_field_sequence
,
675 pytsdl
.tsdl
.String
: _write_field_string
,
679 def _write_field_obj(doc
, fname
, ftype
):
680 return _write_field_obj_cb
[type(ftype
)](doc
, fname
, ftype
)
683 def _struct_to_c_lines(doc
, struct
):
686 for fname
, ftype
in struct
.fields
.items():
687 pname
= _field_name_to_param_name(fname
)
688 align
= _get_obj_alignment(ftype
)
690 # align bit index before writing to the buffer
691 line
= '{}({}, {});'.format(_ALIGN_OFFSET
, _CTX_AT
, align
)
694 # write offset variables
695 if type(ftype
) is pytsdl
.tsdl
.Struct
:
696 offset_vars_tree
= collections
.OrderedDict()
697 _get_struct_size(ftype
, offset_vars_tree
)
698 offset_vars
= _offset_vars_tree_to_vars(offset_vars_tree
)
700 # as many offset as there are child fields because a future
701 # sequence could refer to any of those fields
702 for lname
, offset
in offset_vars
.items():
703 fmt
= 'uint32_t off_{}_{} = {} + {};'
704 line
= fmt
.format(fname
, lname
, _CTX_AT
, offset
);
705 lines
.append(_CLine(line
))
707 # offset of this simple field is the current bit index
708 line
= 'uint32_t off_{} = {};'.format(fname
, _CTX_AT
)
709 lines
.append(_CLine(line
))
711 lines
+= _write_field_obj(doc
, fname
, ftype
)
716 def gen_barectf(metadata
, output
, prefix
, static_inline
, manual_clock
):
717 # open CTF metadata file
719 with
open(metadata
) as f
:
722 _perror('cannot open/read CTF metadata file "{}"'.format(metadata
))
725 parser
= pytsdl
.parser
.Parser()
728 doc
= parser
.parse(tsdl
)
729 except pytsdl
.parser
.ParseError
as e
:
730 _perror('parse error: {}'.format(e
))
732 # validate CTF metadata against barectf constraints
733 _validate_metadata(doc
)
737 lines
= _struct_to_c_lines(doc
, doc
.streams
[0].get_event(0).fields
)
739 print(json
.dumps(lines
, indent
=4))
744 gen_barectf(args
.metadata
, args
.output
, args
.prefix
, args
.static_inline
,