blob: 8f342ecfe02c98073a7caed462d54fcbaf99a0bf [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()
Ted Kremenekef42ca22008-07-15 23:09:14 +000058 args = command + "-DIBOutlet=__attribute__((iboutlet))".split() + args;
Ted Kremenek2797b172008-06-30 16:12:30 +000059 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
Ted Kremenek90125992008-07-15 23:41:32 +0000138 if analysis_type is None:
139 analysis_type = "-checker-cfref"
Ted Kremenek61cd9882008-05-24 15:58:54 +0000140
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.
Ted Kremenek01006782008-07-02 23:16:10 +0000155 htmldir = os.environ.get('CCC_ANALYZER_HTML')
Ted Kremenek61cd9882008-05-24 15:58:54 +0000156
157 # Process the arguments.
158 i = 0
159 while i < len(args):
160 arg = args[i]
161
162 # Modes ccc supports
163 if arg == '-E':
164 action = 'preprocess'
165 if arg == '-c':
166 action = 'compile'
167 if arg.startswith('-print-prog-name'):
168 action = 'print-prog-name'
169 if arg == '-save-temps':
170 save_temps = 1
171
172 # Options with no arguments that should pass through
173 if arg in ['-v']:
174 compile_opts.append(arg)
175 link_opts.append(arg)
Ted Kremenek1262fc42008-05-14 20:10:33 +0000176
Ted Kremenek61cd9882008-05-24 15:58:54 +0000177 # Options with one argument that should be ignored
178 if arg in ['--param', '-u']:
Ted Kremenekb0982882008-03-25 22:35:32 +0000179 i += 1
180
Ted Kremenek61cd9882008-05-24 15:58:54 +0000181 # Prefix matches for the compile mode
182 if arg[:2] in ['-D', '-I', '-U', '-F' ]:
183 if not arg[2:]:
184 arg += args[i+1]
185 i += 1
186 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000187
Ted Kremenek61cd9882008-05-24 15:58:54 +0000188 if arg[:5] in ['-std=']:
189 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000190
Ted Kremenek61cd9882008-05-24 15:58:54 +0000191 # Options with one argument that should pass through to compiler
192 if arg in [ '-include', '-idirafter', '-iprefix',
193 '-iquote', '-isystem', '-iwithprefix',
194 '-iwithprefixbefore']:
195 compile_opts.append(arg)
196 compile_opts.append(args[i+1])
197 i += 1
198
199 # Options with no argument that should pass through to compiler
200 if arg in [ '-nostdinc', '-fobjc-gc-only', '-fobjc-gc' ]:
201 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000202
Ted Kremenek61cd9882008-05-24 15:58:54 +0000203 # Options with one argument that should pass through to linker
204 if arg == '-framework':
205 link_opts.append(arg)
206 link_opts.append(args[i+1])
207 i += 1
Ted Kremenekbfd6a3f2008-05-14 20:17:17 +0000208
Ted Kremenek61cd9882008-05-24 15:58:54 +0000209 # Options with one argument that should pass through to both
210 if arg in ['-isysroot', '-arch']:
211 compile_opts.append(arg)
212 compile_opts.append(args[i+1])
213 link_opts.append(arg)
214 link_opts.append(args[i+1])
215 i += 1
Ted Kremenekb0982882008-03-25 22:35:32 +0000216
Ted Kremenek61cd9882008-05-24 15:58:54 +0000217 # Prefix matches for the link mode
218 if arg[:2] in ['-l', '-L', '-O', '-F']:
219 if arg == '-O': arg = '-O1'
220 if arg == '-Os': arg = '-O2'
221 link_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000222
Ted Kremenek61cd9882008-05-24 15:58:54 +0000223 # Input files
224 if arg == '-filelist':
225 f = open(args[i+1])
226 for line in f:
227 files.append(line.strip())
228 f.close()
229 i += 1
230 if arg == '-x':
231 language = args[i+1]
232 i += 1
233 if arg[0] != '-':
234 files.append(arg)
235
236 # Output file
237 if arg == '-o':
238 output = args[i+1]
239 i += 1
Ted Kremenek49061fa2008-06-04 20:49:03 +0000240
241 # Arguments we currently ignore with one option.
242 if arg in ['-install_name', '-exported_symbols_list',
Ted Kremenekfe4db8b2008-06-05 22:46:24 +0000243 '-current_version', '-compatibility_version', '-init', '-e',
Ted Kremenekcd853482008-06-10 18:56:59 +0000244 '-seg1addr', '-bundle_loader', '-multiply_defined']:
Ted Kremenek49061fa2008-06-04 20:49:03 +0000245 i += 1
246
247 # Arguments we currently ignore with three options.
248 if arg in ['-sectorder']:
249 i += 3
Ted Kremenek61cd9882008-05-24 15:58:54 +0000250
251 i += 1
252
253 if action == 'print-prog-name':
254 # assume we can handle everything
255 print sys.argv[0]
256 return
257
258 if not files:
259 error('no input files')
260
261 if action == 'compile' or save_temps or action == 'link':
262 for i, file in enumerate(files):
Ted Kremenek508b3812008-05-24 16:14:34 +0000263 file_language = language
Ted Kremenek61cd9882008-05-24 15:58:54 +0000264 if not language:
Ted Kremenek508b3812008-05-24 16:14:34 +0000265 file_language = inferlanguage(extension(file))
Ted Kremenek39165e22008-05-24 16:16:30 +0000266 if file_language == "skip":
Ted Kremenek61cd9882008-05-24 15:58:54 +0000267 continue
268
269 if save_temps and action != "compile":
270 # Need a temporary output file
271 coutput = changeextension(file, "o");
272 files[i] = coutput
273 elif not output:
274 coutput = changeextension(file, "o")
275 else:
276 coutput = output
277 analyze_args = [ file ]
Ted Kremenekb96ffdf2008-06-02 17:13:40 +0000278 if file_language != 'unknown':
279 analyze_args = [ '-x', file_language ] + analyze_args
Ted Kremenek61cd9882008-05-24 15:58:54 +0000280 analyze_args = analyze_args + compile_opts
281 analyze(clang, analyze_args, language, output, files, verbose, htmldir, file, analysis_type)
Ted Kremenekb0982882008-03-25 22:35:32 +0000282
283if __name__ == '__main__':
284 main(sys.argv[1:])