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