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