| #!/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. |
| # |
| ##===----------------------------------------------------------------------===## |
| # |
| # This script attempts to be a drop-in replacement for gcc. |
| # |
| ##===----------------------------------------------------------------------===## |
| |
| import sys |
| import subprocess |
| |
| def error(message): |
| print >> sys.stderr, 'ccc: ' + message |
| sys.exit(1) |
| |
| def quote(arg): |
| if '"' in arg: |
| return repr(arg) |
| return arg |
| |
| def run(args): |
| print ' '.join(map(quote, args)) |
| 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): |
| command = 'clang -emit-llvm-bc'.split() |
| run(command + args) |
| |
| def link(args): |
| command = 'llvm-ld -native -disable-internalize'.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): |
| action = 'link' |
| output = '' |
| compile_opts = [] |
| link_opts = [] |
| files = [] |
| save_temps = 0 |
| language = '' |
| |
| 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', '-u']: |
| i += 1 |
| |
| # Preprocessor options with one argument that should be ignored |
| if arg in ['-MT', '-MF']: |
| 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 to compiler |
| if arg in [ '-include', '-idirafter', '-iprefix', |
| '-iquote', '-isystem', '-iwithprefix', |
| '-iwithprefixbefore']: |
| compile_opts.append(arg) |
| compile_opts.append(args[i+1]) |
| i += 1 |
| |
| # Options with one argument that should pass through |
| if arg in ['-framework']: |
| link_opts.append(arg) |
| link_opts.append(args[i+1]) |
| i += 1 |
| |
| # Options with one argument that should pass through to both |
| if arg in ['-isysroot', '-arch']: |
| compile_opts.append(arg) |
| compile_opts.append(args[i+1]) |
| link_opts.append(arg) |
| link_opts.append(args[i+1]) |
| i += 1 |
| |
| # Prefix matches for the link mode |
| if arg[:2] in ['-l', '-L', '-F']: |
| link_opts.append(arg) |
| |
| # Enable threads |
| if arg == '-pthread': |
| link_opts.append('-lpthread') |
| |
| # 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] |
| compile_opts.append(arg) |
| compile_opts.append(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: |
| for i, file in enumerate(files): |
| if not language: |
| language = inferlanguage(extension(file)) |
| if save_temps and action != 'preprocess': |
| # Need a temporary output file |
| if language == 'c': |
| poutput = changeextension(file, "i"); |
| elif language == 'objective-c': |
| poutput = changeextension(file, "mi"); |
| else: |
| poutput = changeextension(file, "tmp." + extension(file)) |
| files[i] = poutput |
| else: |
| poutput = output |
| if poutput: |
| args = ['-x', language, '-o', poutput, file] + compile_opts |
| else: |
| args = ['-x', language, file] + compile_opts |
| preprocess(args) |
| # Discard the explicit language after used once |
| language = '' |
| |
| 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 |
| args = ['-x', language, '-o', coutput, file] + compile_opts |
| compile(args) |
| language = '' |
| |
| if action == 'link': |
| for i, file in enumerate(files): |
| ext = extension(file) |
| if ext != "o" and ext != "a": |
| out = changeextension(file, "o") |
| args = ['-o', out, file] + compile_opts |
| compile(args) |
| files[i] = out |
| if not output: |
| output = 'a.out' |
| args = ['-o', output] + link_opts + files |
| link(args) |
| |
| if __name__ == '__main__': |
| main(sys.argv[1:]) |