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