blob: 8427745127c0ffb97deccf96068a692842d4cb06 [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
Ted Kremenek09c2ad62008-03-31 18:25:05 +000048def analyze(args,language,output,files,verbose,htmldir):
Ted Kremenek8cb53fb2008-04-03 21:29:11 +000049 if language.find("c++") > 0:
Ted Kremenekb0982882008-03-25 22:35:32 +000050 return
51
Ted Kremenekb0982882008-03-25 22:35:32 +000052 print_args = []
53
Ted Kremenek09c2ad62008-03-31 18:25:05 +000054 if verbose:
55 print >> sys.stderr, ' '.join(['\n[LOCATION]:', os.getcwd(), '\n' ])
56 i = 0
57 while i < len(args):
Ted Kremenekb0982882008-03-25 22:35:32 +000058 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()
Ted Kremenek69b64422008-03-31 21:20:32 +000067 args = command + args;
68
69 if htmldir is not None:
70 args.append('-o')
71 print_args.append('-o')
72 args.append(htmldir)
73 print_args.append(htmldir)
Ted Kremenek09c2ad62008-03-31 18:25:05 +000074
75 if verbose:
76 print >> sys.stderr, ' '.join(command+print_args)
77 print >> sys.stderr, '\n'
Ted Kremenekb0982882008-03-25 22:35:32 +000078
Ted Kremenekb0982882008-03-25 22:35:32 +000079 subprocess.call(args)
80
81def link(args):
82 command = 'gcc'.split()
83 run(command + args)
84
85def extension(path):
86 return path.split(".")[-1]
87
88def changeextension(path, newext):
89 i = path.rfind('.')
90 if i < 0:
91 return path
92 j = path.rfind('/', 0, i)
93 print path
94 if j < 0:
95 return path[:i] + "." + newext
96 return path[j+1:i] + "." + newext
97
98def inferlanguage(extension):
99 if extension == "c":
100 return "c"
101 elif extension in ["cpp", "cc"]:
102 return "c++"
103 elif extension == "i":
104 return "c-cpp-output"
105 elif extension == "m":
106 return "objective-c"
107 elif extension == "mi":
108 return "objective-c-cpp-output"
109 else:
110 return "unknown"
111
112def main(args):
113 old_args = args
114 action = 'link'
115 output = ''
116 compile_opts = [ ]
117 link_opts = [ ]
118 files = []
119 save_temps = 0
120 language = ''
121
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000122 verbose = 0
123
124 if os.environ.get('CCC_ANALYZER_VERBOSE') is not None:
125 verbose =1
126
127 htmldir = os.environ.get('CCC_ANALYZER_HTML')
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000128
Ted Kremenekb0982882008-03-25 22:35:32 +0000129 i = 0
130 while i < len(args):
131 arg = args[i]
132
133 # Modes ccc supports
134 if arg == '-E':
135 action = 'preprocess'
136 if arg == '-c':
137 action = 'compile'
138 if arg.startswith('-print-prog-name'):
139 action = 'print-prog-name'
140 if arg == '-save-temps':
141 save_temps = 1
142
143 # Options with no arguments that should pass through
144 if arg in ['-v']:
145 compile_opts.append(arg)
146 link_opts.append(arg)
147
148 # Options with one argument that should be ignored
149 if arg in ['--param', '-arch', '-u']:
150 i += 1
151
152 # Prefix matches for the compile mode
153 if arg[:2] in ['-D', '-I', '-U', '-F']:
154 if not arg[2:]:
155 arg += args[i+1]
156 i += 1
157 compile_opts.append(arg)
158 if arg[:5] in ['-std=']:
159 compile_opts.append(arg)
160
161 # Options with one argument that should pass through
162 if arg in ['-include']:
163 compile_opts.append(arg)
164 compile_opts.append(args[i+1])
165 i += 1
166
167 # Prefix matches for the link mode
168 if arg[:2] in ['-l', '-L', '-O', '-F']:
169 if arg == '-O': arg = '-O1'
170 if arg == '-Os': arg = '-O2'
171 link_opts.append(arg)
172
173 # Options with one argument that should pass through
174 if arg in ['-framework']:
175 link_opts.append(arg)
176 link_opts.append(args[i+1])
177 i += 1
178
179 # Input files
180 if arg == '-filelist':
181 f = open(args[i+1])
182 for line in f:
183 files.append(line.strip())
184 f.close()
185 i += 1
186 if arg == '-x':
187 language = args[i+1]
188 i += 1
189 if arg[0] != '-':
190 files.append(arg)
191
192 # Output file
193 if arg == '-o':
194 output = args[i+1]
195 i += 1
196
197 i += 1
198
199 if action == 'print-prog-name':
200 # assume we can handle everything
201 print sys.argv[0]
202 return
203
204 if not files:
205 error('no input files')
206
207 if action == 'preprocess' or save_temps:
208 compile(args)
209
210 if action == 'compile' or save_temps:
211 for i, file in enumerate(files):
212 if not language:
213 language = inferlanguage(extension(file))
214 if save_temps and action != "compile":
215 # Need a temporary output file
216 coutput = changeextension(file, "o");
217 files[i] = coutput
218 elif not output:
219 coutput = changeextension(file, "o")
220 else:
221 coutput = output
222 analyze_args = [ file ]
223 if language != 'unknown':
224 analyze_args = analyze_args + [ '-x', language ]
225 analyze_args = analyze_args + compile_opts
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000226 analyze(analyze_args, language, output, files, verbose, htmldir)
Ted Kremenekb0982882008-03-25 22:35:32 +0000227 compile(args)
228
229
230 if action == 'link':
231 link(args)
232# analyze(link_opts)
233
234if __name__ == '__main__':
235 main(sys.argv[1:])