4ab91f367057ebf89290bb101e22039c650fd009
[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
27 class Usage(Exception):
28 def __init__(self, msg):
29 self.msg = msg
30
31
32 class HeaderFile:
33 HEADER_TPL = """
34 #undef TRACEPOINT_PROVIDER
35 #define TRACEPOINT_PROVIDER {providerName}
36
37 #undef TRACEPOINT_INCLUDE
38 #define TRACEPOINT_INCLUDE "./{headerFilename}"
39
40 #if !defined({includeGuard}) || defined(TRACEPOINT_HEADER_MULTI_READ)
41 #define {includeGuard}
42
43 #include <lttng/tracepoint.h>
44
45 """
46 FOOTER_TPL = """
47 #endif /* {includeGuard} */
48
49 #include <lttng/tracepoint-event.h>
50 """
51
52 def __init__(self, filename, template):
53 self.outputFilename = filename
54 self.template = template
55
56 def write(self):
57 outputFile = open(self.outputFilename, "w")
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())
61
62 outputFile.write(HeaderFile.HEADER_TPL.format(providerName=self.template.domain,
63 includeGuard=includeGuard,
64 headerFilename=self.outputFilename))
65 outputFile.write(self.template.text)
66 outputFile.write(HeaderFile.FOOTER_TPL.format(includeGuard=includeGuard))
67 outputFile.close()
68
69
70 class CFile:
71 FILE_TPL = """
72 #define TRACEPOINT_CREATE_PROBES
73 /*
74 * The header containing our TRACEPOINT_EVENTs.
75 */
76 #define TRACEPOINT_DEFINE
77 #include "{headerFilename}"
78 """
79
80 def __init__(self, filename, template):
81 self.outputFilename = filename
82 self.template = template
83
84 def write(self):
85 outputFile = open(self.outputFilename, "w")
86
87 headerFilename = self.outputFilename
88 if headerFilename.endswith(".c"):
89 headerFilename = headerFilename[:-2] + ".h"
90
91 outputFile.write(CFile.FILE_TPL.format(
92 headerFilename=headerFilename))
93 outputFile.close()
94
95
96 class ObjFile:
97 def __init__(self, filename, template):
98 self.outputFilename = filename
99 self.template = template
100
101 def _detectCC(self):
102 cc = ""
103 if 'CC' in os.environ:
104 cc = os.environ['CC']
105 try:
106 subprocess.call(cc.split(),
107 stdout=subprocess.PIPE,
108 stderr=subprocess.PIPE)
109 except OSError as msg:
110 print("Invalid CC environment variable")
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)
120 except OSError as msg:
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)
131 except OSError as msg:
132 useGCC = False
133 if useGCC:
134 cc = "gcc"
135 return cc
136
137 def write(self):
138 cFilename = self.outputFilename
139 if cFilename.endswith(".o"):
140 cFilename = cFilename[:-2] + ".c"
141
142 cc = self._detectCC()
143 if cc == "":
144 raise RuntimeError("No C Compiler detected")
145 if 'CPPFLAGS' in os.environ:
146 cppflags = " " + os.environ['CPPFLAGS']
147 else:
148 cppflags = ""
149 if 'CFLAGS' in os.environ:
150 cflags = " " + os.environ['CFLAGS']
151 else:
152 cflags = ""
153 if 'LDFLAGS' in os.environ:
154 ldflags = " " + os.environ['LDFLAGS']
155 else:
156 ldflags = ""
157
158 command = cc + " -c" + cppflags + cflags + ldflags + " -I. -llttng-ust" + " -o " + self.outputFilename + " " + cFilename
159 if verbose:
160 print("Compile command: " + command)
161 subprocess.call(command.split())
162
163
164 class TemplateFile:
165 def __init__(self, filename):
166 self.domain = ""
167 self.inputFilename = filename
168 self.parseTemplate()
169
170 def parseTemplate(self):
171 f = open(self.inputFilename, "r")
172
173 self.text = f.read()
174
175 # Remove # comments (from input and output file) but keep
176 # #include in the output file
177 removeComments = re.compile("#[^include].*$", flags=re.MULTILINE)
178 self.text = removeComments.sub("", self.text)
179 # Remove #include directive from the parsed text
180 removePreprocess = re.compile("#.*$", flags=re.MULTILINE)
181 noPreprocess = removePreprocess.sub("", self.text)
182 # Remove // comments
183 removeLineComment = re.compile("\/\/.*$", flags=re.MULTILINE)
184 nolinecomment = removeLineComment.sub("", noPreprocess)
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)
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:
202 print("Warning: different domain provided (%s,%s)" % (self.domain, domain))
203
204
205 verbose = False
206
207 usage = """
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.
214 for example sample.tp will generate sample.h, sample.c and sample.o)
215
216 When using the -o option, the OUTPUT_FILE must end with either .h, .c or .o
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 """
223
224
225 def main(argv=None):
226 if argv is None:
227 argv = sys.argv
228
229 try:
230 try:
231 opts, args = getopt.gnu_getopt(argv[1:], "ho:av", ["help", "verbose"])
232 except getopt.error as msg:
233 raise Usage(msg)
234
235 except Usage as err:
236 print(err.msg, file=sys.stderr)
237 print("for help use --help", file=sys.stderr)
238 return 2
239
240 outputNames = []
241 for o, a in opts:
242 if o in ("-h", "--help"):
243 print(usage)
244 return(0)
245 if o in ("-o", ""):
246 outputNames.append(a)
247 if o in ("-a", ""):
248 all = True
249 if o in ("-v", "--verbose"):
250 global verbose
251 verbose = True
252 try:
253 if len(args) == 0:
254 raise Usage("No template file given")
255
256 except Usage as err:
257 print(err.msg, file=sys.stderr)
258 print("for help use --help", file=sys.stderr)
259 return 2
260
261 doCFile = None
262 doHeader = None
263 doObj = None
264 headerFilename = None
265 cFilename = None
266 objFilename = None
267
268 if len(outputNames) > 0:
269 if len(args) > 1:
270 print("Cannot process more than one input if you specify an output")
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":
281 doObj = True
282 objFilename = outputName
283 else:
284 print("output file type unsupported")
285 return(4)
286 else:
287 doHeader = True
288 doCFile = True
289 doObj = True
290
291 # process arguments
292 for arg in args:
293 if arg[-3:] != ".tp":
294 print(arg + " does not end in .tp. Skipping.")
295 continue
296
297 tpl = None
298 try:
299 tpl = TemplateFile(arg)
300 except IOError as args:
301 print("Cannot read input file " + args.filename + " " + args.strerror)
302 return -1
303 try:
304 if doHeader:
305 if headerFilename:
306 curFilename = headerFilename
307 else:
308 curFilename = re.sub("\.tp$", ".h", arg)
309 doth = HeaderFile(curFilename, tpl)
310 doth.write()
311 if doCFile:
312 if cFilename:
313 curFilename = cFilename
314 else:
315 curFilename = re.sub("\.tp$", ".c", arg)
316 dotc = CFile(curFilename, tpl)
317 dotc.write()
318 if doObj:
319 if objFilename:
320 curFilename = objFilename
321 else:
322 curFilename = re.sub("\.tp$", ".o", arg)
323 dotobj = ObjFile(curFilename, tpl)
324 dotobj.write()
325 except IOError as args:
326 print("Cannot write output file " + args.filename + " " + args.strerror)
327 return -1
328
329
330 if __name__ == "__main__":
331 sys.exit(main())
This page took 0.036046 seconds and 3 git commands to generate.