blob: f4c960d1c0e4baa6fb1cb5729baba90f27388fe2 [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):
Ted Kremenek61cd9882008-05-24 15:58:54 +000021 print >> sys.stderr, 'ccc: ' + message
22 sys.exit(1)
Ted Kremenekb0982882008-03-25 22:35:32 +000023
Seo Sanghyeond3894652008-04-04 11:02:21 +000024def quote(arg):
Ted Kremenek61cd9882008-05-24 15:58:54 +000025 if '"' in arg:
26 return repr(arg)
27 return arg
Seo Sanghyeond3894652008-04-04 11:02:21 +000028
Ted Kremenekb0982882008-03-25 22:35:32 +000029def run(args):
Ted Kremenek61cd9882008-05-24 15:58:54 +000030 code = subprocess.call(args)
31 if code > 255:
32 code = 1
33 if code:
34 sys.exit(code)
Ted Kremenekb0982882008-03-25 22:35:32 +000035
Ted Kremenekfe873542008-04-21 21:58:05 +000036def compile(args):
Ted Kremenekb0982882008-03-25 22:35:32 +000037 command = 'gcc'.split()
38 run(command + args)
39
40def remove_pch_extension(path):
Ted Kremenek61cd9882008-05-24 15:58:54 +000041 i = path.rfind('.gch')
42 if i < 0:
43 return path
44 return path[:i]
Ted Kremenekb0982882008-03-25 22:35:32 +000045
Ted Kremenek1262fc42008-05-14 20:10:33 +000046def analyze(clang, args,language,output,files,verbose,htmldir,file,analysis_type):
Ted Kremenek30aba6d2008-05-27 23:17:16 +000047 if language.rfind("c++") >= 0:
Ted Kremenek61cd9882008-05-24 15:58:54 +000048 return
49
Ted Kremenek2797b172008-06-30 16:12:30 +000050 RunAnalyzer = 0;
51
52 if language.find("header") > 0:
53 target = remove_pch_extension(output)
54 command = ['cp']
55 args = command + files + [ target ]
56 else:
57 command = clang.split() + analysis_type.split()
58 args = command + args;
59 RunAnalyzer = 1
60
Ted Kremenek61cd9882008-05-24 15:58:54 +000061 print_args = []
Ted Kremenekb0982882008-03-25 22:35:32 +000062
Ted Kremenek61cd9882008-05-24 15:58:54 +000063 if verbose:
64 # We MUST print to stderr. Some clients use the stdout output of
65 # gcc for various purposes.
66 print >> sys.stderr, ' '.join(['\n[LOCATION]:', os.getcwd(), '\n' ])
67 i = 0
68 while i < len(args):
69 print_args.append(''.join([ '\'', args[i], '\'' ]))
70 i += 1
Ted Kremeneka9525c92008-05-12 22:07:14 +000071
Ted Kremenek61cd9882008-05-24 15:58:54 +000072 if verbose == 2:
Ted Kremenek01006782008-07-02 23:16:10 +000073 print >> sys.stderr, '#SHELL (cd ' + os.getcwd() + ' && ' + ' '.join(print_args) + ')\n'
Ted Kremeneka9525c92008-05-12 22:07:14 +000074
Ted Kremenek61cd9882008-05-24 15:58:54 +000075 if RunAnalyzer and htmldir is not None:
76 args.append('-o')
77 print_args.append('-o')
78 args.append(htmldir)
79 print_args.append(htmldir)
80
81 if verbose == 1:
82 # We MUST print to stderr. Some clients use the stdout output of
83 # gcc for various purposes.
Ted Kremenek01006782008-07-02 23:16:10 +000084 print >> sys.stderr, ' '.join(print_args)
Ted Kremenek61cd9882008-05-24 15:58:54 +000085 print >> sys.stderr, '\n'
Ted Kremeneka9525c92008-05-12 22:07:14 +000086
Ted Kremenek68144472008-06-16 21:41:07 +000087 subprocess.call(args)
Ted Kremenekb0982882008-03-25 22:35:32 +000088
89def extension(path):
90 return path.split(".")[-1]
91
92def changeextension(path, newext):
93 i = path.rfind('.')
94 if i < 0:
95 return path
96 j = path.rfind('/', 0, i)
Ted Kremenekb0982882008-03-25 22:35:32 +000097 if j < 0:
98 return path[:i] + "." + newext
99 return path[j+1:i] + "." + newext
100
101def inferlanguage(extension):
102 if extension == "c":
103 return "c"
104 elif extension in ["cpp", "cc"]:
105 return "c++"
106 elif extension == "i":
107 return "c-cpp-output"
108 elif extension == "m":
109 return "objective-c"
110 elif extension == "mi":
111 return "objective-c-cpp-output"
Ted Kremenekcd853482008-06-10 18:56:59 +0000112 elif extension in [ "s", "o", "a", "so" ]:
Ted Kremenekbfd6a3f2008-05-14 20:17:17 +0000113 return "skip"
Ted Kremenekb0982882008-03-25 22:35:32 +0000114 else:
Ted Kremenek1c6f3b22008-07-03 22:24:10 +0000115 return "skip" # Skip files with unknown extensions. This
116 # deviates from ccc, but this works very well for
117 # the analyzer.
Ted Kremenekb0982882008-03-25 22:35:32 +0000118
119def main(args):
Ted Kremenek61cd9882008-05-24 15:58:54 +0000120 old_args = args
121 action = 'link'
122 output = ''
123 compile_opts = [ ]
124 link_opts = [ ]
125 files = []
126 save_temps = 0
127 language = ''
128
129 verbose = 0
130 clang = "clang"
131
132 # Forward to GCC.
133 compile(args)
134
135 # Set the analyzer flag.
136 analysis_type = os.environ.get('CCC_ANALYZER_ANALYSIS')
137
138 if analysis_type is not None:
139 analysis_type = "-" + analysis_type
140 else:
Ted Kremenek01006782008-07-02 23:16:10 +0000141 analysis_type = "-warn-dead-stores -checker-cfref"
Ted Kremenek61cd9882008-05-24 15:58:54 +0000142
143 # Determine the level of verbosity.
144 if os.environ.get('CCC_ANALYZER_VERBOSE') is not None:
145 verbose = 1
Ted Kremenekb0982882008-03-25 22:35:32 +0000146
Ted Kremenek61cd9882008-05-24 15:58:54 +0000147 if os.environ.get('CCC_ANALYZER_LOG') is not None:
148 verbose = 2
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000149
Ted Kremenek61cd9882008-05-24 15:58:54 +0000150 # Determine what clang executable to use.
151 clang_env = os.environ.get('CLANG')
152
153 if clang_env is not None:
154 clang = clang_env
155
156 # Get the HTML output directory.
Ted Kremenek01006782008-07-02 23:16:10 +0000157 htmldir = os.environ.get('CCC_ANALYZER_HTML')
Ted Kremenek61cd9882008-05-24 15:58:54 +0000158
159 # Process the arguments.
160 i = 0
161 while i < len(args):
162 arg = args[i]
163
164 # Modes ccc supports
165 if arg == '-E':
166 action = 'preprocess'
167 if arg == '-c':
168 action = 'compile'
169 if arg.startswith('-print-prog-name'):
170 action = 'print-prog-name'
171 if arg == '-save-temps':
172 save_temps = 1
173
174 # Options with no arguments that should pass through
175 if arg in ['-v']:
176 compile_opts.append(arg)
177 link_opts.append(arg)
Ted Kremenek1262fc42008-05-14 20:10:33 +0000178
Ted Kremenek61cd9882008-05-24 15:58:54 +0000179 # Options with one argument that should be ignored
180 if arg in ['--param', '-u']:
Ted Kremenekb0982882008-03-25 22:35:32 +0000181 i += 1
182
Ted Kremenek61cd9882008-05-24 15:58:54 +0000183 # Prefix matches for the compile mode
184 if arg[:2] in ['-D', '-I', '-U', '-F' ]:
185 if not arg[2:]:
186 arg += args[i+1]
187 i += 1
188 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000189
Ted Kremenek61cd9882008-05-24 15:58:54 +0000190 if arg[:5] in ['-std=']:
191 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000192
Ted Kremenek61cd9882008-05-24 15:58:54 +0000193 # Options with one argument that should pass through to compiler
194 if arg in [ '-include', '-idirafter', '-iprefix',
195 '-iquote', '-isystem', '-iwithprefix',
196 '-iwithprefixbefore']:
197 compile_opts.append(arg)
198 compile_opts.append(args[i+1])
199 i += 1
200
201 # Options with no argument that should pass through to compiler
202 if arg in [ '-nostdinc', '-fobjc-gc-only', '-fobjc-gc' ]:
203 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000204
Ted Kremenek61cd9882008-05-24 15:58:54 +0000205 # Options with one argument that should pass through to linker
206 if arg == '-framework':
207 link_opts.append(arg)
208 link_opts.append(args[i+1])
209 i += 1
Ted Kremenekbfd6a3f2008-05-14 20:17:17 +0000210
Ted Kremenek61cd9882008-05-24 15:58:54 +0000211 # Options with one argument that should pass through to both
212 if arg in ['-isysroot', '-arch']:
213 compile_opts.append(arg)
214 compile_opts.append(args[i+1])
215 link_opts.append(arg)
216 link_opts.append(args[i+1])
217 i += 1
Ted Kremenekb0982882008-03-25 22:35:32 +0000218
Ted Kremenek61cd9882008-05-24 15:58:54 +0000219 # Prefix matches for the link mode
220 if arg[:2] in ['-l', '-L', '-O', '-F']:
221 if arg == '-O': arg = '-O1'
222 if arg == '-Os': arg = '-O2'
223 link_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000224
Ted Kremenek61cd9882008-05-24 15:58:54 +0000225 # Input files
226 if arg == '-filelist':
227 f = open(args[i+1])
228 for line in f:
229 files.append(line.strip())
230 f.close()
231 i += 1
232 if arg == '-x':
233 language = args[i+1]
234 i += 1
235 if arg[0] != '-':
236 files.append(arg)
237
238 # Output file
239 if arg == '-o':
240 output = args[i+1]
241 i += 1
Ted Kremenek49061fa2008-06-04 20:49:03 +0000242
243 # Arguments we currently ignore with one option.
244 if arg in ['-install_name', '-exported_symbols_list',
Ted Kremenekfe4db8b2008-06-05 22:46:24 +0000245 '-current_version', '-compatibility_version', '-init', '-e',
Ted Kremenekcd853482008-06-10 18:56:59 +0000246 '-seg1addr', '-bundle_loader', '-multiply_defined']:
Ted Kremenek49061fa2008-06-04 20:49:03 +0000247 i += 1
248
249 # Arguments we currently ignore with three options.
250 if arg in ['-sectorder']:
251 i += 3
Ted Kremenek61cd9882008-05-24 15:58:54 +0000252
253 i += 1
254
255 if action == 'print-prog-name':
256 # assume we can handle everything
257 print sys.argv[0]
258 return
259
260 if not files:
261 error('no input files')
262
263 if action == 'compile' or save_temps or action == 'link':
264 for i, file in enumerate(files):
Ted Kremenek508b3812008-05-24 16:14:34 +0000265 file_language = language
Ted Kremenek61cd9882008-05-24 15:58:54 +0000266 if not language:
Ted Kremenek508b3812008-05-24 16:14:34 +0000267 file_language = inferlanguage(extension(file))
Ted Kremenek39165e22008-05-24 16:16:30 +0000268 if file_language == "skip":
Ted Kremenek61cd9882008-05-24 15:58:54 +0000269 continue
270
271 if save_temps and action != "compile":
272 # Need a temporary output file
273 coutput = changeextension(file, "o");
274 files[i] = coutput
275 elif not output:
276 coutput = changeextension(file, "o")
277 else:
278 coutput = output
279 analyze_args = [ file ]
Ted Kremenekb96ffdf2008-06-02 17:13:40 +0000280 if file_language != 'unknown':
281 analyze_args = [ '-x', file_language ] + analyze_args
Ted Kremenek61cd9882008-05-24 15:58:54 +0000282 analyze_args = analyze_args + compile_opts
283 analyze(clang, analyze_args, language, output, files, verbose, htmldir, file, analysis_type)
Ted Kremenekb0982882008-03-25 22:35:32 +0000284
285if __name__ == '__main__':
286 main(sys.argv[1:])