blob: 1b925165f45a2d279d4aff53e3f1047de7115029 [file] [log] [blame]
Ted Kremenekb0982882008-03-25 22:35:32 +00001#!/usr/bin/env python
2#
3# The LLVM Compiler Infrastructure
4#
5# This file is distributed under the University of Illinois Open Source
6# License. See LICENSE.TXT for details.
7#
8##===----------------------------------------------------------------------===##
9#
10# A reduced version of the 'ccc' script that is designed to handle off
11# actual compilation to gcc, but run the code passed to gcc through the
12# static analyzer.
13#
14##===----------------------------------------------------------------------===##
15
16import sys
17import subprocess
18import os
19
20def error(message):
21 print >> sys.stderr, 'ccc: ' + message
22 sys.exit(1)
23
24def run(args):
25 print >> sys.stderr, ' '.join(args)
26 print >> sys.stderr, '\n'
27 code = subprocess.call(args)
28 if code > 255:
29 code = 1
30 if code:
31 sys.exit(code)
32
33def preprocess(args):
34 command = 'clang -E'.split()
35 run(command + args)
36
37def compile(args):
38 print >> sys.stderr, '\n'
39 command = 'gcc'.split()
40 run(command + args)
41
42def remove_pch_extension(path):
43 i = path.rfind('.gch')
44 if i < 0:
45 return path
46 return path[:i]
47
48def analyze(args,language,output,files):
49 if language.find("c++") > 0:
50 return
51
52 print >> sys.stderr, ' '.join(['\n[LOCATION]:', os.getcwd(), '\n' ])
53
54 print_args = []
55
56 i = 0
57 while i < len(args):
58 print_args.append(''.join([ '\'', args[i], '\'' ]))
59 i += 1
60
61 if language.find("header") > 0:
62 target = remove_pch_extension(output)
63 command = 'cp'.split()
64 args = command + files + target.split()
65 else:
66 command = 'clang --grsimple'.split()
67 args = command + args
68
69 print >> sys.stderr, ' '.join(command+print_args)
70 print >> sys.stderr, '\n'
71 subprocess.call(args)
72
73def link(args):
74 command = 'gcc'.split()
75 run(command + args)
76
77def extension(path):
78 return path.split(".")[-1]
79
80def changeextension(path, newext):
81 i = path.rfind('.')
82 if i < 0:
83 return path
84 j = path.rfind('/', 0, i)
85 print path
86 if j < 0:
87 return path[:i] + "." + newext
88 return path[j+1:i] + "." + newext
89
90def inferlanguage(extension):
91 if extension == "c":
92 return "c"
93 elif extension in ["cpp", "cc"]:
94 return "c++"
95 elif extension == "i":
96 return "c-cpp-output"
97 elif extension == "m":
98 return "objective-c"
99 elif extension == "mi":
100 return "objective-c-cpp-output"
101 else:
102 return "unknown"
103
104def main(args):
105 old_args = args
106 action = 'link'
107 output = ''
108 compile_opts = [ ]
109 link_opts = [ ]
110 files = []
111 save_temps = 0
112 language = ''
113
114 i = 0
115 while i < len(args):
116 arg = args[i]
117
118 # Modes ccc supports
119 if arg == '-E':
120 action = 'preprocess'
121 if arg == '-c':
122 action = 'compile'
123 if arg.startswith('-print-prog-name'):
124 action = 'print-prog-name'
125 if arg == '-save-temps':
126 save_temps = 1
127
128 # Options with no arguments that should pass through
129 if arg in ['-v']:
130 compile_opts.append(arg)
131 link_opts.append(arg)
132
133 # Options with one argument that should be ignored
134 if arg in ['--param', '-arch', '-u']:
135 i += 1
136
137 # Prefix matches for the compile mode
138 if arg[:2] in ['-D', '-I', '-U', '-F']:
139 if not arg[2:]:
140 arg += args[i+1]
141 i += 1
142 compile_opts.append(arg)
143 if arg[:5] in ['-std=']:
144 compile_opts.append(arg)
145
146 # Options with one argument that should pass through
147 if arg in ['-include']:
148 compile_opts.append(arg)
149 compile_opts.append(args[i+1])
150 i += 1
151
152 # Prefix matches for the link mode
153 if arg[:2] in ['-l', '-L', '-O', '-F']:
154 if arg == '-O': arg = '-O1'
155 if arg == '-Os': arg = '-O2'
156 link_opts.append(arg)
157
158 # Options with one argument that should pass through
159 if arg in ['-framework']:
160 link_opts.append(arg)
161 link_opts.append(args[i+1])
162 i += 1
163
164 # Input files
165 if arg == '-filelist':
166 f = open(args[i+1])
167 for line in f:
168 files.append(line.strip())
169 f.close()
170 i += 1
171 if arg == '-x':
172 language = args[i+1]
173 i += 1
174 if arg[0] != '-':
175 files.append(arg)
176
177 # Output file
178 if arg == '-o':
179 output = args[i+1]
180 i += 1
181
182 i += 1
183
184 if action == 'print-prog-name':
185 # assume we can handle everything
186 print sys.argv[0]
187 return
188
189 if not files:
190 error('no input files')
191
192 if action == 'preprocess' or save_temps:
193 compile(args)
194
195 if action == 'compile' or save_temps:
196 for i, file in enumerate(files):
197 if not language:
198 language = inferlanguage(extension(file))
199 if save_temps and action != "compile":
200 # Need a temporary output file
201 coutput = changeextension(file, "o");
202 files[i] = coutput
203 elif not output:
204 coutput = changeextension(file, "o")
205 else:
206 coutput = output
207 analyze_args = [ file ]
208 if language != 'unknown':
209 analyze_args = analyze_args + [ '-x', language ]
210 analyze_args = analyze_args + compile_opts
211 analyze(analyze_args,language,output,files)
212 compile(args)
213
214
215 if action == 'link':
216 link(args)
217# analyze(link_opts)
218
219if __name__ == '__main__':
220 main(sys.argv[1:])