#!/usr/bin/python # # Copyright (c) 2012 Yannick Brosseau # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; only version 2 # of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import sys import getopt import re import os import subprocess class Usage(Exception): def __init__(self, msg): self.msg = msg class HeaderFile: HEADER_TPL=""" #undef TRACEPOINT_PROVIDER #define TRACEPOINT_PROVIDER {providerName} #undef TRACEPOINT_INCLUDE_FILE #define TRACEPOINT_INCLUDE_FILE ./{headerFilename} #ifdef __cplusplus extern "C"{{ #endif /* __cplusplus */ #if !defined({includeGuard}) || defined(TRACEPOINT_HEADER_MULTI_READ) #define {includeGuard} #include """ FOOTER_TPL=""" #endif /* {includeGuard} */ #include #ifdef __cplusplus }} #endif /* __cplusplus */ """ def __init__(self, filename, template): self.outputFilename = filename self.template = template def write(self): outputFile = open(self.outputFilename,"w") includeGuard = "_"+self.outputFilename.upper().replace(".","_") outputFile.write(HeaderFile.HEADER_TPL.format(providerName=self.template.domain, includeGuard = includeGuard, headerFilename = self.outputFilename)) outputFile.write(self.template.text) outputFile.write(HeaderFile.FOOTER_TPL.format(includeGuard = includeGuard)) outputFile.close() class CFile: FILE_TPL=""" #define TRACEPOINT_CREATE_PROBES /* * The header containing our TRACEPOINT_EVENTs. */ #define TRACEPOINT_DEFINE #include "{headerFilename}" """ def __init__(self, filename, template): self.outputFilename = filename self.template = template def write(self): outputFile = open(self.outputFilename,"w") headerFilename = self.outputFilename.replace(".c",".h") outputFile.write(CFile.FILE_TPL.format( headerFilename = headerFilename)) outputFile.close() class ObjFile: def __init__(self, filename, template): self.outputFilename = filename self.template = template def _detectCC(self): cc = "" if os.environ.has_key('CC'): cc = os.environ['CC'] try: subprocess.call(cc, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError, msg: print "Invalid CC environment variable" cc = "" else: # Try c first, if that fails try gcc try: useCC = True subprocess.call("cc", stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError, msg: useCC = False if useCC: cc = "cc" else: try: useGCC = True subprocess.call("gcc", stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError, msg: useGCC = False if useGCC: cc = "gcc" return cc def write(self): cFilename = self.outputFilename.replace(".o",".c") cc = self._detectCC() if cc == "": raise RuntimeError("No C Compiler detected") if os.environ.has_key('CFLAGS'): cflags = os.environ['CFLAGS'] else: cflags = "" command = cc + " -c " + cflags + " -I. -llttng-ust" + " -o " + self.outputFilename + " " + cFilename subprocess.call(command.split()) class TemplateFile: def __init__(self, filename): self.domain = "" self.inputFilename = filename self.parseTemplate() def parseTemplate(self): f = open(self.inputFilename,"r") self.text = f.read() #Remove # comments (from input and output file removeComments = re.compile("#.*$",flags=re.MULTILINE) self.text = removeComments.sub("",self.text) #Remove // comments removeLineComment = re.compile("\/\/.*$",flags=re.MULTILINE) nolinecomment = removeLineComment.sub("",self.text) #Remove all spaces and lines cleantext = re.sub("\s*","",nolinecomment) #Remove multine C style comments nocomment = re.sub("/\*.*?\*/","",cleantext) entries = re.split("TRACEPOINT_.*?",nocomment) for entry in entries: if entry != '': decomp = re.findall("(\w*?)\((\w*?),(\w*?),", entry) typea = decomp[0][0] domain = decomp[0][1] name = decomp[0][2] if self.domain == "": self.domain = domain else: if self.domain != domain: print "Warning: different domain provided (%s,%s)" % (self.domain, domain) usage=""" lttng-gen-tp - Generate the LTTng-UST header and source based on a simple template usage: lttng-gen-tp TEMPLATE_FILE [-o OUTPUT_FILE][-o OUTPUT_FILE] If no OUTPUT_FILE is given, the .h and .c file will be generated. (The basename of the template file with be used for the generated file. for example sample.tp will generate sample.h, sample.c and sample.o) When using the -o option, the OUTPUT_FILE must end with either .h, .c or .o The -o option can be repeated multiple times. The template file must contains TRACEPOINT_EVENT and TRACEPOINT_LOGLEVEL as per defined in the lttng/tracepoint.h file. See the lttng-ust(3) man page for more details on the format. """ def main(argv=None): if argv is None: argv = sys.argv try: try: opts, args = getopt.gnu_getopt(argv[1:], "ho:a", ["help"]) except getopt.error, msg: raise Usage(msg) if len(args) == 0: raise Usage("No template file given") except Usage, err: print >>sys.stderr, err.msg print >>sys.stderr, "for help use --help" return 2 outputNames = [] for o, a in opts: if o in ("-h", "--help"): print usage return(0) if o in ("-o",""): outputNames.append(a) if o in ("-a",""): all = True doCFile = None doHeader = None doObj = None headerFilename = None cFilename = None objFilename = None if len(outputNames) > 0: if len(args) > 1: print "Cannot process more than one input if you specify an output" return(3) for outputName in outputNames: if outputName[-2:] == ".h": doHeader = True headerFilename = outputName elif outputName[-2:] == ".c": doCFile = True cFilename = outputName elif outputName[-2:] == ".o": doObj = True objFilename = outputName else: print "output file type unsupported" return(4) else: doHeader = True doCFile = True doObj = True # process arguments for arg in args: tpl = None try: tpl = TemplateFile(arg) except IOError as args: print "Cannot read input file " + args.filename + " " + args.strerror return -1 try: if doHeader: if headerFilename: curFilename = headerFilename else: curFilename = re.sub("\.tp$",".h",arg) doth = HeaderFile(curFilename, tpl) doth.write() if doCFile: if cFilename: curFilename = cFilename else: curFilename = re.sub("\.tp$",".c",arg) dotc = CFile(curFilename, tpl) dotc.write() if doObj: if objFilename: curFilename = objFilename else: curFilename = re.sub("\.tp$",".o",arg) dotobj = ObjFile(curFilename, tpl) dotobj.write() except IOError as args: print "Cannot write output file " + args.filename + " " + args.strerror return -1 if __name__ == "__main__": sys.exit(main())