Move to kernel style SPDX license identifiers
[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 TRACEPOINT_PROVIDER
23 #define TRACEPOINT_PROVIDER {providerName}
24
25 #undef TRACEPOINT_INCLUDE
26 #define TRACEPOINT_INCLUDE "./{headerFilename}"
27
28 #if !defined({includeGuard}) || defined(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 TRACEPOINT_CREATE_PROBES
61 /*
62 * The header containing our TRACEPOINT_EVENTs.
63 */
64 #define 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 if 'LDFLAGS' in os.environ:
142 ldflags = " " + os.environ['LDFLAGS']
143 else:
144 ldflags = ""
145
146 command = cc + " -c" + cppflags + cflags + ldflags + " -I. -llttng-ust" + " -o " + self.outputFilename + " " + cFilename
147 if verbose:
148 print("Compile command: " + command)
149 subprocess.call(command.split())
150
151
152 class TemplateFile:
153 def __init__(self, filename):
154 self.domain = ""
155 self.inputFilename = filename
156 self.parseTemplate()
157
158 def parseTemplate(self):
159 f = open(self.inputFilename, "r")
160
161 self.text = f.read()
162
163 # Remove # comments (from input and output file) but keep
164 # #include in the output file
165 removeComments = re.compile("#[^include].*$", flags=re.MULTILINE)
166 self.text = removeComments.sub("", self.text)
167 # Remove #include directive from the parsed text
168 removePreprocess = re.compile("#.*$", flags=re.MULTILINE)
169 noPreprocess = removePreprocess.sub("", self.text)
170 # Remove // comments
171 removeLineComment = re.compile("\/\/.*$", flags=re.MULTILINE)
172 nolinecomment = removeLineComment.sub("", noPreprocess)
173 # Remove all spaces and lines
174 cleantext = re.sub("\s*", "", nolinecomment)
175 # Remove multine C style comments
176 nocomment = re.sub("/\*.*?\*/", "", cleantext)
177 entries = re.split("TRACEPOINT_.*?", nocomment)
178
179 for entry in entries:
180 if entry != '':
181 decomp = re.findall("(\w*?)\((\w*?),(\w*?),", entry)
182 typea = decomp[0][0]
183 domain = decomp[0][1]
184 name = decomp[0][2]
185
186 if self.domain == "":
187 self.domain = domain
188 else:
189 if self.domain != domain:
190 print("Warning: different domain provided (%s,%s)" % (self.domain, domain))
191
192
193 verbose = False
194
195 usage = """
196 lttng-gen-tp - Generate the LTTng-UST header and source based on a simple template
197
198 usage: lttng-gen-tp TEMPLATE_FILE [-o OUTPUT_FILE][-o OUTPUT_FILE]
199
200 If no OUTPUT_FILE is given, the .h and .c file will be generated.
201 (The basename of the template file with be used for the generated file.
202 for example sample.tp will generate sample.h, sample.c and sample.o)
203
204 When using the -o option, the OUTPUT_FILE must end with either .h, .c or .o
205 The -o option can be repeated multiple times.
206
207 The template file must contains TRACEPOINT_EVENT and TRACEPOINT_LOGLEVEL
208 as per defined in the lttng/tracepoint.h file.
209 See the lttng-ust(3) man page for more details on the format.
210 """
211
212
213 def main(argv=None):
214 if argv is None:
215 argv = sys.argv
216
217 try:
218 try:
219 opts, args = getopt.gnu_getopt(argv[1:], "ho:av", ["help", "verbose"])
220 except getopt.error as msg:
221 raise Usage(msg)
222
223 except Usage as err:
224 print(err.msg, file=sys.stderr)
225 print("for help use --help", file=sys.stderr)
226 return 2
227
228 outputNames = []
229 for o, a in opts:
230 if o in ("-h", "--help"):
231 print(usage)
232 return(0)
233 if o in ("-o", ""):
234 outputNames.append(a)
235 if o in ("-a", ""):
236 all = True
237 if o in ("-v", "--verbose"):
238 global verbose
239 verbose = True
240 try:
241 if len(args) == 0:
242 raise Usage("No template file given")
243
244 except Usage as err:
245 print(err.msg, file=sys.stderr)
246 print("for help use --help", file=sys.stderr)
247 return 2
248
249 doCFile = None
250 doHeader = None
251 doObj = None
252 headerFilename = None
253 cFilename = None
254 objFilename = None
255
256 if len(outputNames) > 0:
257 if len(args) > 1:
258 print("Cannot process more than one input if you specify an output")
259 return(3)
260
261 for outputName in outputNames:
262 if outputName[-2:] == ".h":
263 doHeader = True
264 headerFilename = outputName
265 elif outputName[-2:] == ".c":
266 doCFile = True
267 cFilename = outputName
268 elif outputName[-2:] == ".o":
269 doObj = True
270 objFilename = outputName
271 else:
272 print("output file type unsupported")
273 return(4)
274 else:
275 doHeader = True
276 doCFile = True
277 doObj = True
278
279 # process arguments
280 for arg in args:
281 if arg[-3:] != ".tp":
282 print(arg + " does not end in .tp. Skipping.")
283 continue
284
285 tpl = None
286 try:
287 tpl = TemplateFile(arg)
288 except IOError as args:
289 print("Cannot read input file " + args.filename + " " + args.strerror)
290 return -1
291 try:
292 if doHeader:
293 if headerFilename:
294 curFilename = headerFilename
295 else:
296 curFilename = re.sub("\.tp$", ".h", arg)
297 doth = HeaderFile(curFilename, tpl)
298 doth.write()
299 if doCFile:
300 if cFilename:
301 curFilename = cFilename
302 else:
303 curFilename = re.sub("\.tp$", ".c", arg)
304 dotc = CFile(curFilename, tpl)
305 dotc.write()
306 if doObj:
307 if objFilename:
308 curFilename = objFilename
309 else:
310 curFilename = re.sub("\.tp$", ".o", arg)
311 dotobj = ObjFile(curFilename, tpl)
312 dotobj.write()
313 except IOError as args:
314 print("Cannot write output file " + args.filename + " " + args.strerror)
315 return -1
316
317
318 if __name__ == "__main__":
319 sys.exit(main())
This page took 0.035352 seconds and 4 git commands to generate.