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