b62cd9907618207de72604e947a3b0ab11df9558
[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.replace(".c",".h")
83
84 outputFile.write(CFile.FILE_TPL.format(
85 headerFilename = headerFilename))
86 outputFile.close()
87
88 class ObjFile:
89 def __init__(self, filename, template):
90 self.outputFilename = filename
91 self.template = template
92 def _detectCC(self):
93 cc = ""
94 if 'CC' in os.environ:
95 cc = os.environ['CC']
96 try:
97 subprocess.call(cc.split(),
98 stdout=subprocess.PIPE,
99 stderr=subprocess.PIPE)
100 except OSError as msg:
101 print("Invalid CC environment variable")
102 cc = ""
103
104 else:
105 # Try c first, if that fails try gcc
106 try:
107 useCC = True
108 subprocess.call("cc",
109 stdout=subprocess.PIPE,
110 stderr=subprocess.PIPE)
111 except OSError as msg:
112 useCC = False
113 if useCC:
114 cc = "cc"
115
116 else:
117 try:
118 useGCC = True
119 subprocess.call("gcc",
120 stdout=subprocess.PIPE,
121 stderr=subprocess.PIPE)
122 except OSError as msg:
123 useGCC = False
124 if useGCC:
125 cc = "gcc"
126 return cc
127
128 def write(self):
129 cFilename = self.outputFilename.replace(".o",".c")
130 cc = self._detectCC()
131 if cc == "":
132 raise RuntimeError("No C Compiler detected")
133 if 'CPPFLAGS' in os.environ:
134 cppflags = " " + os.environ['CPPFLAGS']
135 else:
136 cppflags = ""
137 if 'CFLAGS' in os.environ:
138 cflags = " " + os.environ['CFLAGS']
139 else:
140 cflags = ""
141 if 'LDFLAGS' in os.environ:
142 ldflags = " " + os.environ['LDFLAGS']
143 else:
144 ldflags = ""
145
146 command = cc + " -c" + cppflags + cflags + ldflags + " -I. -llttng-ust" + " -o " + self.outputFilename + " " + cFilename
147 if verbose:
148 print("Compile command: " + command)
149 subprocess.call(command.split())
150
151 class TemplateFile:
152 def __init__(self, filename):
153 self.domain = ""
154 self.inputFilename = filename
155 self.parseTemplate()
156
157
158 def parseTemplate(self):
159 f = open(self.inputFilename,"r")
160
161 self.text = f.read()
162
163 #Remove # comments (from input and output file) but keep
164 # #include in the output file
165 removeComments = re.compile("#[^include].*$",flags=re.MULTILINE)
166 self.text = removeComments.sub("",self.text)
167 # Remove #include directive from the parsed text
168 removePreprocess = re.compile("#.*$",flags=re.MULTILINE)
169 noPreprocess = removePreprocess.sub("", self.text)
170 #Remove // comments
171 removeLineComment = re.compile("\/\/.*$",flags=re.MULTILINE)
172 nolinecomment = removeLineComment.sub("", noPreprocess)
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)
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:
190 print("Warning: different domain provided (%s,%s)" % (self.domain, domain))
191
192 verbose=False
193
194 usage="""
195 lttng-gen-tp - Generate the LTTng-UST header and source based on a simple template
196
197 usage: lttng-gen-tp TEMPLATE_FILE [-o OUTPUT_FILE][-o OUTPUT_FILE]
198
199 If no OUTPUT_FILE is given, the .h and .c file will be generated.
200 (The basename of the template file with be used for the generated file.
201 for example sample.tp will generate sample.h, sample.c and sample.o)
202
203 When using the -o option, the OUTPUT_FILE must end with either .h, .c or .o
204 The -o option can be repeated multiple times.
205
206 The template file must contains TRACEPOINT_EVENT and TRACEPOINT_LOGLEVEL
207 as per defined in the lttng/tracepoint.h file.
208 See the lttng-ust(3) man page for more details on the format.
209 """
210 def main(argv=None):
211 if argv is None:
212 argv = sys.argv
213
214 try:
215 try:
216 opts, args = getopt.gnu_getopt(argv[1:], "ho:av", ["help","verbose"])
217 except getopt.error as msg:
218 raise Usage(msg)
219
220 except Usage as err:
221 print(err.msg, file=sys.stderr)
222 print("for help use --help", file=sys.stderr)
223 return 2
224
225 outputNames = []
226 for o, a in opts:
227 if o in ("-h", "--help"):
228 print(usage)
229 return(0)
230 if o in ("-o",""):
231 outputNames.append(a)
232 if o in ("-a",""):
233 all = True
234 if o in ("-v", "--verbose"):
235 global verbose
236 verbose = True
237 try:
238 if len(args) == 0:
239 raise Usage("No template file given")
240
241 except Usage as err:
242 print(err.msg, file=sys.stderr)
243 print("for help use --help", file=sys.stderr)
244 return 2
245
246 doCFile = None
247 doHeader = None
248 doObj = None
249 headerFilename = None
250 cFilename = None
251 objFilename = None
252
253 if len(outputNames) > 0:
254 if len(args) > 1:
255 print("Cannot process more than one input if you specify an output")
256 return(3)
257
258 for outputName in outputNames:
259 if outputName[-2:] == ".h":
260 doHeader = True
261 headerFilename = outputName
262 elif outputName[-2:] == ".c":
263 doCFile = True
264 cFilename = outputName
265 elif outputName[-2:] == ".o":
266 doObj = True
267 objFilename = outputName
268 else:
269 print("output file type unsupported")
270 return(4)
271 else:
272 doHeader = True
273 doCFile = True
274 doObj = True
275
276 # process arguments
277 for arg in args:
278 if arg[-3:] != ".tp":
279 print(arg + " does not end in .tp. Skipping.")
280 continue
281
282 tpl = None
283 try:
284 tpl = TemplateFile(arg)
285 except IOError as args:
286 print("Cannot read input file " + args.filename + " " + args.strerror)
287 return -1
288 try:
289 if doHeader:
290 if headerFilename:
291 curFilename = headerFilename
292 else:
293 curFilename = re.sub("\.tp$",".h",arg)
294 doth = HeaderFile(curFilename, tpl)
295 doth.write()
296 if doCFile:
297 if cFilename:
298 curFilename = cFilename
299 else:
300 curFilename = re.sub("\.tp$",".c",arg)
301 dotc = CFile(curFilename, tpl)
302 dotc.write()
303 if doObj:
304 if objFilename:
305 curFilename = objFilename
306 else:
307 curFilename = re.sub("\.tp$",".o",arg)
308 dotobj = ObjFile(curFilename, tpl)
309 dotobj.write()
310 except IOError as args:
311 print("Cannot write output file " + args.filename + " " + args.strerror)
312 return -1
313
314 if __name__ == "__main__":
315 sys.exit(main())
This page took 0.03537 seconds and 3 git commands to generate.