Move to kernel style SPDX license identifiers
[lttng-ust.git] / tools / lttng-gen-tp
CommitLineData
f5c77416 1#!/usr/bin/env python
b25c5b37 2#
c0c0989a 3# SPDX-License-Identifier: GPL-2.0-only
b25c5b37 4#
c0c0989a 5# Copyright (C) 2012 Yannick Brosseau <yannick.brosseau@gmail.com>
b25c5b37 6
2d9c7df1 7from __future__ import print_function
b25c5b37
YB
8import sys
9import getopt
10import re
db06a0a2
YB
11import os
12import subprocess
b25c5b37 13
2982a614 14
b25c5b37
YB
15class Usage(Exception):
16 def __init__(self, msg):
17 self.msg = msg
18
2982a614 19
b25c5b37 20class HeaderFile:
2982a614 21 HEADER_TPL = """
b25c5b37
YB
22#undef TRACEPOINT_PROVIDER
23#define TRACEPOINT_PROVIDER {providerName}
24
45f399e8
MD
25#undef TRACEPOINT_INCLUDE
26#define TRACEPOINT_INCLUDE "./{headerFilename}"
b25c5b37 27
b25c5b37
YB
28#if !defined({includeGuard}) || defined(TRACEPOINT_HEADER_MULTI_READ)
29#define {includeGuard}
30
31#include <lttng/tracepoint.h>
32
33"""
2982a614 34 FOOTER_TPL = """
b25c5b37
YB
35#endif /* {includeGuard} */
36
37#include <lttng/tracepoint-event.h>
b25c5b37 38"""
2982a614 39
b25c5b37
YB
40 def __init__(self, filename, template):
41 self.outputFilename = filename
42 self.template = template
43
44 def write(self):
2982a614 45 outputFile = open(self.outputFilename, "w")
8ed68685
YB
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())
b25c5b37
YB
49
50 outputFile.write(HeaderFile.HEADER_TPL.format(providerName=self.template.domain,
2982a614
JR
51 includeGuard=includeGuard,
52 headerFilename=self.outputFilename))
b25c5b37 53 outputFile.write(self.template.text)
2982a614 54 outputFile.write(HeaderFile.FOOTER_TPL.format(includeGuard=includeGuard))
b25c5b37
YB
55 outputFile.close()
56
2982a614 57
b25c5b37 58class CFile:
2982a614 59 FILE_TPL = """
b25c5b37
YB
60#define TRACEPOINT_CREATE_PROBES
61/*
62 * The header containing our TRACEPOINT_EVENTs.
63 */
64#define TRACEPOINT_DEFINE
65#include "{headerFilename}"
66"""
2982a614 67
b25c5b37
YB
68 def __init__(self, filename, template):
69 self.outputFilename = filename
70 self.template = template
71
72 def write(self):
2982a614 73 outputFile = open(self.outputFilename, "w")
b25c5b37 74
b1714423
JR
75 headerFilename = self.outputFilename
76 if headerFilename.endswith(".c"):
77 headerFilename = headerFilename[:-2] + ".h"
b25c5b37
YB
78
79 outputFile.write(CFile.FILE_TPL.format(
2982a614 80 headerFilename=headerFilename))
b25c5b37
YB
81 outputFile.close()
82
2982a614 83
db06a0a2
YB
84class ObjFile:
85 def __init__(self, filename, template):
86 self.outputFilename = filename
87 self.template = template
2982a614 88
db06a0a2
YB
89 def _detectCC(self):
90 cc = ""
2d9c7df1 91 if 'CC' in os.environ:
db06a0a2
YB
92 cc = os.environ['CC']
93 try:
7996e006 94 subprocess.call(cc.split(),
db06a0a2
YB
95 stdout=subprocess.PIPE,
96 stderr=subprocess.PIPE)
2d9c7df1
ZT
97 except OSError as msg:
98 print("Invalid CC environment variable")
db06a0a2
YB
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)
2d9c7df1 108 except OSError as msg:
db06a0a2
YB
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)
2d9c7df1 119 except OSError as msg:
db06a0a2
YB
120 useGCC = False
121 if useGCC:
122 cc = "gcc"
123 return cc
124
125 def write(self):
b1714423
JR
126 cFilename = self.outputFilename
127 if cFilename.endswith(".o"):
128 cFilename = cFilename[:-2] + ".c"
129
db06a0a2
YB
130 cc = self._detectCC()
131 if cc == "":
132 raise RuntimeError("No C Compiler detected")
170423b0 133 if 'CPPFLAGS' in os.environ:
aa4e204a 134 cppflags = " " + os.environ['CPPFLAGS']
170423b0
MD
135 else:
136 cppflags = ""
2d9c7df1 137 if 'CFLAGS' in os.environ:
aa4e204a 138 cflags = " " + os.environ['CFLAGS']
db06a0a2
YB
139 else:
140 cflags = ""
170423b0 141 if 'LDFLAGS' in os.environ:
aa4e204a 142 ldflags = " " + os.environ['LDFLAGS']
170423b0
MD
143 else:
144 ldflags = ""
db06a0a2 145
aa4e204a 146 command = cc + " -c" + cppflags + cflags + ldflags + " -I. -llttng-ust" + " -o " + self.outputFilename + " " + cFilename
0794b3f6
YB
147 if verbose:
148 print("Compile command: " + command)
db06a0a2
YB
149 subprocess.call(command.split())
150
2982a614 151
b25c5b37
YB
152class TemplateFile:
153 def __init__(self, filename):
154 self.domain = ""
155 self.inputFilename = filename
156 self.parseTemplate()
157
b25c5b37 158 def parseTemplate(self):
2982a614 159 f = open(self.inputFilename, "r")
b25c5b37
YB
160
161 self.text = f.read()
162
2982a614 163 # Remove # comments (from input and output file) but keep
0794b3f6 164 # #include in the output file
2982a614
JR
165 removeComments = re.compile("#[^include].*$", flags=re.MULTILINE)
166 self.text = removeComments.sub("", self.text)
0794b3f6 167 # Remove #include directive from the parsed text
2982a614 168 removePreprocess = re.compile("#.*$", flags=re.MULTILINE)
0794b3f6 169 noPreprocess = removePreprocess.sub("", self.text)
2982a614
JR
170 # Remove // comments
171 removeLineComment = re.compile("\/\/.*$", flags=re.MULTILINE)
0794b3f6 172 nolinecomment = removeLineComment.sub("", noPreprocess)
2982a614
JR
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)
b25c5b37
YB
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:
2d9c7df1 190 print("Warning: different domain provided (%s,%s)" % (self.domain, domain))
b25c5b37 191
0794b3f6 192
2982a614
JR
193verbose = False
194
195usage = """
b25c5b37
YB
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.
db06a0a2 202 for example sample.tp will generate sample.h, sample.c and sample.o)
b25c5b37 203
db06a0a2 204 When using the -o option, the OUTPUT_FILE must end with either .h, .c or .o
b25c5b37
YB
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"""
2982a614
JR
211
212
b25c5b37
YB
213def main(argv=None):
214 if argv is None:
215 argv = sys.argv
216
217 try:
218 try:
2982a614 219 opts, args = getopt.gnu_getopt(argv[1:], "ho:av", ["help", "verbose"])
2d9c7df1 220 except getopt.error as msg:
2982a614 221 raise Usage(msg)
b25c5b37 222
2d9c7df1
ZT
223 except Usage as err:
224 print(err.msg, file=sys.stderr)
225 print("for help use --help", file=sys.stderr)
b25c5b37
YB
226 return 2
227
228 outputNames = []
229 for o, a in opts:
230 if o in ("-h", "--help"):
2d9c7df1 231 print(usage)
b25c5b37 232 return(0)
2982a614 233 if o in ("-o", ""):
b25c5b37 234 outputNames.append(a)
2982a614 235 if o in ("-a", ""):
b25c5b37 236 all = True
0794b3f6
YB
237 if o in ("-v", "--verbose"):
238 global verbose
239 verbose = True
a719be64
CB
240 try:
241 if len(args) == 0:
242 raise Usage("No template file given")
243
2d9c7df1
ZT
244 except Usage as err:
245 print(err.msg, file=sys.stderr)
246 print("for help use --help", file=sys.stderr)
a719be64 247 return 2
b25c5b37
YB
248
249 doCFile = None
250 doHeader = None
db06a0a2 251 doObj = None
b25c5b37
YB
252 headerFilename = None
253 cFilename = None
db06a0a2 254 objFilename = None
b25c5b37
YB
255
256 if len(outputNames) > 0:
257 if len(args) > 1:
2d9c7df1 258 print("Cannot process more than one input if you specify an output")
b25c5b37
YB
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":
db06a0a2
YB
269 doObj = True
270 objFilename = outputName
b25c5b37 271 else:
2d9c7df1 272 print("output file type unsupported")
b25c5b37
YB
273 return(4)
274 else:
275 doHeader = True
276 doCFile = True
db06a0a2 277 doObj = True
b25c5b37
YB
278
279 # process arguments
280 for arg in args:
7cd5a840 281 if arg[-3:] != ".tp":
2d9c7df1 282 print(arg + " does not end in .tp. Skipping.")
7cd5a840 283 continue
b25c5b37 284
44745fc1
YB
285 tpl = None
286 try:
287 tpl = TemplateFile(arg)
288 except IOError as args:
2d9c7df1 289 print("Cannot read input file " + args.filename + " " + args.strerror)
44745fc1
YB
290 return -1
291 try:
292 if doHeader:
293 if headerFilename:
294 curFilename = headerFilename
295 else:
2982a614 296 curFilename = re.sub("\.tp$", ".h", arg)
44745fc1
YB
297 doth = HeaderFile(curFilename, tpl)
298 doth.write()
299 if doCFile:
300 if cFilename:
301 curFilename = cFilename
302 else:
2982a614 303 curFilename = re.sub("\.tp$", ".c", arg)
44745fc1
YB
304 dotc = CFile(curFilename, tpl)
305 dotc.write()
306 if doObj:
307 if objFilename:
308 curFilename = objFilename
309 else:
2982a614 310 curFilename = re.sub("\.tp$", ".o", arg)
44745fc1
YB
311 dotobj = ObjFile(curFilename, tpl)
312 dotobj.write()
313 except IOError as args:
2d9c7df1 314 print("Cannot write output file " + args.filename + " " + args.strerror)
44745fc1 315 return -1
2d9c7df1 316
2982a614 317
b25c5b37
YB
318if __name__ == "__main__":
319 sys.exit(main())
This page took 0.041727 seconds and 4 git commands to generate.