Allow #include in template (.tp) file
[lttng-ust.git] / tools / lttng-gen-tp
CommitLineData
b25c5b37
YB
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
19import sys
20import getopt
21import re
db06a0a2
YB
22import os
23import subprocess
b25c5b37
YB
24
25class Usage(Exception):
26 def __init__(self, msg):
27 self.msg = msg
28
29class HeaderFile:
30 HEADER_TPL="""
31#undef TRACEPOINT_PROVIDER
32#define TRACEPOINT_PROVIDER {providerName}
33
45f399e8
MD
34#undef TRACEPOINT_INCLUDE
35#define TRACEPOINT_INCLUDE "./{headerFilename}"
b25c5b37
YB
36
37#ifdef __cplusplus
9cc0a748
MD
38extern "C"{{
39#endif /* __cplusplus */
b25c5b37
YB
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}}
9cc0a748 55#endif /* __cplusplus */
b25c5b37
YB
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")
739b96c6
YB
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())
b25c5b37
YB
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
75class 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
db06a0a2
YB
97class 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
47eba1fd
YB
148 if verbose:
149 print("Compile command: " + command)
db06a0a2
YB
150 subprocess.call(command.split())
151
b25c5b37
YB
152class 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
47eba1fd
YB
164 #Remove # comments (from input and output file) but keep
165 # #include in the output file
166 removeComments = re.compile("#[^include].*$",flags=re.MULTILINE)
c233fe11 167 self.text = removeComments.sub("",self.text)
47eba1fd
YB
168 # Remove #include directive from the parsed text
169 removePreprocess = re.compile("#.*$",flags=re.MULTILINE)
170 noPreprocess = removePreprocess.sub("", self.text)
b25c5b37 171 #Remove // comments
c233fe11 172 removeLineComment = re.compile("\/\/.*$",flags=re.MULTILINE)
47eba1fd 173 nolinecomment = removeLineComment.sub("", noPreprocess)
b25c5b37
YB
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
47eba1fd
YB
193verbose=False
194
b25c5b37
YB
195usage="""
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.
db06a0a2 202 for example sample.tp will generate sample.h, sample.c and sample.o)
b25c5b37 203
db06a0a2 204 When using the -o option, the OUTPUT_FILE must end with either .h, .c or .o
b25c5b37
YB
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"""
211def main(argv=None):
212 if argv is None:
213 argv = sys.argv
214
215 try:
216 try:
47eba1fd 217 opts, args = getopt.gnu_getopt(argv[1:], "ho:av", ["help","verbose"])
b25c5b37
YB
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
47eba1fd
YB
235 if o in ("-v", "--verbose"):
236 global verbose
237 verbose = True
a719be64
CB
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
b25c5b37
YB
246
247 doCFile = None
248 doHeader = None
db06a0a2 249 doObj = None
b25c5b37
YB
250 headerFilename = None
251 cFilename = None
db06a0a2 252 objFilename = None
b25c5b37
YB
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":
db06a0a2
YB
267 doObj = True
268 objFilename = outputName
b25c5b37
YB
269 else:
270 print "output file type unsupported"
271 return(4)
272 else:
273 doHeader = True
274 doCFile = True
db06a0a2 275 doObj = True
b25c5b37
YB
276
277 # process arguments
278 for arg in args:
7cd5a840
CB
279 if arg[-3:] != ".tp":
280 print arg + " does not end in .tp. Skipping."
281 continue
b25c5b37 282
44745fc1
YB
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
b25c5b37
YB
315if __name__ == "__main__":
316 sys.exit(main())
This page took 0.035861 seconds and 4 git commands to generate.