blob: 25474e6f2fa55d186dc36c0b73e8fb859f05d655 [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 Kremenekf22eacb2008-04-18 22:00:56 +000053def analyze(clang, args,language,output,files,verbose,htmldir):
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 Kremenekf22eacb2008-04-18 22:00:56 +000076 command = clang.split() + '-checker-cfref'.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'
82
83
84 if RunAnalyzer and htmldir is not None:
85 args.append('-o')
86 print_args.append('-o')
87 args.append(htmldir)
88 print_args.append(htmldir)
Ted Kremenek09c2ad62008-03-31 18:25:05 +000089
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000090 if verbose:
91 # We MUST print to stderr. Some clients use the stdout output of
92 # gcc for various purposes.
Ted Kremenek09c2ad62008-03-31 18:25:05 +000093 print >> sys.stderr, ' '.join(command+print_args)
94 print >> sys.stderr, '\n'
Ted Kremeneka9525c92008-05-12 22:07:14 +000095
Ted Kremenek73cb1032008-05-13 17:10:28 +000096 subprocess.call(args)
Ted Kremenekb0982882008-03-25 22:35:32 +000097
98def link(args):
99 command = 'gcc'.split()
100 run(command + args)
101
102def extension(path):
103 return path.split(".")[-1]
104
105def changeextension(path, newext):
106 i = path.rfind('.')
107 if i < 0:
108 return path
109 j = path.rfind('/', 0, i)
110 print path
111 if j < 0:
112 return path[:i] + "." + newext
113 return path[j+1:i] + "." + newext
114
115def inferlanguage(extension):
116 if extension == "c":
117 return "c"
118 elif extension in ["cpp", "cc"]:
119 return "c++"
120 elif extension == "i":
121 return "c-cpp-output"
122 elif extension == "m":
123 return "objective-c"
124 elif extension == "mi":
125 return "objective-c-cpp-output"
126 else:
127 return "unknown"
128
129def main(args):
130 old_args = args
131 action = 'link'
132 output = ''
133 compile_opts = [ ]
134 link_opts = [ ]
135 files = []
136 save_temps = 0
137 language = ''
138
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000139 verbose = 0
Ted Kremenek33196002008-05-12 23:47:41 +0000140 clang = "clang"
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000141
Ted Kremenek33196002008-05-12 23:47:41 +0000142 # Forward to GCC.
143 compile(args)
144
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000145 if os.environ.get('CCC_ANALYZER_VERBOSE') is not None:
Ted Kremeneka9525c92008-05-12 22:07:14 +0000146 verbose = 1
147
148 if os.environ.get('CCC_ANALYZER_LOG') is not None:
149 verbose = 2
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000150
151 clang_env = os.environ.get('CLANG')
152
153 if clang_env is not None:
154 clang = clang_env
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000155
156 htmldir = os.environ.get('CCC_ANALYZER_HTML')
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000157
Ted Kremenekb0982882008-03-25 22:35:32 +0000158 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)
176
177 # Options with one argument that should be ignored
Ted Kremenekd0eef022008-04-21 20:28:01 +0000178 if arg in ['--param', '-u']:
Ted Kremenekb0982882008-03-25 22:35:32 +0000179 i += 1
180
181 # Prefix matches for the compile mode
Ted Kremenekdc343002008-04-25 21:28:20 +0000182 if arg[:2] in ['-D', '-I', '-U', '-F' ]:
Ted Kremenekb0982882008-03-25 22:35:32 +0000183 if not arg[2:]:
184 arg += args[i+1]
185 i += 1
186 compile_opts.append(arg)
Ted Kremenekdc343002008-04-25 21:28:20 +0000187
Ted Kremenekb0982882008-03-25 22:35:32 +0000188 if arg[:5] in ['-std=']:
189 compile_opts.append(arg)
190
Nate Begeman4cd36032008-04-22 04:47:32 +0000191 # Options with one argument that should pass through to compiler
Ted Kremenekdc343002008-04-25 21:28:20 +0000192 if arg in [ '-include', '-idirafter', '-iprefix',
193 '-iquote', '-isystem', '-iwithprefix',
194 '-iwithprefixbefore']:
Ted Kremenekb0982882008-03-25 22:35:32 +0000195 compile_opts.append(arg)
196 compile_opts.append(args[i+1])
197 i += 1
Ted Kremenekdc343002008-04-25 21:28:20 +0000198
199 # Options with no argument that should pass through to compiler
Ted Kremenek73c083c2008-05-01 21:26:22 +0000200 if arg in [ '-nostdinc', '-fobjc-gc-only', '-fobjc-gc' ]:
Ted Kremenekdc343002008-04-25 21:28:20 +0000201 compile_opts.append(arg)
Ted Kremenekb0982882008-03-25 22:35:32 +0000202
Nate Begeman4cd36032008-04-22 04:47:32 +0000203 # Options with one argument that should pass through to linker
Ted Kremenek73c083c2008-05-01 21:26:22 +0000204 if arg == '-framework':
Nate Begeman4cd36032008-04-22 04:47:32 +0000205 link_opts.append(arg)
206 link_opts.append(args[i+1])
207 i += 1
208
209 # 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
216
Ted Kremenekb0982882008-03-25 22:35:32 +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)
222
Ted Kremenekb0982882008-03-25 22:35:32 +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
240
241 i += 1
242
243 if action == 'print-prog-name':
244 # assume we can handle everything
245 print sys.argv[0]
246 return
247
248 if not files:
249 error('no input files')
250
Ted Kremenek33196002008-05-12 23:47:41 +0000251 # if action == 'preprocess' or save_temps:
252 # compile(args)
Ted Kremenekb0982882008-03-25 22:35:32 +0000253
254 if action == 'compile' or save_temps:
255 for i, file in enumerate(files):
256 if not language:
257 language = inferlanguage(extension(file))
258 if save_temps and action != "compile":
259 # Need a temporary output file
260 coutput = changeextension(file, "o");
261 files[i] = coutput
262 elif not output:
263 coutput = changeextension(file, "o")
264 else:
265 coutput = output
266 analyze_args = [ file ]
267 if language != 'unknown':
Ted Kremenek7edbce22008-05-12 23:56:50 +0000268 analyze_args = [ '-x', language ] + analyze_args
Ted Kremenekb0982882008-03-25 22:35:32 +0000269 analyze_args = analyze_args + compile_opts
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000270 analyze(clang, analyze_args, language, output, files, verbose, htmldir)
Ted Kremenek33196002008-05-12 23:47:41 +0000271# compile(args)
Ted Kremenekb0982882008-03-25 22:35:32 +0000272
273
Ted Kremenek33196002008-05-12 23:47:41 +0000274# if action == 'link':
275# link(args)
276# # analyze(link_opts)
Ted Kremenekb0982882008-03-25 22:35:32 +0000277
278if __name__ == '__main__':
279 main(sys.argv[1:])