5937dfdfe1793f61b46c43e544d41f2b109d0674
[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 subprocess.call(command.split())
149
150 class TemplateFile:
151 def __init__(self, filename):
152 self.domain = ""
153 self.inputFilename = filename
154 self.parseTemplate()
155
156
157 def parseTemplate(self):
158 f = open(self.inputFilename,"r")
159
160 self.text = f.read()
161
162 #Remove # comments (from input and output file
163 removeComments = re.compile("#.*$",flags=re.MULTILINE)
164 self.text = removeComments.sub("",self.text)
165 #Remove // comments
166 removeLineComment = re.compile("\/\/.*$",flags=re.MULTILINE)
167 nolinecomment = removeLineComment.sub("",self.text)
168 #Remove all spaces and lines
169 cleantext = re.sub("\s*","",nolinecomment)
170 #Remove multine C style comments
171 nocomment = re.sub("/\*.*?\*/","",cleantext)
172 entries = re.split("TRACEPOINT_.*?",nocomment)
173
174 for entry in entries:
175 if entry != '':
176 decomp = re.findall("(\w*?)\((\w*?),(\w*?),", entry)
177 typea = decomp[0][0]
178 domain = decomp[0][1]
179 name = decomp[0][2]
180
181 if self.domain == "":
182 self.domain = domain
183 else:
184 if self.domain != domain:
185 print "Warning: different domain provided (%s,%s)" % (self.domain, domain)
186
187 usage="""
188 lttng-gen-tp - Generate the LTTng-UST header and source based on a simple template
189
190 usage: lttng-gen-tp TEMPLATE_FILE [-o OUTPUT_FILE][-o OUTPUT_FILE]
191
192 If no OUTPUT_FILE is given, the .h and .c file will be generated.
193 (The basename of the template file with be used for the generated file.
194 for example sample.tp will generate sample.h, sample.c and sample.o)
195
196 When using the -o option, the OUTPUT_FILE must end with either .h, .c or .o
197 The -o option can be repeated multiple times.
198
199 The template file must contains TRACEPOINT_EVENT and TRACEPOINT_LOGLEVEL
200 as per defined in the lttng/tracepoint.h file.
201 See the lttng-ust(3) man page for more details on the format.
202 """
203 def main(argv=None):
204 if argv is None:
205 argv = sys.argv
206
207 try:
208 try:
209 opts, args = getopt.gnu_getopt(argv[1:], "ho:a", ["help"])
210 except getopt.error, msg:
211 raise Usage(msg)
212
213 except Usage, err:
214 print >>sys.stderr, err.msg
215 print >>sys.stderr, "for help use --help"
216 return 2
217
218 outputNames = []
219 for o, a in opts:
220 if o in ("-h", "--help"):
221 print usage
222 return(0)
223 if o in ("-o",""):
224 outputNames.append(a)
225 if o in ("-a",""):
226 all = True
227 try:
228 if len(args) == 0:
229 raise Usage("No template file given")
230
231 except Usage, err:
232 print >>sys.stderr, err.msg
233 print >>sys.stderr, "for help use --help"
234 return 2
235
236 doCFile = None
237 doHeader = None
238 doObj = None
239 headerFilename = None
240 cFilename = None
241 objFilename = None
242
243 if len(outputNames) > 0:
244 if len(args) > 1:
245 print "Cannot process more than one input if you specify an output"
246 return(3)
247
248 for outputName in outputNames:
249 if outputName[-2:] == ".h":
250 doHeader = True
251 headerFilename = outputName
252 elif outputName[-2:] == ".c":
253 doCFile = True
254 cFilename = outputName
255 elif outputName[-2:] == ".o":
256 doObj = True
257 objFilename = outputName
258 else:
259 print "output file type unsupported"
260 return(4)
261 else:
262 doHeader = True
263 doCFile = True
264 doObj = True
265
266 # process arguments
267 for arg in args:
268 if arg[-3:] != ".tp":
269 print arg + " does not end in .tp. Skipping."
270 continue
271
272 tpl = None
273 try:
274 tpl = TemplateFile(arg)
275 except IOError as args:
276 print "Cannot read input file " + args.filename + " " + args.strerror
277 return -1
278 try:
279 if doHeader:
280 if headerFilename:
281 curFilename = headerFilename
282 else:
283 curFilename = re.sub("\.tp$",".h",arg)
284 doth = HeaderFile(curFilename, tpl)
285 doth.write()
286 if doCFile:
287 if cFilename:
288 curFilename = cFilename
289 else:
290 curFilename = re.sub("\.tp$",".c",arg)
291 dotc = CFile(curFilename, tpl)
292 dotc.write()
293 if doObj:
294 if objFilename:
295 curFilename = objFilename
296 else:
297 curFilename = re.sub("\.tp$",".o",arg)
298 dotobj = ObjFile(curFilename, tpl)
299 dotobj.write()
300 except IOError as args:
301 print "Cannot write output file " + args.filename + " " + args.strerror
302 return -1
303
304 if __name__ == "__main__":
305 sys.exit(main())
This page took 0.035665 seconds and 3 git commands to generate.