Version 2.13.0-rc1
[lttng-ust.git] / tools / lttng-gen-tp
1 #!/usr/bin/env python
2 #
3 # SPDX-License-Identifier: GPL-2.0-only
4 #
5 # Copyright (C) 2012 Yannick Brosseau <yannick.brosseau@gmail.com>
6
7 from __future__ import print_function
8 import sys
9 import getopt
10 import re
11 import os
12 import subprocess
13
14
15 class Usage(Exception):
16 def __init__(self, msg):
17 self.msg = msg
18
19
20 class HeaderFile:
21 HEADER_TPL = """
22 #undef LTTNG_UST_TRACEPOINT_PROVIDER
23 #define LTTNG_UST_TRACEPOINT_PROVIDER {providerName}
24
25 #undef LTTNG_UST_TRACEPOINT_INCLUDE
26 #define LTTNG_UST_TRACEPOINT_INCLUDE "./{headerFilename}"
27
28 #if !defined({includeGuard}) || defined(LTTNG_UST_TRACEPOINT_HEADER_MULTI_READ)
29 #define {includeGuard}
30
31 #include <lttng/tracepoint.h>
32
33 """
34 FOOTER_TPL = """
35 #endif /* {includeGuard} */
36
37 #include <lttng/tracepoint-event.h>
38 """
39
40 def __init__(self, filename, template):
41 self.outputFilename = filename
42 self.template = template
43
44 def write(self):
45 outputFile = open(self.outputFilename, "w")
46 # Include guard macro will be created by uppercasing the filename and
47 # replacing all non alphanumeric characters with '_'
48 includeGuard = re.sub('[^0-9a-zA-Z]', '_', self.outputFilename.upper())
49
50 outputFile.write(HeaderFile.HEADER_TPL.format(providerName=self.template.domain,
51 includeGuard=includeGuard,
52 headerFilename=self.outputFilename))
53 outputFile.write(self.template.text)
54 outputFile.write(HeaderFile.FOOTER_TPL.format(includeGuard=includeGuard))
55 outputFile.close()
56
57
58 class CFile:
59 FILE_TPL = """
60 #define LTTNG_UST_TRACEPOINT_CREATE_PROBES
61 /*
62 * The header containing our LTTNG_UST_TRACEPOINT_EVENTs.
63 */
64 #define LTTNG_UST_TRACEPOINT_DEFINE
65 #include "{headerFilename}"
66 """
67
68 def __init__(self, filename, template):
69 self.outputFilename = filename
70 self.template = template
71
72 def write(self):
73 outputFile = open(self.outputFilename, "w")
74
75 headerFilename = self.outputFilename
76 if headerFilename.endswith(".c"):
77 headerFilename = headerFilename[:-2] + ".h"
78
79 outputFile.write(CFile.FILE_TPL.format(
80 headerFilename=headerFilename))
81 outputFile.close()
82
83
84 class ObjFile:
85 def __init__(self, filename, template):
86 self.outputFilename = filename
87 self.template = template
88
89 def _detectCC(self):
90 cc = ""
91 if 'CC' in os.environ:
92 cc = os.environ['CC']
93 try:
94 subprocess.call(cc.split(),
95 stdout=subprocess.PIPE,
96 stderr=subprocess.PIPE)
97 except OSError as msg:
98 print("Invalid CC environment variable")
99 cc = ""
100
101 else:
102 # Try c first, if that fails try gcc
103 try:
104 useCC = True
105 subprocess.call("cc",
106 stdout=subprocess.PIPE,
107 stderr=subprocess.PIPE)
108 except OSError as msg:
109 useCC = False
110 if useCC:
111 cc = "cc"
112
113 else:
114 try:
115 useGCC = True
116 subprocess.call("gcc",
117 stdout=subprocess.PIPE,
118 stderr=subprocess.PIPE)
119 except OSError as msg:
120 useGCC = False
121 if useGCC:
122 cc = "gcc"
123 return cc
124
125 def write(self):
126 cFilename = self.outputFilename
127 if cFilename.endswith(".o"):
128 cFilename = cFilename[:-2] + ".c"
129
130 cc = self._detectCC()
131 if cc == "":
132 raise RuntimeError("No C Compiler detected")
133 if 'CPPFLAGS' in os.environ:
134 cppflags = " " + os.environ['CPPFLAGS']
135 else:
136 cppflags = ""
137 if 'CFLAGS' in os.environ:
138 cflags = " " + os.environ['CFLAGS']
139 else:
140 cflags = ""
141
142 command = cc + " -c" + cppflags + cflags + " -I. -o " + self.outputFilename + " " + cFilename
143 if verbose:
144 print("Compile command: " + command)
145 subprocess.call(command.split())
146
147
148 class TemplateFile:
149 def __init__(self, filename):
150 self.domain = ""
151 self.inputFilename = filename
152 self.parseTemplate()
153
154 def parseTemplate(self):
155 f = open(self.inputFilename, "r")
156
157 self.text = f.read()
158
159 # Remove # comments (from input and output file) but keep
160 # #include in the output file
161 removeComments = re.compile("#[^include].*$", flags=re.MULTILINE)
162 self.text = removeComments.sub("", self.text)
163 # Remove #include directive from the parsed text
164 removePreprocess = re.compile("#.*$", flags=re.MULTILINE)
165 noPreprocess = removePreprocess.sub("", self.text)
166 # Remove // comments
167 removeLineComment = re.compile("\/\/.*$", flags=re.MULTILINE)
168 nolinecomment = removeLineComment.sub("", noPreprocess)
169 # Remove all spaces and lines
170 cleantext = re.sub("\s*", "", nolinecomment)
171 # Remove multine C style comments
172 nocomment = re.sub("/\*.*?\*/", "", cleantext)
173 entries = re.split("^LTTNG_UST_TRACEPOINT_.*?", nocomment)
174
175 for entry in entries:
176 if entry != '':
177 decomp = re.findall("(\w*?)\((\w*?),(\w*?),", entry)
178 typea = decomp[0][0]
179 domain = decomp[0][1]
180 name = decomp[0][2]
181
182 if self.domain == "":
183 self.domain = domain
184 else:
185 if self.domain != domain:
186 print("Warning: different domain provided (%s,%s)" % (self.domain, domain))
187
188
189 verbose = False
190
191 usage = """
192 lttng-gen-tp - Generate the LTTng-UST header and source based on a simple template
193
194 usage: lttng-gen-tp TEMPLATE_FILE [-o OUTPUT_FILE][-o OUTPUT_FILE]
195
196 If no OUTPUT_FILE is given, the .h and .c file will be generated.
197 (The basename of the template file with be used for the generated file.
198 for example sample.tp will generate sample.h, sample.c and sample.o)
199
200 When using the -o option, the OUTPUT_FILE must end with either .h, .c or .o
201 The -o option can be repeated multiple times.
202
203 The template file must contains LTTNG_UST_TRACEPOINT_EVENT and LTTNG_UST_TRACEPOINT_LOGLEVEL
204 as per defined in the lttng/tracepoint.h file.
205 See the lttng-ust(3) man page for more details on the format.
206 """
207
208
209 def main(argv=None):
210 if argv is None:
211 argv = sys.argv
212
213 try:
214 try:
215 opts, args = getopt.gnu_getopt(argv[1:], "ho:av", ["help", "verbose"])
216 except getopt.error as msg:
217 raise Usage(msg)
218
219 except Usage as err:
220 print(err.msg, file=sys.stderr)
221 print("for help use --help", file=sys.stderr)
222 return 2
223
224 outputNames = []
225 for o, a in opts:
226 if o in ("-h", "--help"):
227 print(usage)
228 return(0)
229 if o in ("-o", ""):
230 outputNames.append(a)
231 if o in ("-a", ""):
232 all = True
233 if o in ("-v", "--verbose"):
234 global verbose
235 verbose = True
236 try:
237 if len(args) == 0:
238 raise Usage("No template file given")
239
240 except Usage as err:
241 print(err.msg, file=sys.stderr)
242 print("for help use --help", file=sys.stderr)
243 return 2
244
245 doCFile = None
246 doHeader = None
247 doObj = None
248 headerFilename = None
249 cFilename = None
250 objFilename = None
251
252 if len(outputNames) > 0:
253 if len(args) > 1:
254 print("Cannot process more than one input if you specify an output")
255 return(3)
256
257 for outputName in outputNames:
258 if outputName[-2:] == ".h":
259 doHeader = True
260 headerFilename = outputName
261 elif outputName[-2:] == ".c":
262 doCFile = True
263 cFilename = outputName
264 elif outputName[-2:] == ".o":
265 doObj = True
266 objFilename = outputName
267 else:
268 print("output file type unsupported")
269 return(4)
270 else:
271 doHeader = True
272 doCFile = True
273 doObj = True
274
275 # process arguments
276 for arg in args:
277 if arg[-3:] != ".tp":
278 print(arg + " does not end in .tp. Skipping.")
279 continue
280
281 tpl = None
282 try:
283 tpl = TemplateFile(arg)
284 except IOError as args:
285 print("Cannot read input file " + args.filename + " " + args.strerror)
286 return -1
287 try:
288 if doHeader:
289 if headerFilename:
290 curFilename = headerFilename
291 else:
292 curFilename = re.sub("\.tp$", ".h", arg)
293 doth = HeaderFile(curFilename, tpl)
294 doth.write()
295 if doCFile:
296 if cFilename:
297 curFilename = cFilename
298 else:
299 curFilename = re.sub("\.tp$", ".c", arg)
300 dotc = CFile(curFilename, tpl)
301 dotc.write()
302 if doObj:
303 if objFilename:
304 curFilename = objFilename
305 else:
306 curFilename = re.sub("\.tp$", ".o", arg)
307 dotobj = ObjFile(curFilename, tpl)
308 dotobj.write()
309 except IOError as args:
310 print("Cannot write output file " + args.filename + " " + args.strerror)
311 return -1
312
313
314 if __name__ == "__main__":
315 sys.exit(main())
This page took 0.040488 seconds and 4 git commands to generate.