Skip to content
ccc 5.58 KiB
Newer Older
Seo Sanghyeon's avatar
Seo Sanghyeon committed
#!/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
Seo Sanghyeon's avatar
Seo Sanghyeon committed
    sys.exit(1)

def run(args):
    print >> sys.stderr, ' '.join(args)
Seo Sanghyeon's avatar
Seo Sanghyeon committed
    code = subprocess.call(args)
    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'.split()
    run(command + args)

def extension(path):
    return path.rpartition(".")[2]

def changeextension(path, newext):
    components = path.rpartition(".")
    return "".join([components[0], components[1], newext])

def inferlanguage(extension):
    if extension == "c":
        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"

Seo Sanghyeon's avatar
Seo Sanghyeon committed
def main(args):
    action = 'link'
    output = ''
Seo Sanghyeon's avatar
Seo Sanghyeon committed
    link_opts = []
    files = []
    save_temps = 0
    language = ''
    
Seo Sanghyeon's avatar
Seo Sanghyeon committed
    i = 0
    while i < len(args):
        arg = args[i]

        # Modes ccc supports
Seo Sanghyeon's avatar
Seo Sanghyeon committed
        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']:
Seo Sanghyeon's avatar
Seo Sanghyeon committed
            i += 1

        # Prefix matches for the compile mode
        if arg[:2] in ['-D', '-I', '-U', '-F']:
Seo Sanghyeon's avatar
Seo Sanghyeon committed
            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']:
Seo Sanghyeon's avatar
Seo Sanghyeon committed
            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
Seo Sanghyeon's avatar
Seo Sanghyeon committed
        if arg[0] != '-':
            files.append(arg)

        # Output file
        if arg == '-o':
            output = args[i+1]
            i += 1

Seo Sanghyeon's avatar
Seo Sanghyeon committed
        i += 1

    if action == 'print-prog-name':
        # assume we can handle everything
        print sys.argv[0]
        return

Seo Sanghyeon's avatar
Seo Sanghyeon committed
    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 = ''
Seo Sanghyeon's avatar
Seo Sanghyeon committed

    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 = ''
Seo Sanghyeon's avatar
Seo Sanghyeon committed

    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
Seo Sanghyeon's avatar
Seo Sanghyeon committed
                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:])