Add documentation
[deliverable/exatracer.git] / scripts / lttng-ust-auto-api
CommitLineData
74c0b9b3
OD
1#!/usr/bin/env python3
2#
3# SPDX-License-Identifier: MIT
4#
5# Copyright (c) 2023 EfficiOS, Inc.
6#
7# Author: Olivier Dion <odion@efficios.com>
8#
c75d6f3f 9# Auto-generate lttng-ust tracepoints for a public API.
74c0b9b3
OD
10#
11# Require: python-clang (libclang)
12
13import argparse
14import re
15import os
16import subprocess
17
18from string import Template
19
20import clang.cindex
21
22COMMON_PREFIX = None
23IGNORE = set()
24PROVIDER = None
25
26# LTTNG_UST_TP_ARGS is limited to 10 arguments. Since we introduce two
27# arguments of our own (thread-id and local-id), the maximum is 8.
28#
29# If a function has more arguments than this limit, all arguments -- at the
30# exception of the IDs -- will be passed through a data structure instead.
31MAX_TP_ARGS_COUNT = 8
32
c75d6f3f 33# Compatibility layer for Python3 < 3.9
2d9baab4
OD
34def remove_prefix(string, prefix):
35 if string.startswith(prefix):
36 return string[len(prefix):]
37 return string
38
74c0b9b3
OD
39class EnumValue:
40
41 def __init__(self, ev):
42 self.name = ev.spelling
43 self.value = ev.enum_value
44
45class EnumType:
46
47 def __init__(self, en, name=None):
48 self.name = name or en.spelling
49 self.values = [EnumValue(ev) for ev in en.get_children()]
50 self.en = en
51
52class Typedef:
53
54 def __init__(self, spelling, value):
55 self.spelling = spelling
56 self.value = value
57
58class ArgumentType:
59
60 integer_set = {
61 clang.cindex.TypeKind.UCHAR,
62 clang.cindex.TypeKind.USHORT,
63 clang.cindex.TypeKind.UINT,
64 clang.cindex.TypeKind.ULONG,
65 clang.cindex.TypeKind.ULONGLONG,
66 clang.cindex.TypeKind.SHORT,
67 clang.cindex.TypeKind.INT,
68 clang.cindex.TypeKind.LONG,
69 clang.cindex.TypeKind.LONGLONG,
70 }
71
72 float_set = {
73 clang.cindex.TypeKind.FLOAT,
74 clang.cindex.TypeKind.DOUBLE,
75 }
76
77 address_set = {
78 clang.cindex.TypeKind.POINTER,
79 clang.cindex.TypeKind.INCOMPLETEARRAY,
80 }
81
82 def __init__(self, arg, name_prefix="", expr_prefix=""):
83 self.type = arg.type
84 self.arg = arg
85 self.const = ""
86 self.name_prefix = name_prefix
87 self.expr_prefix = expr_prefix
88
89 if self.kind() == clang.cindex.TypeKind.POINTER:
90 if self.type.get_pointee().is_const_qualified():
91 self.const = "const "
92 elif self.type.is_const_qualified():
93 self.const = "const "
94
95 def name(self):
96 return self.arg.spelling
97
98 def type_name(self):
99 if self.kind() == clang.cindex.TypeKind.INCOMPLETEARRAY:
100 return self.const + re.sub(r"\[[0-9]*\]", "*", self.type.spelling)
101 if self.kind() == clang.cindex.TypeKind.POINTER:
102 return f"{self.const}void *"
103 return self.const + self.type.spelling
104
105 def kind(self):
106 return self.type.get_canonical().kind
107
108 def to_lttng_field(self):
109 if self.name() == "reserved":
110 return ""
111 elif self.kind() in ArgumentType.address_set:
112 return f"lttng_ust_field_integer_hex(uintptr_t, {self.name_prefix}{self.name()}, (uintptr_t){self.expr_prefix}{self.name()})"
113 elif self.kind() in ArgumentType.integer_set:
114 return f"lttng_ust_field_integer({self.type_name()}, {self.name_prefix}{self.name()}, {self.expr_prefix}{self.name()})"
115 elif self.kind() in ArgumentType.float_set:
116 return f"lttng_ust_field_float({self.type_name()}, {self.name_prefix}{self.name()}, {self.expr_prefix}{self.name()})"
117 elif self.kind() == clang.cindex.TypeKind.ENUM:
2d9baab4 118 enum_name = remove_prefix(self.type_name(), "enum ")
74c0b9b3
OD
119 return f"lttng_ust_field_enum({PROVIDER}, {enum_name}, int, {self.name_prefix}{self.name()}, {self.expr_prefix}{self.name()})"
120 elif self.kind() == clang.cindex.TypeKind.RECORD:
121 return [
122 ArgumentType(field, f"{self.name()}_", f"{self.expr_prefix}{self.name()}.").to_lttng_field()
123 for field in self.type.get_canonical().get_fields()
124 ]
125 else:
126 raise Exception("Unsupported kind: %s" % self.kind())
127
128class FunctionType:
129
130 struct_tpl = Template("""
131$name {
132 $fields
133};
134""")
135
136 def __init__(self, fn):
137 self.name = fn.spelling
138 self.args = [ArgumentType(arg) for arg in fn.get_arguments()]
139 self.fn = fn
140
141 def tp_args(self):
142 if len(self.args) == 0:
143 return ""
144 elif len(self.args) > MAX_TP_ARGS_COUNT:
145 return ",\n " + f"{self.arguments_struct_name()} *, lttng_args"
146 else:
147 return ",\n " + ",\n ".join([f"{arg.type_name()}, {arg.name()}"
148 for arg in self.args])
149
150 def tp_fields(self):
151 if len(self.args) == 0:
152 return ""
153 elif len(self.args) > MAX_TP_ARGS_COUNT:
154 packed_args = [ArgumentType(arg.arg, "", "lttng_args->") for arg in self.args]
155 return "\n ".join(flatten([arg.to_lttng_field()
156 for arg in packed_args]))
157 else:
158 return "\n ".join(flatten([arg.to_lttng_field()
159 for arg in self.args]))
160 def get_return_type_name(self):
161 return self.fn.type.get_result().spelling
162
163 def ctor_params(self):
164 if len(self.args) == 0:
165 return ""
166 elif len(self.args) > MAX_TP_ARGS_COUNT:
167 return ", &lttng_args"
168 else:
169 return ", " + ", ".join(arg.name() for arg in self.args)
170
171 def arguments_struct_variable(self):
172 if len(self.args) > MAX_TP_ARGS_COUNT:
173 return "%s lttng_args = {%s};" % (self.arguments_struct_name(),
174 ", ".join([arg.name() for arg in self.args]))
175 else:
176 return f"/* {self.arguments_struct_name()} lttng_args */"
177
178
179 def arguments_struct_name(self):
180 return f"struct lttng_arguments_of_{self.name}"
181
182 def arguments_struct(self):
183 if len(self.args) > MAX_TP_ARGS_COUNT:
184 return self.struct_tpl.substitute(name=self.arguments_struct_name(),
185 fields="\n ".join([
186 f"{arg.type_name()} {arg.name()};"
187 for arg in self.args
188 ]))
189 else:
190 return ""
191
192def flatten(lst):
193 new_lst = []
194 for e in lst:
195 if isinstance(e, list):
196 for e in flatten(e):
197 new_lst.append(e)
198 else:
199 new_lst.append(e)
200 return new_lst
201
202def list_function_declarations(root):
203 return [ child
204 for child in root.get_children()
205 if child.kind == clang.cindex.CursorKind.FUNCTION_DECL ]
206
207def list_enum_declarations(root):
208 return [
209 child
210 for child in root.get_children()
211 if child.kind == clang.cindex.CursorKind.ENUM_DECL
212 ]
213
214def list_typedef_enums(root):
215 enums = []
216 for child in root.get_children():
217 if child.kind == clang.cindex.CursorKind.TYPEDEF_DECL:
218 maybe_enum = child.underlying_typedef_type.get_declaration()
219 if maybe_enum.kind == clang.cindex.CursorKind.ENUM_DECL:
220 enums.append(Typedef(child.spelling, maybe_enum))
221 return enums
222
223def search_header_in(name, paths):
224 for path in paths.split(":"):
225 for dirpath, _, files in os.walk(path, followlinks=True):
226 for file in files:
227 if file == name:
228 return os.path.join(dirpath, file)
229 return None
230
231def search_c_header(name):
232 return search_header_in(name, os.environ["C_INCLUDE_PATH"])
233
234def search_cxx_header(name):
235 return search_header_in(name, os.environ["CPLUS_INCLUDE_PATH"])
236
237def get_system_include_paths():
238
239 clang_args = ["clang", "-v", "-c", "-xc", "/dev/null", "-o", "/dev/null"]
240 paths = []
241
242 with subprocess.Popen(clang_args, stderr=subprocess.PIPE,
243 encoding="ascii") as proc:
244 start_sys_search = False
245 for line in proc.stderr:
246 if start_sys_search:
247 if line == "End of search list.\n":
248 break
249 paths.append("-isystem")
250 paths.append(line.strip())
251 elif line == "#include <...> search starts here:\n":
252 start_sys_search = True
253
254 return paths
255
256def parse_header(header_file, includes, defines,
257 required_c_headers, required_cxx_headers):
258
259 args = get_system_include_paths()
260
261 if includes:
262 for inc in includes:
263 args.append("-I")
264 args.append(inc)
265
266 if defines:
267 for d in defines:
268 args.append("-D")
269 args.append(d)
270
271 for header in required_c_headers:
272 found = search_c_header(header)
273 if found:
274 args.append("-I")
275 args.append(os.path.dirname(found))
276
277 for header in required_cxx_headers:
278 found = search_cxx_header(header)
279 if found:
280 args.append("-I")
281 args.append(os.path.dirname(found))
282
283 tu = clang.cindex.Index.create().parse(header_file, args=args)
284
285 for d in tu.diagnostics:
286 print(f"WARNING: {d}")
287
288 return tu.cursor
289
290def list_functions(root):
291 return [
292 FunctionType(fn)
293 for fn in list_function_declarations(root)
294 if fn.spelling.startswith(COMMON_PREFIX) and fn.spelling not in IGNORE
295 ]
296
297def list_enums(root):
298
299 enums = [
300 en
301 for en in list_enum_declarations(root)
302 if en.spelling.startswith(COMMON_PREFIX) and en.spelling not in IGNORE
303 ]
304
305 typedef_enums = [
306 typedef
307 for typedef in list_typedef_enums(root)
308 if typedef.spelling.startswith(COMMON_PREFIX) and
309 typedef.spelling not in IGNORE and
310 typedef.value.get_definition() not in enums
311 ]
312
313 all_enums = ([ EnumType(e) for e in enums ] +
314 [ EnumType(td.value, td.spelling) for td in typedef_enums])
315
316 return all_enums
317
318def generate_tracepoint_definitions(function_declarations, enum_declarations,
319 api_file, output_defs, output_interface,
320 header_guard):
321 defs_tpl = Template("""/* Auto-generated file! */
322#undef LTTNG_UST_TRACEPOINT_PROVIDER
323#define LTTNG_UST_TRACEPOINT_PROVIDER $provider
324
325#undef LTTNG_UST_TRACEPOINT_INCLUDE
326#define LTTNG_UST_TRACEPOINT_INCLUDE "$output_defs"
327
328#if !defined($header_guard)
329#include <$api_file>
330$pass_by_struct
331#endif
332
333#if !defined($header_guard) || defined(LTTNG_UST_TRACEPOINT_HEADER_MULTI_READ)
334#define $header_guard
335
336#include <lttng/tracepoint.h>
337
338$enum_definitions
339$tracepoint_definitions
340
341#endif /* $header_guard */
342
343#include <lttng/tracepoint-event.h>
344""")
345
346 interface_tpl = Template("""/* Auto-generated file! */
347#ifndef ${header_guard}_IMPL
348#define ${header_guard}_IMPL
349
350#include "${output_defs}"
351
352#endif /* ${header_guard}_IMPL */
353""")
354
355 tp_tpl = Template("""
356LTTNG_UST_TRACEPOINT_EVENT(
357 $provider,
358 ${name}_entry,
359 LTTNG_UST_TP_ARGS(
360 uint64_t, lttng_thread_id,
361 uint64_t, lttng_local_id$tp_args
362 ),
363 LTTNG_UST_TP_FIELDS(
364 lttng_ust_field_integer(uint64_t, lttng_thread_id, lttng_thread_id)
365 lttng_ust_field_integer(uint64_t, lttng_local_id, lttng_local_id)
366 $tp_fields
367 )
368)
369""")
370
371 tp_ret_tpl = Template("""
372LTTNG_UST_TRACEPOINT_EVENT(
373 $provider,
374 ${name}_exit,
375 LTTNG_UST_TP_ARGS(
376 uint64_t, lttng_thread_id,
377 uint64_t, lttng_local_id,
378 int, lttng_has_ret,
379 $ret_type, lttng_ret
380 ),
381 LTTNG_UST_TP_FIELDS(
382 lttng_ust_field_integer(uint64_t, lttng_thread_id, lttng_thread_id)
383 lttng_ust_field_integer(uint64_t, lttng_local_id, lttng_local_id)
384 lttng_ust_field_integer(int, lttng_has_ret, lttng_has_ret)
385 lttng_ust_field_integer($ret_type, lttng_ret, lttng_ret)
386 )
387)
388""")
389
390 tp_void_tpl = Template("""
391LTTNG_UST_TRACEPOINT_EVENT(
392 $provider,
393 ${name}_exit,
394 LTTNG_UST_TP_ARGS(
395 uint64_t, lttng_thread_id,
396 uint64_t, lttng_local_id,
397 int, lttng_has_ret
398 ),
399 LTTNG_UST_TP_FIELDS(
400 lttng_ust_field_integer(uint64_t, lttng_thread_id, lttng_thread_id)
401 lttng_ust_field_integer(uint64_t, lttng_local_id, lttng_local_id)
402 lttng_ust_field_integer(int, lttng_has_ret, lttng_has_ret)
403 )
404)
405""")
406 enum_tpl = Template("""
407LTTNG_UST_TRACEPOINT_ENUM($provider, $name,
408 LTTNG_UST_TP_ENUM_VALUES(
409 $values
410 )
411)
412""")
413 with open(output_defs, "w") as output:
414 definitions = []
415 for fn in function_declarations:
416 ret_type = fn.get_return_type_name()
417 definitions.append(tp_tpl.substitute(provider=PROVIDER,
418 name=fn.name,
419 tp_args=fn.tp_args(),
420 tp_fields=fn.tp_fields()))
421 if ret_type == "void":
422 tpl = tp_void_tpl
423 else:
424 tpl = tp_ret_tpl
425
426 definitions.append(tpl.substitute(provider=PROVIDER,
427 name=fn.name,
428 ret_type=ret_type))
429
430 tracepoint_definitions = "\n".join(definitions)
431
432 enum_definitions = "\n".join([
433 enum_tpl.substitute(provider=PROVIDER,
434 name=en.name,
435 values="\n ".join([f'lttng_ust_field_enum_value("{ev.name}", {ev.value})'
436 for ev in en.values]))
437 for en in enum_declarations
438 ])
439
440 output.write(defs_tpl.substitute(provider=PROVIDER,
441 output_defs=output_defs,
442 header_guard=header_guard,
443 tracepoint_definitions=tracepoint_definitions,
444 enum_definitions=enum_definitions,
445 api_file=api_file,
446 pass_by_struct="".join([fn.arguments_struct()
447 for fn in function_declarations])))
448 with open(output_interface, "w") as output:
449 output.write(interface_tpl.substitute(header_guard=header_guard,
450 output_defs=output_defs,))
451
452def generate_tracepoint_classes(function_declarations, api_file, output_path, header_guard, namespace):
453 global_tpl = Template("""/* Auto-generated file! */
454#include <atomic>
455#include <cstdint>
456#include <$api_file>
457namespace $namespace {
458 struct unique_id {
459 uint64_t thread_id;
460 uint64_t local_id;
461 };
462
463 class id_generator {
464 static std::atomic<uint64_t> _thread_counter;
465 uint64_t _thread_id;
466 uint64_t _local_id;
467 public:
468 id_generator() {
469 _thread_id = _thread_counter++;
470 _local_id = 0;
471 }
472
473 unique_id next_id() {
474 return {
475 .thread_id = _thread_id,
476 .local_id = _local_id++,
477 };
478 }
479 };
480
481 extern thread_local id_generator generator;
482
483 template<typename RetType>
484 class base_api_object {
485 protected:
486 unique_id _id;
487 int _has_ret;
488 RetType _ret;
489 public:
490 void generate_id() {
491 _id = generator.next_id();
492 }
493
494 void mark_return(RetType ret) {
495 _ret = ret;
496 _has_ret = 1;
497 }
498 };
499
500 class base_api_object_void {
501 protected:
502 unique_id _id;
503 int _has_ret;
504 public:
505 void generate_id() {
506 _id = generator.next_id();
507 }
508
509 void mark_return(void) {
510 _has_ret = 1;
511 }
512 };
513
514$classes
515};
516""")
517
518 cls_ret_tpl = Template("""
519class api_object_$fn_name : public base_api_object<$ret_type>
520{
521public:
522 api_object_$fn_name($ctor_type_params) {
523 if (lttng_ust_tracepoint_enabled($provider, ${fn_name}_entry)) {
524 generate_id();
525 $pass_by_struct
526 lttng_ust_do_tracepoint($provider,
527 ${fn_name}_entry,
528 _id.thread_id,
529 _id.local_id$ctor_params);
530 }
531 }
532 ~api_object_$fn_name() {
533 if (lttng_ust_tracepoint_enabled($provider, ${fn_name}_exit)) {
534 lttng_ust_do_tracepoint($provider,
535 ${fn_name}_exit,
536 _id.thread_id,
537 _id.local_id,
538 _has_ret,
539 _ret);
540 }
541 }
542};
543""")
544
545 cls_void_tpl = Template("""
546class api_object_$fn_name : public base_api_object_void
547{
548public:
549 api_object_$fn_name($ctor_type_params) {
550 if (lttng_ust_tracepoint_enabled($provider, ${fn_name}_entry)) {
551 generate_id();
552 $pass_by_struct
553 lttng_ust_do_tracepoint($provider,
554 ${fn_name}_entry,
555 _id.thread_id,
556 _id.local_id$ctor_params);
557 }
558 }
559 ~api_object_$fn_name() {
560 if (lttng_ust_tracepoint_enabled($provider, ${fn_name}_exit)) {
561 lttng_ust_do_tracepoint($provider,
562 ${fn_name}_exit,
563 _id.thread_id,
564 _id.local_id,
565 _has_ret);
566 }
567 }
568};
569""")
570
571 with open(output_path, "w") as output:
572 classes = []
573 for fn in function_declarations:
574 ret_type = fn.get_return_type_name()
575 if ret_type == "void":
576 cls_tpl = cls_void_tpl
577 else:
578 cls_tpl = cls_ret_tpl
579 classes.append(cls_tpl.substitute(provider=PROVIDER,
580 fn_name=fn.name,
581 pass_by_struct=fn.arguments_struct_variable(),
582 ctor_type_params=", ".join([f"{arg.type_name()} {arg.name()}"
583 for arg in fn.args]),
584 ctor_params=fn.ctor_params(),
585 ret_type=ret_type))
586 output.write(global_tpl.substitute(api_file=api_file,
587 namespace=namespace,
588 classes="".join(classes)))
589
590def generate_tracepoint_emulated_classes(function_declarations, api_file, output_path,
591 header_guard, namespace):
592 global_tpl = Template("""/* Auto-generated file! */
593#include <stdint.h>
594#include <$api_file>
595#define ${NAMESPACE}_CAT_PRIMITIVE(A, B) A##B
596#define ${NAMESPACE}_CAT(A, B) ${NAMESPACE}_CAT_PRIMITIVE(A, B)
597
598struct ${namespace}_unique_id {
599 uint64_t thread_id;
600 uint64_t local_id;
601};
602
603struct ${namespace}_id_generator {
604 uint64_t thread_id;
605 uint64_t local_id;
606 int initialized;
607};
608
609extern uint64_t ${namespace}_id_generator_thread_counter;
610extern _Thread_local struct ${namespace}_id_generator ${namespace}_generator;
611
612#define ${namespace}_unlikely(x) __builtin_expect(!!(x), 0)
613
614static inline void ${namespace}_id_generator_next_id(struct ${namespace}_unique_id *id)
615{
616 if (${namespace}_unlikely(!${namespace}_generator.initialized)) {
617 ${namespace}_generator.thread_id =
618 __atomic_fetch_add(&${namespace}_id_generator_thread_counter,
619 1,
620 __ATOMIC_RELAXED);
621 ${namespace}_generator.initialized = 1;
622 }
623
624 id->thread_id = ${namespace}_generator.thread_id;
625 id->local_id = ${namespace}_generator.local_id++;
626}
627
628#define ${NAMESPACE}_API_OBJECT_NAME ${namespace}_api_object
629
630#define ${NAMESPACE}_MAKE_API_OBJECT(name, ...) \\
631 struct ${NAMESPACE}_CAT(${namespace}_api_state_, name) __attribute__((cleanup(${NAMESPACE}_CAT(name, _exit)))) \\
632 ${NAMESPACE}_API_OBJECT_NAME = { 0 }; \\
633 ${NAMESPACE}_CAT(name, _entry)(&${NAMESPACE}_API_OBJECT_NAME, ##__VA_ARGS__); \\
634 do { } while (0)
635
636#define ${NAMESPACE}_MARK_RETURN_API_OBJECT(code) \\
637 ({ \\
638 ${NAMESPACE}_API_OBJECT_NAME.ret = code; \\
639 ${NAMESPACE}_API_OBJECT_NAME.has_ret = 1; \\
640 })
641${classes}
642""")
643
644 cls_tpl = Template("""
645struct ${namespace}_api_state_${fn_name} {
646 struct ${namespace}_unique_id id;
647 int has_ret;
648 $ret_type ret;
649};
650
651static inline void ${fn_name}_entry(${ctor_type_params})
652{
653 if (${namespace}_ust_tracepoint_enabled(${provider}, ${fn_name}_entry)) {
654 ${namespace}_id_generator_next_id(&lttng_state->id);
655 ${pass_by_struct}
656 ${namespace}_ust_do_tracepoint($provider, ${fn_name}_entry,
657 lttng_state->id.thread_id,
658 lttng_state->id.local_id${ctor_params});
659 }
660}
661
662static inline void ${fn_name}_exit(const struct ${namespace}_api_state_${fn_name} *lttng_state)
663{
664 lttng_ust_tracepoint(${provider}, ${fn_name}_exit,
665 lttng_state->id.thread_id,
666 lttng_state->id.local_id,
667 lttng_state->has_ret,
668 lttng_state->ret);
669}
670""")
671 with open(output_path, "w") as output:
672 output.write(global_tpl.substitute(api_file=api_file,
673 namespace=namespace,
674 NAMESPACE=namespace.upper(),
675 classes="".join([
676 cls_tpl.substitute(provider=PROVIDER,
677 fn_name=fn.name,
678 pass_by_struct=fn.arguments_struct_variable(),
679 ctor_params=fn.ctor_params(),
680 ctor_type_params=", ".join([f"struct {namespace}_api_state_{fn.name} *lttng_state"] +
681 [f"{arg.type_name()} {arg.name()}"
682 for arg in fn.args]),
683 namespace=namespace,
684 NAMESPACE=namespace.upper(),
685 ret_type=fn.get_return_type_name())
686 for fn in function_declarations
687 ])))
688
74c0b9b3
OD
689def generate_tracepoint_implementations(namespace, defs, impls):
690 tpl = Template("""/* Auto-generated !*/
691#define LTTNG_UST_TRACEPOINT_CREATE_PROBES
692#define LTTNG_UST_TRACEPOINT_DEFINE
693#include "${defs}"
694""")
695
696 with open(impls, "w") as output:
697 output.write(tpl.substitute(defs=defs))
698
699def generate_tracepoint_states(namespace,
700 interface,
701 classes,
702 states,
703 emulated_classes):
704
705 if emulated_classes:
706 body_tpl = Template("""
707uint64_t ${namespace}_id_generator_thread_counter = 0;
708_Thread_local struct ${namespace}_id_generator ${namespace}_generator;
709""")
710 else:
711 body_tpl = Template("""
712#include <atomic>
713namespace ${namespace} {
714 std::atomic<uint64_t> id_generator::_thread_counter{0};
715 thread_local id_generator generator;
716};
717""")
718
719 tpl = Template("""/* Auto-generated! */
720#include "${interface}"
721#include "${classes}"
722
723$body
724""")
725
726 with open(states, "w") as output:
727 output.write(tpl.substitute(interface=interface,
728 classes=classes,
729 body=body_tpl.substitute(namespace=namespace)))
730
731def main():
732
733 global COMMON_PREFIX
734 global IGNORE
735 global PROVIDER
736
737 parser = argparse.ArgumentParser(prog="lttng-ust-autogen-api",
738 description="Generate LTTng classes and tracepoint definitions")
739
740 parser.add_argument("api",
741 help="Header file that has the API")
742
743 parser.add_argument("defs",
744 help="Path to tracepoint definitions")
745
746 parser.add_argument("interface",
747 help="Path to tracepoints interfaces")
748
749 parser.add_argument("classes",
750 help="Path to tracepoint classes")
751
752 parser.add_argument("impl",
753 help="Path to tracepoint implementations")
754
755 parser.add_argument("states",
756 help="Path to states")
757
758 parser.add_argument("--provider",
759 dest="provider",
760 metavar="PROVIDER",
761 default="noprovider",
762 help="Tracepoints PROVIDER")
763
764 parser.add_argument("--common-prefix",
765 dest="common_prefix",
766 metavar="PREFIX",
767 default="",
768 help="Common PREFIX of API functions (C namespace)")
769
770 parser.add_argument("-I",
771 action="append",
772 metavar="DIR",
773 dest="includes",
774 help="Add DIR to list of directories to include")
775
776 parser.add_argument("-D",
777 action="append",
778 metavar="DEFINITION",
779 dest="defines",
780 help="Add DEFINITION to list of definitions")
781
782 parser.add_argument("--tp-guard",
783 dest="tp_guard",
784 metavar="GUARD",
785 default="LTTNG_TRACEPOINT_DEF_H",
786 help="Use GUARD as header guard for tracepoint definitions")
787
788 parser.add_argument("--classes-guard",
789 dest="classes_guard",
790 metavar="GUARD",
791 default="LTTNG_TRACEPOINT_CLASSES_HPP",
792 help="Use GUARD as header guard for classes definitions")
793
794 parser.add_argument("--emulated-classes",
795 dest="emulated_classes",
796 action="store_true",
797 default=False,
798 help="Emulate C++ classes")
799
800 parser.add_argument("--namespace",
801 dest="namespace",
802 metavar="NAMESPACE",
803 default="lttng",
804 help="Generate classes in NAMESPACE")
805
806 parser.add_argument("--ignores",
807 dest="ignores",
808 metavar="FILE",
809 default=None,
810 help="Ignore functions listed in FILE")
811
812 parser.add_argument("--c-header",
813 dest="required_c_headers",
814 metavar="HEADER",
815 action="append",
816 default=[],
817 help="Search for HEADER in C_INCLUDE_PATH and add its directory to search path")
818
819 parser.add_argument("--cxx-header",
820 dest="required_cxx_headers",
821 metavar="HEADER",
822 action="append",
823 default=[],
824 help="Search for HEADER in CPLUS_INCLUDE_PATH add its directory to search path")
825
826 args = parser.parse_args()
827
828 PROVIDER = args.provider
829 COMMON_PREFIX = args.common_prefix
830
831 if args.ignores:
832 with open(args.ignores, "r") as f:
833 for ignore in f.read().splitlines():
834 IGNORE.add(ignore)
835
836 root = parse_header(args.api, args.includes, args.defines,
837 args.required_c_headers,
838 args.required_cxx_headers)
839
840 function_declarations = list_functions(root)
841 enum_declarations = list_enums(root)
842
843 generate_tracepoint_definitions(function_declarations,
844 enum_declarations,
845 args.api, args.defs, args.interface,
846 args.tp_guard)
847
848 if args.emulated_classes:
849 generate_tracepoint_emulated_classes(function_declarations,
850 args.api,
851 args.classes,
852 args.classes_guard,
853 args.namespace)
854 else:
855 generate_tracepoint_classes(function_declarations,
856 args.api,
857 args.classes,
858 args.classes_guard,
859 args.namespace)
860
861 generate_tracepoint_implementations(args.namespace,
862 args.interface,
863 args.impl)
864
865 generate_tracepoint_states(args.namespace,
866 args.interface,
867 args.classes,
868 args.states,
869 args.emulated_classes)
870
871
872if __name__ == "__main__":
873 main()
This page took 0.052613 seconds and 4 git commands to generate.