2008-01-10 04:43:47 +03:00
|
|
|
#!/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.
|
|
|
|
#
|
|
|
|
##===----------------------------------------------------------------------===##
|
|
|
|
|
2008-08-24 02:15:15 +04:00
|
|
|
import os
|
2008-01-10 04:43:47 +03:00
|
|
|
import sys
|
2008-02-06 22:03:27 +03:00
|
|
|
import subprocess
|
2008-01-10 04:43:47 +03:00
|
|
|
|
2008-08-24 02:15:15 +04:00
|
|
|
def checkenv(name, alternate=None):
|
|
|
|
"""checkenv(var, alternate=None) - Return the given environment var,
|
|
|
|
or alternate if it is undefined or empty."""
|
|
|
|
v = os.getenv(name)
|
|
|
|
if v and v.strip():
|
|
|
|
return v.strip()
|
|
|
|
return alternate
|
|
|
|
|
|
|
|
CCC_ECHO = checkenv('CCC_ECHO','1')
|
|
|
|
CCC_NATIVE = checkenv('CCC_NATIVE')
|
2008-08-30 01:03:27 +04:00
|
|
|
CCC_FALLBACK = checkenv('CCC_FALLBACK')
|
2008-09-02 14:27:37 +04:00
|
|
|
CCC_LANGUAGES = checkenv('CCC_LANGUAGES','c,c++,c-cpp-output,objective-c,objective-c++,objective-c-cpp-output')
|
2008-08-30 01:03:27 +04:00
|
|
|
if CCC_LANGUAGES:
|
|
|
|
CCC_LANGUAGES = set([s.strip() for s in CCC_LANGUAGES.split(',')])
|
2008-08-24 02:15:15 +04:00
|
|
|
|
|
|
|
# We want to support use as CC or LD, so we need different defines.
|
|
|
|
CLANG = checkenv('CLANG', 'clang')
|
|
|
|
LLC = checkenv('LLC', 'llc')
|
|
|
|
AS = checkenv('AS', 'as')
|
|
|
|
CC = checkenv('CCC_CC', 'cc')
|
|
|
|
LD = checkenv('CCC_LD', 'c++')
|
|
|
|
|
2008-01-10 04:43:47 +03:00
|
|
|
def error(message):
|
2008-01-29 10:21:34 +03:00
|
|
|
print >> sys.stderr, 'ccc: ' + message
|
2008-01-10 04:43:47 +03:00
|
|
|
sys.exit(1)
|
|
|
|
|
2008-04-04 15:02:21 +04:00
|
|
|
def quote(arg):
|
2008-08-30 01:03:27 +04:00
|
|
|
if '"' in arg or ' ' in arg:
|
2008-04-04 15:02:21 +04:00
|
|
|
return repr(arg)
|
|
|
|
return arg
|
|
|
|
|
2008-08-24 02:15:15 +04:00
|
|
|
def stripoutput(args):
|
|
|
|
"""stripoutput(args) -> (output_name, newargs)
|
|
|
|
|
|
|
|
Remove the -o argument from the arg list and return the output
|
|
|
|
filename and a new argument list. Assumes there will be at most
|
|
|
|
one -o option. If no output argument is found the result is (None,
|
|
|
|
args)."""
|
|
|
|
for i,a in enumerate(args):
|
|
|
|
if a.startswith('-o'):
|
|
|
|
if a=='-o':
|
|
|
|
if i+1<len(args):
|
|
|
|
return args[i+1],args[:i]+args[i+2:]
|
|
|
|
elif a.startswith('-o='):
|
|
|
|
opt,arg = a.split('=',1)
|
|
|
|
return arg,args[:i]+args[i+1:]
|
|
|
|
return None,args
|
|
|
|
|
2008-01-10 04:43:47 +03:00
|
|
|
def run(args):
|
2008-08-24 02:15:15 +04:00
|
|
|
if CCC_ECHO:
|
|
|
|
print ' '.join(map(quote, args))
|
2008-08-30 01:03:27 +04:00
|
|
|
sys.stdout.flush()
|
2008-02-06 22:03:27 +03:00
|
|
|
code = subprocess.call(args)
|
2008-02-04 00:27:46 +03:00
|
|
|
if code > 255:
|
|
|
|
code = 1
|
2008-01-10 04:43:47 +03:00
|
|
|
if code:
|
|
|
|
sys.exit(code)
|
|
|
|
|
2008-08-24 02:15:15 +04:00
|
|
|
def remove(path):
|
|
|
|
"""remove(path) -> bool - Attempt to remove the file at path (if any).
|
|
|
|
|
|
|
|
The result indicates if the remove was successful. A warning is
|
|
|
|
printed if there is an error removing the file."""
|
|
|
|
if os.path.exists(path):
|
|
|
|
try:
|
|
|
|
os.remove(path)
|
|
|
|
except:
|
|
|
|
print >>sys.stderr, 'WARNING: Unable to remove temp "%s"'%(path,)
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
2008-01-10 04:43:47 +03:00
|
|
|
def preprocess(args):
|
2008-08-24 02:15:15 +04:00
|
|
|
command = [CLANG,'-E']
|
2008-02-06 22:03:27 +03:00
|
|
|
run(command + args)
|
2008-01-10 04:43:47 +03:00
|
|
|
|
2008-08-30 01:03:27 +04:00
|
|
|
def compile_fallback(args):
|
|
|
|
command = [CC,'-c']
|
|
|
|
run(command + args)
|
|
|
|
|
2008-08-24 02:15:15 +04:00
|
|
|
def compile(args, native, save_temps=False):
|
|
|
|
if native:
|
|
|
|
output,args = stripoutput(args)
|
|
|
|
if not output:
|
|
|
|
raise ValueError,'Expected to always have explicit -o in compile()'
|
2008-01-10 04:43:47 +03:00
|
|
|
|
2008-08-24 02:15:15 +04:00
|
|
|
# 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']
|
2008-08-30 01:03:27 +04:00
|
|
|
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)
|
2008-08-24 02:15:15 +04:00
|
|
|
else:
|
|
|
|
command = [CLANG,'-emit-llvm-bc']
|
|
|
|
run(command + args)
|
|
|
|
|
2008-08-30 01:03:27 +04:00
|
|
|
def checked_compile(args, native, language, save_temps):
|
|
|
|
if CCC_LANGUAGES and language and language not in CCC_LANGUAGES:
|
|
|
|
print >>sys.stderr, 'NOTE: ccc: Using fallback compiler for: %s'%(' '.join(map(quote, args)),)
|
|
|
|
compile_fallback(args)
|
|
|
|
elif CCC_FALLBACK:
|
|
|
|
try:
|
|
|
|
compile(args, native, save_temps)
|
|
|
|
except:
|
|
|
|
print >>sys.stderr, 'WARNING: ccc: Using fallback compiler for: %s'%(' '.join(map(quote, args)),)
|
|
|
|
compile_fallback(args)
|
|
|
|
else:
|
|
|
|
compile(args, native, save_temps)
|
|
|
|
|
2008-08-24 02:15:15 +04:00
|
|
|
def link(args, native):
|
|
|
|
if native:
|
2008-08-30 01:03:27 +04:00
|
|
|
run([LD] + args)
|
2008-08-24 02:15:15 +04:00
|
|
|
else:
|
|
|
|
command = ['llvm-ld', '-native', '-disable-internalize']
|
|
|
|
run(command + args)
|
2008-01-10 04:43:47 +03:00
|
|
|
|
2008-01-29 10:21:34 +03:00
|
|
|
def extension(path):
|
2008-02-03 06:40:41 +03:00
|
|
|
return path.split(".")[-1]
|
2008-01-29 10:21:34 +03:00
|
|
|
|
|
|
|
def changeextension(path, newext):
|
2008-02-03 06:40:41 +03:00
|
|
|
i = path.rfind('.')
|
|
|
|
if i < 0:
|
|
|
|
return path
|
2008-02-04 00:27:46 +03:00
|
|
|
j = path.rfind('/', 0, i)
|
|
|
|
if j < 0:
|
|
|
|
return path[:i] + "." + newext
|
|
|
|
return path[j+1:i] + "." + newext
|
2008-01-29 10:21:34 +03:00
|
|
|
|
|
|
|
def inferlanguage(extension):
|
|
|
|
if extension == "c":
|
|
|
|
return "c"
|
2008-02-16 01:35:25 +03:00
|
|
|
elif extension in ["cpp", "cc"]:
|
|
|
|
return "c++"
|
2008-01-29 10:21:34 +03:00
|
|
|
elif extension == "i":
|
|
|
|
return "c-cpp-output"
|
|
|
|
elif extension == "m":
|
|
|
|
return "objective-c"
|
2008-08-30 01:03:27 +04:00
|
|
|
elif extension == "mm":
|
|
|
|
return "objective-c++"
|
2008-01-29 10:21:34 +03:00
|
|
|
elif extension == "mi":
|
|
|
|
return "objective-c-cpp-output"
|
2008-09-02 14:27:37 +04:00
|
|
|
elif extension == "s":
|
|
|
|
return "assembler"
|
|
|
|
elif extension == "S":
|
|
|
|
return "assembler-with-cpp"
|
2008-01-29 10:21:34 +03:00
|
|
|
else:
|
|
|
|
return "unknown"
|
|
|
|
|
2008-01-10 04:43:47 +03:00
|
|
|
def main(args):
|
|
|
|
action = 'link'
|
|
|
|
output = ''
|
2008-01-25 17:57:54 +03:00
|
|
|
compile_opts = []
|
2008-01-10 04:43:47 +03:00
|
|
|
link_opts = []
|
|
|
|
files = []
|
2008-01-29 10:21:34 +03:00
|
|
|
save_temps = 0
|
|
|
|
language = ''
|
2008-08-24 02:15:15 +04:00
|
|
|
native = CCC_NATIVE
|
|
|
|
|
2008-01-10 04:43:47 +03:00
|
|
|
i = 0
|
|
|
|
while i < len(args):
|
|
|
|
arg = args[i]
|
2008-01-29 10:21:34 +03:00
|
|
|
|
|
|
|
# Modes ccc supports
|
2008-01-10 04:43:47 +03:00
|
|
|
if arg == '-E':
|
|
|
|
action = 'preprocess'
|
|
|
|
if arg == '-c':
|
|
|
|
action = 'compile'
|
2008-01-25 17:57:54 +03:00
|
|
|
if arg.startswith('-print-prog-name'):
|
|
|
|
action = 'print-prog-name'
|
2008-01-29 10:21:34 +03:00
|
|
|
if arg == '-save-temps':
|
|
|
|
save_temps = 1
|
2008-08-24 02:15:15 +04:00
|
|
|
if arg == '-emit-llvm' or arg == '--emit-llvm':
|
|
|
|
native = False
|
2008-01-29 10:21:34 +03:00
|
|
|
|
|
|
|
# Options with no arguments that should pass through
|
2008-08-30 01:03:27 +04:00
|
|
|
if arg in ['-v', '-fobjc-gc', '-fobjc-gc-only', '-fnext-runtime',
|
|
|
|
'-fgnu-runtime']:
|
2008-01-29 10:21:34 +03:00
|
|
|
compile_opts.append(arg)
|
|
|
|
link_opts.append(arg)
|
|
|
|
|
|
|
|
# Options with one argument that should be ignored
|
2008-04-22 00:28:01 +04:00
|
|
|
if arg in ['--param', '-u']:
|
2008-01-17 04:08:43 +03:00
|
|
|
i += 1
|
2008-01-29 10:21:34 +03:00
|
|
|
|
2008-07-24 07:49:15 +04:00
|
|
|
# Preprocessor options with one argument that should be ignored
|
|
|
|
if arg in ['-MT', '-MF']:
|
|
|
|
i += 1
|
|
|
|
|
2008-01-29 10:21:34 +03:00
|
|
|
# Prefix matches for the compile mode
|
|
|
|
if arg[:2] in ['-D', '-I', '-U', '-F']:
|
2008-01-10 04:43:47 +03:00
|
|
|
if not arg[2:]:
|
|
|
|
arg += args[i+1]
|
|
|
|
i += 1
|
|
|
|
compile_opts.append(arg)
|
2008-01-29 10:21:34 +03:00
|
|
|
if arg[:5] in ['-std=']:
|
|
|
|
compile_opts.append(arg)
|
|
|
|
|
2008-06-17 21:23:14 +04:00
|
|
|
# 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
|
|
|
|
|
2008-01-29 10:21:34 +03:00
|
|
|
# Options with one argument that should pass through
|
2008-09-12 23:42:28 +04:00
|
|
|
if arg in ('-framework', '-multiply_defined', '-bundle_loader',
|
|
|
|
'-e'):
|
2008-06-17 21:23:14 +04:00
|
|
|
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']:
|
2008-01-29 10:21:34 +03:00
|
|
|
compile_opts.append(arg)
|
|
|
|
compile_opts.append(args[i+1])
|
2008-06-17 21:23:14 +04:00
|
|
|
link_opts.append(arg)
|
|
|
|
link_opts.append(args[i+1])
|
2008-01-29 10:21:34 +03:00
|
|
|
i += 1
|
2008-09-12 23:42:28 +04:00
|
|
|
|
|
|
|
# Options with three arguments that should pass through
|
|
|
|
if arg in ('-sectorder',):
|
|
|
|
link_opts.extend(args[i:i+4])
|
|
|
|
i += 3
|
2008-01-29 10:21:34 +03:00
|
|
|
|
|
|
|
# Prefix matches for the link mode
|
2008-08-11 01:58:01 +04:00
|
|
|
if arg[:2] in ['-l', '-L', '-F', '-R']:
|
2008-01-10 04:43:47 +03:00
|
|
|
link_opts.append(arg)
|
2008-01-29 10:21:34 +03:00
|
|
|
|
2008-06-21 21:46:11 +04:00
|
|
|
# Enable threads
|
|
|
|
if arg == '-pthread':
|
|
|
|
link_opts.append('-lpthread')
|
|
|
|
|
2008-01-29 10:21:34 +03:00
|
|
|
# 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
|
2008-01-10 04:43:47 +03:00
|
|
|
if arg[0] != '-':
|
|
|
|
files.append(arg)
|
2008-01-29 10:21:34 +03:00
|
|
|
|
|
|
|
# Output file
|
|
|
|
if arg == '-o':
|
|
|
|
output = args[i+1]
|
|
|
|
i += 1
|
|
|
|
|
2008-01-10 04:43:47 +03:00
|
|
|
i += 1
|
|
|
|
|
2008-01-25 17:57:54 +03:00
|
|
|
if action == 'print-prog-name':
|
|
|
|
# assume we can handle everything
|
|
|
|
print sys.argv[0]
|
|
|
|
return
|
|
|
|
|
2008-01-10 04:43:47 +03:00
|
|
|
if not files:
|
|
|
|
error('no input files')
|
|
|
|
|
2008-01-29 10:21:34 +03:00
|
|
|
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 = ''
|
2008-01-10 04:43:47 +03:00
|
|
|
|
2008-01-29 10:21:34 +03:00
|
|
|
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
|
2008-08-30 01:03:27 +04:00
|
|
|
checked_compile(args, native, language, save_temps)
|
2008-01-29 10:21:34 +03:00
|
|
|
language = ''
|
2008-01-10 04:43:47 +03:00
|
|
|
|
|
|
|
if action == 'link':
|
|
|
|
for i, file in enumerate(files):
|
2008-08-30 01:03:27 +04:00
|
|
|
if not language:
|
|
|
|
language = inferlanguage(extension(file))
|
2008-02-01 02:48:19 +03:00
|
|
|
ext = extension(file)
|
2008-08-11 02:17:57 +04:00
|
|
|
if ext != "o" and ext != "a" and ext != "so":
|
2008-01-29 10:21:34 +03:00
|
|
|
out = changeextension(file, "o")
|
2008-08-30 01:03:27 +04:00
|
|
|
args = ['-x', language, '-o', out, file] + compile_opts
|
|
|
|
checked_compile(args, native, language, save_temps)
|
|
|
|
language = ''
|
2008-01-10 04:43:47 +03:00
|
|
|
files[i] = out
|
|
|
|
if not output:
|
|
|
|
output = 'a.out'
|
|
|
|
args = ['-o', output] + link_opts + files
|
2008-08-24 02:15:15 +04:00
|
|
|
link(args, native)
|
2008-01-10 04:43:47 +03:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main(sys.argv[1:])
|