Fix: lttng-gen-tp: only replace file extension
[lttng-ust.git] / tools / lttng-gen-tp
1 #!/usr/bin/env python
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
19 from __future__ import print_function
20 import sys
21 import getopt
22 import re
23 import os
24 import subprocess
25
26 class Usage(Exception):
27 def __init__(self, msg):
28 self.msg = msg
29
30 class HeaderFile:
31 HEADER_TPL="""
32 #undef TRACEPOINT_PROVIDER
33 #define TRACEPOINT_PROVIDER {providerName}
34
35 #undef TRACEPOINT_INCLUDE
36 #define TRACEPOINT_INCLUDE "./{headerFilename}"
37
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>
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")
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())
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
66 class 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
82 headerFilename = self.outputFilename
83 if headerFilename.endswith(".c"):
84 headerFilename = headerFilename[:-2] + ".h"
85
86 outputFile.write(CFile.FILE_TPL.format(
87 headerFilename = headerFilename))
88 outputFile.close()
89
90 class ObjFile:
91 def __init__(self, filename, template):
92 self.outputFilename = filename
93 self.template = template
94 def _detectCC(self):
95 cc = ""
96 if 'CC' in os.environ:
97 cc = os.environ['CC']
98 try:
99 subprocess.call(cc.split(),
100 stdout=subprocess.PIPE,
101 stderr=subprocess.PIPE)
102 except OSError as msg:
103 print("Invalid CC environment variable")
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)
113 except OSError as msg:
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)
124 except OSError as msg:
125 useGCC = False
126 if useGCC:
127 cc = "gcc"
128 return cc
129
130 def write(self):
131 cFilename = self.outputFilename
132 if cFilename.endswith(".o"):
133 cFilename = cFilename[:-2] + ".c"
134
135 cc = self._detectCC()
136 if cc == "":
137 raise RuntimeError("No C Compiler detected")
138 if 'CPPFLAGS' in os.environ:
139 cppflags = " " + os.environ['CPPFLAGS']
140 else:
141 cppflags = ""
142 if 'CFLAGS' in os.environ:
143 cflags = " " + os.environ['CFLAGS']
144 else:
145 cflags = ""
146 if 'LDFLAGS' in os.environ:
147 ldflags = " " + os.environ['LDFLAGS']
148 else:
149 ldflags = ""
150
151 command = cc + " -c" + cppflags + cflags + ldflags + " -I. -llttng-ust" + " -o " + self.outputFilename + " " + cFilename
152 if verbose:
153 print("Compile command: " + command)
154 subprocess.call(command.split())
155
156 class 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
168 #Remove # comments (from input and output file) but keep
169 # #include in the output file
170 removeComments = re.compile("#[^include].*$",flags=re.MULTILINE)
171 self.text = removeComments.sub("",self.text)
172 # Remove #include directive from the parsed text
173 removePreprocess = re.compile("#.*$",flags=re.MULTILINE)
174 noPreprocess = removePreprocess.sub("", self.text)
175 #Remove // comments
176 removeLineComment = re.compile("\/\/.*$",flags=re.MULTILINE)
177 nolinecomment = removeLineComment.sub("", noPreprocess)
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:
195 print("Warning: different domain provided (%s,%s)" % (self.domain, domain))
196
197 verbose=False
198
199 usage="""
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.
206 for example sample.tp will generate sample.h, sample.c and sample.o)
207
208 When using the -o option, the OUTPUT_FILE must end with either .h, .c or .o
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 """
215 def main(argv=None):
216 if argv is None:
217 argv = sys.argv
218
219 try:
220 try:
221 opts, args = getopt.gnu_getopt(argv[1:], "ho:av", ["help","verbose"])
222 except getopt.error as msg:
223 raise Usage(msg)
224
225 except Usage as err:
226 print(err.msg, file=sys.stderr)
227 print("for help use --help", file=sys.stderr)
228 return 2
229
230 outputNames = []
231 for o, a in opts:
232 if o in ("-h", "--help"):
233 print(usage)
234 return(0)
235 if o in ("-o",""):
236 outputNames.append(a)
237 if o in ("-a",""):
238 all = True
239 if o in ("-v", "--verbose"):
240 global verbose
241 verbose = True
242 try:
243 if len(args) == 0:
244 raise Usage("No template file given")
245
246 except Usage as err:
247 print(err.msg, file=sys.stderr)
248 print("for help use --help", file=sys.stderr)
249 return 2
250
251 doCFile = None
252 doHeader = None
253 doObj = None
254 headerFilename = None
255 cFilename = None
256 objFilename = None
257
258 if len(outputNames) > 0:
259 if len(args) > 1:
260 print("Cannot process more than one input if you specify an output")
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":
271 doObj = True
272 objFilename = outputName
273 else:
274 print("output file type unsupported")
275 return(4)
276 else:
277 doHeader = True
278 doCFile = True
279 doObj = True
280
281 # process arguments
282 for arg in args:
283 if arg[-3:] != ".tp":
284 print(arg + " does not end in .tp. Skipping.")
285 continue
286
287 tpl = None
288 try:
289 tpl = TemplateFile(arg)
290 except IOError as args:
291 print("Cannot read input file " + args.filename + " " + args.strerror)
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:
316 print("Cannot write output file " + args.filename + " " + args.strerror)
317 return -1
318
319 if __name__ == "__main__":
320 sys.exit(main())
This page took 0.035237 seconds and 4 git commands to generate.