blob: 10141889fb1584cf18fbf207512621fac5c83a76 [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
50 print_args = []
Ted Kremenekb0982882008-03-25 22:35:32 +000051
Ted Kremenek61cd9882008-05-24 15:58:54 +000052 if verbose:
53 # We MUST print to stderr. Some clients use the stdout output of
54 # gcc for various purposes.
55 print >> sys.stderr, ' '.join(['\n[LOCATION]:', os.getcwd(), '\n' ])
56 i = 0
57 while i < len(args):
58 print_args.append(''.join([ '\'', args[i], '\'' ]))
59 i += 1
Ted Kremeneka9525c92008-05-12 22:07:14 +000060
Ted Kremenek61cd9882008-05-24 15:58:54 +000061 RunAnalyzer = 0;
Ted Kremeneka9525c92008-05-12 22:07:14 +000062
Ted Kremenek61cd9882008-05-24 15:58:54 +000063 if language.find("header") > 0:
64 target = remove_pch_extension(output)
65 command = 'cp'.split()
66 args = command + files + target.split()
67 else:
68 command = clang.split() + analysis_type.split()
69 args = command + args;
70 RunAnalyzer = 1
Ted Kremeneka9525c92008-05-12 22:07:14 +000071
Ted Kremenek61cd9882008-05-24 15:58:54 +000072 if verbose == 2:
73 print >> sys.stderr, '#SHELL (cd ' + os.getcwd() + ' && ' + ' '.join(command + 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.
84 print >> sys.stderr, ' '.join(command+print_args)
85 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:
115 return "unknown"
116
117def main(args):
Ted Kremenek61cd9882008-05-24 15:58:54 +0000118 old_args = args
119 action = 'link'
120 output = ''
121 compile_opts = [ ]
122 link_opts = [ ]
123 files = []
124 save_temps = 0
125 language = ''
126
127 verbose = 0
128 clang = "clang"
129
130 # Forward to GCC.
131 compile(args)
132
133 # Set the analyzer flag.
134 analysis_type = os.environ.get('CCC_ANALYZER_ANALYSIS')
135
136 if analysis_type is not None:
137 analysis_type = "-" + analysis_type
138 else:
139 analysis_type = "-checker-cfref"
140
141 # Determine the level of verbosity.
142 if os.environ.get('CCC_ANALYZER_VERBOSE') is not None:
143 verbose = 1
Ted Kremenekb0982882008-03-25 22:35:32 +0000144
Ted Kremenek61cd9882008-05-24 15:58:54 +0000145 if os.environ.get('CCC_ANALYZER_LOG') is not None:
146 verbose = 2
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000147
Ted Kremenek61cd9882008-05-24 15:58:54 +0000148 # Determine what clang executable to use.
149 clang_env = os.environ.get('CLANG')
150
151 if clang_env is not None:
152 clang = clang_env
153
154 # Get the HTML output directory.
155 htmldir = None
156
157 if analysis_type == "-checker-cfref":
158 htmldir = os.environ.get('CCC_ANALYZER_HTML')
159
160 # Process the arguments.
161 i = 0
162 while i < len(args):
163 arg = args[i]
164
165 # Modes ccc supports
166 if arg == '-E':
167 action = 'preprocess'
168 if arg == '-c':
169 action = 'compile'
170 if arg.startswith('-print-prog-name'):
171 action = 'print-prog-name'
172 if arg == '-save-temps':
173 save_temps = 1
174
175 # Options with no arguments that should pass through
176 if arg in ['-v']:
177 compile_opts.append(arg)
178 link_opts.append(arg)
Ted Kremenek1262fc42008-05-14 20:10:33 +0000179
Ted Kremenek61cd9882008-05-24 15:58:54 +0000180 # Options with one argument that should be ignored
181 if arg in ['--param', '-u']:
Ted Kremenekb0982882008-03-25 22:35:32 +0000182 i += 1
183
Ted Kremenek61cd9882008-05-24 15:58:54 +0000184 # Prefix matches for the compile mode
185 if arg[:2] in ['-D', '-I', '-U', '-F' ]:
186 if not arg[2:]:
187 arg += args[i+1]
188 i += 1
189 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000190
Ted Kremenek61cd9882008-05-24 15:58:54 +0000191 if arg[:5] in ['-std=']:
192 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000193
Ted Kremenek61cd9882008-05-24 15:58:54 +0000194 # Options with one argument that should pass through to compiler
195 if arg in [ '-include', '-idirafter', '-iprefix',
196 '-iquote', '-isystem', '-iwithprefix',
197 '-iwithprefixbefore']:
198 compile_opts.append(arg)
199 compile_opts.append(args[i+1])
200 i += 1
201
202 # Options with no argument that should pass through to compiler
203 if arg in [ '-nostdinc', '-fobjc-gc-only', '-fobjc-gc' ]:
204 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000205
Ted Kremenek61cd9882008-05-24 15:58:54 +0000206 # Options with one argument that should pass through to linker
207 if arg == '-framework':
208 link_opts.append(arg)
209 link_opts.append(args[i+1])
210 i += 1
Ted Kremenekbfd6a3f2008-05-14 20:17:17 +0000211
Ted Kremenek61cd9882008-05-24 15:58:54 +0000212 # Options with one argument that should pass through to both
213 if arg in ['-isysroot', '-arch']:
214 compile_opts.append(arg)
215 compile_opts.append(args[i+1])
216 link_opts.append(arg)
217 link_opts.append(args[i+1])
218 i += 1
Ted Kremenekb0982882008-03-25 22:35:32 +0000219
Ted Kremenek61cd9882008-05-24 15:58:54 +0000220 # Prefix matches for the link mode
221 if arg[:2] in ['-l', '-L', '-O', '-F']:
222 if arg == '-O': arg = '-O1'
223 if arg == '-Os': arg = '-O2'
224 link_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000225
Ted Kremenek61cd9882008-05-24 15:58:54 +0000226 # Input files
227 if arg == '-filelist':
228 f = open(args[i+1])
229 for line in f:
230 files.append(line.strip())
231 f.close()
232 i += 1
233 if arg == '-x':
234 language = args[i+1]
235 i += 1
236 if arg[0] != '-':
237 files.append(arg)
238
239 # Output file
240 if arg == '-o':
241 output = args[i+1]
242 i += 1
Ted Kremenek49061fa2008-06-04 20:49:03 +0000243
244 # Arguments we currently ignore with one option.
245 if arg in ['-install_name', '-exported_symbols_list',
Ted Kremenekfe4db8b2008-06-05 22:46:24 +0000246 '-current_version', '-compatibility_version', '-init', '-e',
Ted Kremenekcd853482008-06-10 18:56:59 +0000247 '-seg1addr', '-bundle_loader', '-multiply_defined']:
Ted Kremenek49061fa2008-06-04 20:49:03 +0000248 i += 1
249
250 # Arguments we currently ignore with three options.
251 if arg in ['-sectorder']:
252 i += 3
Ted Kremenek61cd9882008-05-24 15:58:54 +0000253
254 i += 1
255
256 if action == 'print-prog-name':
257 # assume we can handle everything
258 print sys.argv[0]
259 return
260
261 if not files:
262 error('no input files')
263
264 if action == 'compile' or save_temps or action == 'link':
265 for i, file in enumerate(files):
Ted Kremenek508b3812008-05-24 16:14:34 +0000266 file_language = language
Ted Kremenek61cd9882008-05-24 15:58:54 +0000267 if not language:
Ted Kremenek508b3812008-05-24 16:14:34 +0000268 file_language = inferlanguage(extension(file))
Ted Kremenek39165e22008-05-24 16:16:30 +0000269 if file_language == "skip":
Ted Kremenek61cd9882008-05-24 15:58:54 +0000270 continue
271
272 if save_temps and action != "compile":
273 # Need a temporary output file
274 coutput = changeextension(file, "o");
275 files[i] = coutput
276 elif not output:
277 coutput = changeextension(file, "o")
278 else:
279 coutput = output
280 analyze_args = [ file ]
Ted Kremenekb96ffdf2008-06-02 17:13:40 +0000281 if file_language != 'unknown':
282 analyze_args = [ '-x', file_language ] + analyze_args
Ted Kremenek61cd9882008-05-24 15:58:54 +0000283 analyze_args = analyze_args + compile_opts
284 analyze(clang, analyze_args, language, output, files, verbose, htmldir, file, analysis_type)
Ted Kremenekb0982882008-03-25 22:35:32 +0000285
286if __name__ == '__main__':
287 main(sys.argv[1:])