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