diff --git a/utils/ccc b/utils/ccc --- a/utils/ccc +++ b/utils/ccc @@ -13,7 +13,7 @@ import os import sys -import subprocess +import subprocess, tempfile def checkenv(name, alternate=None): """checkenv(var, alternate=None) - Return the given environment var, @@ -42,10 +42,11 @@ # We want to support use as CC or LD, so we need different defines. CLANG = checkenv('CLANG', 'clang') +LLVM_LD = checkenv('LLVM_LD', 'llvm-ld') LLC = checkenv('LLC', 'llc') AS = checkenv('AS', 'as') -CC = checkenv('CCC_CC', 'cc') -LD = checkenv('CCC_LD', 'c++') +CC = checkenv('CCC_CC', 'llvm-gcc') +LD = checkenv('CCC_LD', 'llvm-gcc') def error(message): print >> sys.stderr, 'ccc: ' + message @@ -73,15 +74,19 @@ return arg,args[:i]+args[i+1:] return None,args -def run(args): +def run(args, infile=None, outfile=None, wait=True): if CCC_ECHO: print ' '.join(map(quote, args)) sys.stdout.flush() - code = subprocess.call(args) - if code > 255: - code = 1 - if code: - sys.exit(code) + + if wait: + code = subprocess.call(args, 0, None, infile, outfile) + if code > 255: + code = 1 + if code: + sys.exit(code) + else: + return subprocess.Popen(args, 0, None, infile, outfile) def remove(path): """remove(path) -> bool - Attempt to remove the file at path (if any). @@ -104,56 +109,62 @@ command = [CLANG,'-fsyntax-only'] run(command + args) -def compile_fallback(args): +def compile_fallback(args, save_temps=False, pipe=False): command = [CC,'-c'] + if save_temps: + commands += ['-save-temps'] + if pipe: + commands += ['-pipe'] run(command + args) -def compile(args, native, save_temps=False): +def compile(args, native, save_temps, pipe): if native: output,args = stripoutput(args) if not output: raise ValueError,'Expected to always have explicit -o in compile()' - # I prefer suffixing these to changing the extension, which is - # more likely to overwrite other things. We could of course - # use temp files. - bc_output = output + '.bc' - s_output = output + '.s' - command = [CLANG,'-emit-llvm-bc'] - try: - run(command + args + ['-o', bc_output]) - # FIXME: What controls relocation model? - run([LLC, '-relocation-model=pic', '-f', '-o', s_output, bc_output]) - run([AS, '-o', output, s_output]) - finally: - if not save_temps: - remove(bc_output) - remove(s_output) + if pipe: + command = [CLANG, '-S', '-o', '-'] + args + compiler = run(command, None, subprocess.PIPE, False) + run([AS, '-o', output], compiler.stdout) + else: + tempfd, tempnam = tempfile.mkstemp('.s') + try: + run([CLANG, '-S', '-o', tempnam] + args) + run([AS, '-o', output, tempnam]) + finally: + if not save_temps: + remove(tempnam) else: command = [CLANG,'-emit-llvm-bc'] run(command + args) -def checked_compile(args, native, language, save_temps): +def checked_compile(args, native, language, save_temps=False, pipe=False): if CCC_LANGUAGES and language and language not in CCC_LANGUAGES: log('fallback', args) print >>sys.stderr, 'NOTE: ccc: Using fallback compiler for: %s'%(' '.join(map(quote, args)),) - compile_fallback(args) + compile_fallback(args, save_temps, pipe) elif CCC_FALLBACK: try: - compile(args, native, save_temps) + compile(args, native, save_temps, pipe) except: log('fallback-on-fail', args) print >>sys.stderr, 'WARNING: ccc: Using fallback compiler for: %s'%(' '.join(map(quote, args)),) - compile_fallback(args) + compile_fallback(args, save_temps, pipe) else: - compile(args, native, save_temps) + compile(args, native, save_temps, pipe) -def link(args, native): +def link(args, output, native, is_library, save_temps=False, pipe=False): + # TODO: implement `pipe' somehow if native: - run([LD] + args) + run([LD, '-o', output] + args) else: - command = ['llvm-ld', '-native', '-disable-internalize'] + command = [LLVM_LD, '-native', '-o', output] + if is_library: + command += ['-disable-internalize'] run(command + args) + if not save_temps: + remove(os.path.splitext(output)[0] + '.bc') def extension(path): return path.split(".")[-1] @@ -208,12 +219,15 @@ def main(args): log('invoke', args) + relocation_model = None + link_library = False action = inferaction(args) output = '' compile_opts = [] link_opts = [] files = [] - save_temps = 0 + save_temps = False + pipe = False language = '' native = CCC_NATIVE @@ -228,23 +242,56 @@ # Modes ccc supports if arg == '-save-temps': - save_temps = 1 - if arg == '-emit-llvm' or arg == '--emit-llvm': + save_temps = True + if arg == '-emit-llvm' or arg == '--emit-llvm' or arg == '-flto': native = False + if arg == '-pipe': + pipe = True + if arg == '-v': + global CCC_ECHO + if CCC_ECHO: + compile_opts.append(arg) + link_opts.append(arg) + else: + CCC_ECHO = True + # Options with no arguments that should pass through - if arg in ['-v', '-fobjc-gc', '-fobjc-gc-only', '-fnext-runtime', - '-fgnu-runtime']: + if arg in ['-fobjc-gc', '-fobjc-gc-only', '-fnext-runtime', + '-fgnu-runtime', '-MD', '-MMD', '-MP', '', + '-fms-extensions', '-fblocks', '-flax-vector-conversions', + '-fwritable-strings', '-fpascal-strings', + '-Werror', '-Wfloat-equal', '-w']: compile_opts.append(arg) link_opts.append(arg) - + # Options with one argument that should be ignored - if arg in ['--param', '-u']: + if arg in ['--param']: i += 1 - # Preprocessor options with one argument that should be ignored - if arg in ['-MT', '-MF']: - i += 1 + if arg == '-static': + relocation_model = 'static' + + if arg in ['-mdynamic-no-pic', '-fno-pic', '-fno-PIC']: + relocation_model = 'dynamic-no-pic' + + if arg in ['-fPIC', '-fpic']: + relocation_model = 'pic' + + if arg == '-Wimplicit': + compile_opts.append('-Wimplicit-function-declaration') + if arg == '-Wuninitialized': + compile_opts.append('-warn-uninit-values') + + if arg == '-Wall': + compile_opts += ['-warn-uninit-values', '-warn-objc-unused-ivars', + '-warn-objc-methodsigs', '-warn-objc-missing-dealloc', + '-Wimplicit-function-declaration'] + + if arg in ['-Wextra', '-W']: + compile_opts += ['-warn-uninit-values', '-warn-objc-unused-ivars', + '-warn-objc-methodsigs', '-warn-objc-missing-dealloc', + '-checker-cfref', '-warn-dead-stores'] # Prefix matches for the compile mode if arg[:2] in ['-D', '-I', '-U', '-F']: @@ -260,32 +307,60 @@ if arg in ('-g', '-gdwarf-2'): compile_opts.append('-g') + # Optimization options + for lvl in range(0,9): + if (arg != '-O' + str(lvl)): + continue + if (lvl > 3): + native = False + lvl = 3 + compile_opts = [p for p in compile_opts if p[:-1] != '-O'] + compile_opts.append('-O' + str(lvl)) + # Options with one argument that should pass through to compiler if arg in [ '-include', '-idirafter', '-iprefix', '-iquote', '-isystem', '-iwithprefix', - '-iwithprefixbefore']: + '-iwithprefixbefore', '-MT', '-MF']: compile_opts.append(arg) compile_opts.append(args[i+1]) i += 1 - # Options with no arguments that should pass through - if (arg in ('-dynamiclib', '-bundle', '-headerpad_max_install_names', - '-nostdlib', '-static', '-dynamic', '-r') or - arg.startswith('-Wl,')): + # Options with no arguments that should pass through to linker + if (arg in ('-dynamiclib', '-bundle', '-static', '-dynamic', '-r')): link_opts.append(arg) + link_library = True - # Options with one argument that should pass through + # Options with no arguments that should pass through to linker + if (arg in ('-headerpad_max_install_names', '-nostdlib', + '-dead_strip_dylibs', '-dead_strip')): + link_opts.append('-Xlinker') + link_opts.append(arg) + # Use alternate, more compatible syntax + if (arg.startswith('-Wl,')): + for subarg in arg[4:].split(','): + link_opts += ['-Xlinker', subarg] + + # Options with one argument that should pass through to linker + if arg == '-Xlinker': + link_opts.append(arg) + link_opts.append(args[i+1]) + i += 1 + + # Options with one argument that should pass wrapped to linker if arg in ('-framework', '-multiply_defined', '-bundle_loader', '-weak_framework', '-e', '-install_name', '-unexported_symbols_list', '-exported_symbols_list', '-compatibility_version', '-current_version', '-init', - '-seg1addr', '-dylib_file', '-Xlinker'): + '-seg1addr', '-dylib_file'): + link_opts.append('-Xlinker') link_opts.append(arg) + link_opts.append('-Xlinker') link_opts.append(args[i+1]) i += 1 # Options with one argument that should pass through to both + # linker and compiler if arg in ['-isysroot', '-arch']: compile_opts.append(arg) compile_opts.append(args[i+1]) @@ -293,7 +368,7 @@ link_opts.append(args[i+1]) i += 1 - # Options with three arguments that should pass through + # Options with three arguments that should pass through to linker if arg in ('-sectorder',): link_opts.extend(args[i:i+4]) i += 3 @@ -325,6 +400,10 @@ i += 1 i += 1 + + if relocation_model: + compile_opts.append('-relocation-model=' + relocation_model) + link_opts.append('-relocation-model=' + relocation_model) if action == 'print-prog-name': # assume we can handle everything @@ -387,7 +466,7 @@ if language: args.extend(['-x', language]) args += ['-o', coutput, file] + compile_opts - checked_compile(args, native, language, save_temps) + checked_compile(args, native, language, save_temps, pipe) language = '' if action == 'link': @@ -395,19 +474,19 @@ if not language: language = inferlanguage(extension(file)) ext = extension(file) - if ext != "o" and ext != "a" and ext != "so": + if ext and ext != "o" and ext != "a" and ext != "so": out = changeextension(file, "o") args = [] if language: args.extend(['-x', language]) args = ['-o', out, file] + compile_opts - checked_compile(args, native, language, save_temps) + checked_compile(args, native, language, save_temps, pipe) language = '' files[i] = out if not output: output = 'a.out' - args = ['-o', output] + files + link_opts - link(args, native) + args = files + link_opts + link(args, output, native, link_library, save_temps, pipe) if __name__ == '__main__': main(sys.argv[1:])