#!/usr/bin/env python # # The LLVM Compiler Infrastructure # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. # ##===----------------------------------------------------------------------===## # # A reduced version of the 'ccc' script that is designed to handle off # actual compilation to gcc, but run the code passed to gcc through the # static analyzer. # ##===----------------------------------------------------------------------===## import sys import subprocess import os def error(message): print >> sys.stderr, 'ccc: ' + message sys.exit(1) def run(args): print >> sys.stderr, ' '.join(args) print >> sys.stderr, '\n' code = subprocess.call(args) if code > 255: code = 1 if code: sys.exit(code) def preprocess(args): command = 'clang -E'.split() run(command + args) def compile(args): print >> sys.stderr, '\n' command = 'gcc'.split() run(command + args) def remove_pch_extension(path): i = path.rfind('.gch') if i < 0: return path return path[:i] def analyze(args,language,output,files,verbose,htmldir): if language.find("c++") > 0: return print_args = [] if verbose: print >> sys.stderr, ' '.join(['\n[LOCATION]:', os.getcwd(), '\n' ]) i = 0 while i < len(args): print_args.append(''.join([ '\'', args[i], '\'' ])) i += 1 if language.find("header") > 0: target = remove_pch_extension(output) command = 'cp'.split() args = command + files + target.split() else: command = 'clang --grsimple'.split() args = command + args; if htmldir is not None: args.append('-o') print_args.append('-o') args.append(htmldir) print_args.append(htmldir) if verbose: print >> sys.stderr, ' '.join(command+print_args) print >> sys.stderr, '\n' subprocess.call(args) def link(args): command = 'gcc'.split() run(command + args) def extension(path): return path.split(".")[-1] def changeextension(path, newext): i = path.rfind('.') if i < 0: return path j = path.rfind('/', 0, i) print path if j < 0: return path[:i] + "." + newext return path[j+1:i] + "." + newext def inferlanguage(extension): if extension == "c": return "c" elif extension in ["cpp", "cc"]: return "c++" elif extension == "i": return "c-cpp-output" elif extension == "m": return "objective-c" elif extension == "mi": return "objective-c-cpp-output" else: return "unknown" def main(args): old_args = args action = 'link' output = '' compile_opts = [ ] link_opts = [ ] files = [] save_temps = 0 language = '' verbose = 0 if os.environ.get('CCC_ANALYZER_VERBOSE') is not None: verbose =1 htmldir = os.environ.get('CCC_ANALYZER_HTML') i = 0 while i < len(args): arg = args[i] # Modes ccc supports if arg == '-E': action = 'preprocess' if arg == '-c': action = 'compile' if arg.startswith('-print-prog-name'): action = 'print-prog-name' if arg == '-save-temps': save_temps = 1 # Options with no arguments that should pass through if arg in ['-v']: compile_opts.append(arg) link_opts.append(arg) # Options with one argument that should be ignored if arg in ['--param', '-arch', '-u']: i += 1 # Prefix matches for the compile mode if arg[:2] in ['-D', '-I', '-U', '-F']: if not arg[2:]: arg += args[i+1] i += 1 compile_opts.append(arg) if arg[:5] in ['-std=']: compile_opts.append(arg) # Options with one argument that should pass through if arg in ['-include']: compile_opts.append(arg) compile_opts.append(args[i+1]) i += 1 # Prefix matches for the link mode if arg[:2] in ['-l', '-L', '-O', '-F']: if arg == '-O': arg = '-O1' if arg == '-Os': arg = '-O2' link_opts.append(arg) # Options with one argument that should pass through if arg in ['-framework']: link_opts.append(arg) link_opts.append(args[i+1]) i += 1 # Input files if arg == '-filelist': f = open(args[i+1]) for line in f: files.append(line.strip()) f.close() i += 1 if arg == '-x': language = args[i+1] i += 1 if arg[0] != '-': files.append(arg) # Output file if arg == '-o': output = args[i+1] i += 1 i += 1 if action == 'print-prog-name': # assume we can handle everything print sys.argv[0] return if not files: error('no input files') if action == 'preprocess' or save_temps: compile(args) if action == 'compile' or save_temps: for i, file in enumerate(files): if not language: language = inferlanguage(extension(file)) if save_temps and action != "compile": # Need a temporary output file coutput = changeextension(file, "o"); files[i] = coutput elif not output: coutput = changeextension(file, "o") else: coutput = output analyze_args = [ file ] if language != 'unknown': analyze_args = analyze_args + [ '-x', language ] analyze_args = analyze_args + compile_opts analyze(analyze_args, language, output, files, verbose, htmldir) compile(args) if action == 'link': link(args) # analyze(link_opts) if __name__ == '__main__': main(sys.argv[1:])