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