blob: 5cb9151f35982955d6adcc04dbfc982b4589394c [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
Seo Sanghyeond3894652008-04-04 11:02:21 +000024def quote(arg):
25 if '"' in arg:
26 return repr(arg)
27 return arg
28
Ted Kremenekb0982882008-03-25 22:35:32 +000029def run(args):
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000030 # We MUST print to stderr. Some clients use the stdout output of
31 # gcc for various purposes.
Ted Kremenek33196002008-05-12 23:47:41 +000032 #print >> sys.stderr, ' '.join(map(quote, args))
33 #print >> sys.stderr
Ted Kremenekb0982882008-03-25 22:35:32 +000034 code = subprocess.call(args)
35 if code > 255:
36 code = 1
37 if code:
38 sys.exit(code)
39
Ted Kremenekfe873542008-04-21 21:58:05 +000040def compile(args):
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000041 # We MUST print to stderr. Some clients use the stdout output of
42 # gcc for various purposes.
Ted Kremenek33196002008-05-12 23:47:41 +000043 #print >> sys.stderr, '\n'
Ted Kremenekb0982882008-03-25 22:35:32 +000044 command = 'gcc'.split()
45 run(command + args)
46
47def remove_pch_extension(path):
48 i = path.rfind('.gch')
49 if i < 0:
50 return path
51 return path[:i]
52
Ted Kremenek1262fc42008-05-14 20:10:33 +000053def analyze(clang, args,language,output,files,verbose,htmldir,file,analysis_type):
Ted Kremenek8cb53fb2008-04-03 21:29:11 +000054 if language.find("c++") > 0:
Ted Kremenekb0982882008-03-25 22:35:32 +000055 return
56
Ted Kremenekb0982882008-03-25 22:35:32 +000057 print_args = []
58
Ted Kremenek09c2ad62008-03-31 18:25:05 +000059 if verbose:
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000060 # We MUST print to stderr. Some clients use the stdout output of
61 # gcc for various purposes.
Ted Kremenek09c2ad62008-03-31 18:25:05 +000062 print >> sys.stderr, ' '.join(['\n[LOCATION]:', os.getcwd(), '\n' ])
63 i = 0
64 while i < len(args):
Ted Kremenekb0982882008-03-25 22:35:32 +000065 print_args.append(''.join([ '\'', args[i], '\'' ]))
66 i += 1
Ted Kremeneka9525c92008-05-12 22:07:14 +000067
68
69 RunAnalyzer = 0;
70
Ted Kremenekb0982882008-03-25 22:35:32 +000071 if language.find("header") > 0:
72 target = remove_pch_extension(output)
73 command = 'cp'.split()
74 args = command + files + target.split()
75 else:
Ted Kremenek1262fc42008-05-14 20:10:33 +000076 command = clang.split() + analysis_type.split()
Ted Kremenek69b64422008-03-31 21:20:32 +000077 args = command + args;
Ted Kremeneka9525c92008-05-12 22:07:14 +000078 RunAnalyzer = 1
79
80 if verbose == 2:
81 print >> sys.stderr, '#SHELL (cd ' + os.getcwd() + ' && ' + ' '.join(command + print_args) + ')\n'
Ted Kremeneka9525c92008-05-12 22:07:14 +000082
83 if RunAnalyzer and htmldir is not None:
84 args.append('-o')
85 print_args.append('-o')
86 args.append(htmldir)
87 print_args.append(htmldir)
Ted Kremenek09c2ad62008-03-31 18:25:05 +000088
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000089 if verbose:
90 # We MUST print to stderr. Some clients use the stdout output of
91 # gcc for various purposes.
Ted Kremenek09c2ad62008-03-31 18:25:05 +000092 print >> sys.stderr, ' '.join(command+print_args)
93 print >> sys.stderr, '\n'
Ted Kremeneka9525c92008-05-12 22:07:14 +000094
Ted Kremenek73cb1032008-05-13 17:10:28 +000095 subprocess.call(args)
Ted Kremenekb0982882008-03-25 22:35:32 +000096
97def link(args):
98 command = 'gcc'.split()
99 run(command + args)
100
101def extension(path):
102 return path.split(".")[-1]
103
104def changeextension(path, newext):
105 i = path.rfind('.')
106 if i < 0:
107 return path
108 j = path.rfind('/', 0, i)
109 print path
110 if j < 0:
111 return path[:i] + "." + newext
112 return path[j+1:i] + "." + newext
113
114def inferlanguage(extension):
115 if extension == "c":
116 return "c"
117 elif extension in ["cpp", "cc"]:
118 return "c++"
119 elif extension == "i":
120 return "c-cpp-output"
121 elif extension == "m":
122 return "objective-c"
123 elif extension == "mi":
124 return "objective-c-cpp-output"
Ted Kremenekbfd6a3f2008-05-14 20:17:17 +0000125 elif extention == "s":
126 return "skip"
Ted Kremenekb0982882008-03-25 22:35:32 +0000127 else:
128 return "unknown"
129
130def main(args):
131 old_args = args
132 action = 'link'
133 output = ''
134 compile_opts = [ ]
135 link_opts = [ ]
136 files = []
137 save_temps = 0
138 language = ''
139
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000140 verbose = 0
Ted Kremenek33196002008-05-12 23:47:41 +0000141 clang = "clang"
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000142
Ted Kremenek33196002008-05-12 23:47:41 +0000143 # Forward to GCC.
144 compile(args)
Ted Kremenek1262fc42008-05-14 20:10:33 +0000145
146 # Set the analyzer flag.
147 analysis_type = os.environ.get('CCC_ANALYZER_ANALYSIS')
148
149 if analysis_type is not None:
150 analysis_type = "-" + analysis_type
151 else:
152 analysis_type = "-checker-cfref"
153
154 # Determine the level of verbosity.
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000155 if os.environ.get('CCC_ANALYZER_VERBOSE') is not None:
Ted Kremeneka9525c92008-05-12 22:07:14 +0000156 verbose = 1
157
158 if os.environ.get('CCC_ANALYZER_LOG') is not None:
159 verbose = 2
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000160
Ted Kremenek1262fc42008-05-14 20:10:33 +0000161 # Determine what clang executable to use.
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000162 clang_env = os.environ.get('CLANG')
163
164 if clang_env is not None:
165 clang = clang_env
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000166
Ted Kremenek1262fc42008-05-14 20:10:33 +0000167 # Get the HTML output directory.
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000168 htmldir = os.environ.get('CCC_ANALYZER_HTML')
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000169
Ted Kremenekb0982882008-03-25 22:35:32 +0000170 i = 0
171 while i < len(args):
172 arg = args[i]
173
174 # Modes ccc supports
175 if arg == '-E':
176 action = 'preprocess'
177 if arg == '-c':
178 action = 'compile'
179 if arg.startswith('-print-prog-name'):
180 action = 'print-prog-name'
181 if arg == '-save-temps':
182 save_temps = 1
183
184 # Options with no arguments that should pass through
185 if arg in ['-v']:
186 compile_opts.append(arg)
187 link_opts.append(arg)
188
189 # Options with one argument that should be ignored
Ted Kremenekd0eef022008-04-21 20:28:01 +0000190 if arg in ['--param', '-u']:
Ted Kremenekb0982882008-03-25 22:35:32 +0000191 i += 1
192
193 # Prefix matches for the compile mode
Ted Kremenekdc343002008-04-25 21:28:20 +0000194 if arg[:2] in ['-D', '-I', '-U', '-F' ]:
Ted Kremenekb0982882008-03-25 22:35:32 +0000195 if not arg[2:]:
196 arg += args[i+1]
197 i += 1
198 compile_opts.append(arg)
Ted Kremenekdc343002008-04-25 21:28:20 +0000199
Ted Kremenekb0982882008-03-25 22:35:32 +0000200 if arg[:5] in ['-std=']:
201 compile_opts.append(arg)
202
Nate Begeman4cd36032008-04-22 04:47:32 +0000203 # Options with one argument that should pass through to compiler
Ted Kremenekdc343002008-04-25 21:28:20 +0000204 if arg in [ '-include', '-idirafter', '-iprefix',
205 '-iquote', '-isystem', '-iwithprefix',
206 '-iwithprefixbefore']:
Ted Kremenekb0982882008-03-25 22:35:32 +0000207 compile_opts.append(arg)
208 compile_opts.append(args[i+1])
209 i += 1
Ted Kremenekdc343002008-04-25 21:28:20 +0000210
211 # Options with no argument that should pass through to compiler
Ted Kremenek73c083c2008-05-01 21:26:22 +0000212 if arg in [ '-nostdinc', '-fobjc-gc-only', '-fobjc-gc' ]:
Ted Kremenekdc343002008-04-25 21:28:20 +0000213 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000214
Nate Begeman4cd36032008-04-22 04:47:32 +0000215 # Options with one argument that should pass through to linker
Ted Kremenek73c083c2008-05-01 21:26:22 +0000216 if arg == '-framework':
Nate Begeman4cd36032008-04-22 04:47:32 +0000217 link_opts.append(arg)
218 link_opts.append(args[i+1])
219 i += 1
220
221 # Options with one argument that should pass through to both
222 if arg in ['-isysroot', '-arch']:
223 compile_opts.append(arg)
224 compile_opts.append(args[i+1])
225 link_opts.append(arg)
226 link_opts.append(args[i+1])
227 i += 1
228
Ted Kremenekb0982882008-03-25 22:35:32 +0000229 # Prefix matches for the link mode
230 if arg[:2] in ['-l', '-L', '-O', '-F']:
231 if arg == '-O': arg = '-O1'
232 if arg == '-Os': arg = '-O2'
233 link_opts.append(arg)
234
Ted Kremenekb0982882008-03-25 22:35:32 +0000235 # Input files
236 if arg == '-filelist':
237 f = open(args[i+1])
238 for line in f:
239 files.append(line.strip())
240 f.close()
241 i += 1
242 if arg == '-x':
243 language = args[i+1]
244 i += 1
245 if arg[0] != '-':
246 files.append(arg)
247
248 # Output file
249 if arg == '-o':
250 output = args[i+1]
251 i += 1
252
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
Ted Kremenek33196002008-05-12 23:47:41 +0000263 # if action == 'preprocess' or save_temps:
264 # compile(args)
Ted Kremenekb0982882008-03-25 22:35:32 +0000265
266 if action == 'compile' or save_temps:
267 for i, file in enumerate(files):
268 if not language:
269 language = inferlanguage(extension(file))
Ted Kremenekbfd6a3f2008-05-14 20:17:17 +0000270 if language == "skip":
271 continue
272
Ted Kremenekb0982882008-03-25 22:35:32 +0000273 if save_temps and action != "compile":
274 # Need a temporary output file
275 coutput = changeextension(file, "o");
276 files[i] = coutput
277 elif not output:
278 coutput = changeextension(file, "o")
279 else:
280 coutput = output
281 analyze_args = [ file ]
282 if language != 'unknown':
Ted Kremenek7edbce22008-05-12 23:56:50 +0000283 analyze_args = [ '-x', language ] + analyze_args
Ted Kremenekb0982882008-03-25 22:35:32 +0000284 analyze_args = analyze_args + compile_opts
Ted Kremenek1262fc42008-05-14 20:10:33 +0000285 analyze(clang, analyze_args, language, output, files, verbose, htmldir, file, analysis_type)
Ted Kremenek33196002008-05-12 23:47:41 +0000286# compile(args)
Ted Kremenekb0982882008-03-25 22:35:32 +0000287
288
Ted Kremenek33196002008-05-12 23:47:41 +0000289# if action == 'link':
290# link(args)
291# # analyze(link_opts)
Ted Kremenekb0982882008-03-25 22:35:32 +0000292
293if __name__ == '__main__':
294 main(sys.argv[1:])