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