blob: abd86f85bf7d63b325c833ec4807459eebb26a26 [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.
32 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 Kremenekb0982882008-03-25 22:35:32 +000043 print >> sys.stderr, '\n'
44 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
67
68 if language.find("header") > 0:
69 target = remove_pch_extension(output)
70 command = 'cp'.split()
71 args = command + files + target.split()
72 else:
Ted Kremenekf22eacb2008-04-18 22:00:56 +000073 command = clang.split() + '-checker-cfref'.split()
Ted Kremenek69b64422008-03-31 21:20:32 +000074 args = command + args;
75
76 if htmldir is not None:
77 args.append('-o')
78 print_args.append('-o')
79 args.append(htmldir)
80 print_args.append(htmldir)
Ted Kremenek09c2ad62008-03-31 18:25:05 +000081
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000082 if verbose:
83 # We MUST print to stderr. Some clients use the stdout output of
84 # gcc for various purposes.
Ted Kremenek09c2ad62008-03-31 18:25:05 +000085 print >> sys.stderr, ' '.join(command+print_args)
86 print >> sys.stderr, '\n'
Ted Kremenekb0982882008-03-25 22:35:32 +000087
Ted Kremenekb0982882008-03-25 22:35:32 +000088 subprocess.call(args)
89
90def link(args):
91 command = 'gcc'.split()
92 run(command + args)
93
94def extension(path):
95 return path.split(".")[-1]
96
97def changeextension(path, newext):
98 i = path.rfind('.')
99 if i < 0:
100 return path
101 j = path.rfind('/', 0, i)
102 print path
103 if j < 0:
104 return path[:i] + "." + newext
105 return path[j+1:i] + "." + newext
106
107def inferlanguage(extension):
108 if extension == "c":
109 return "c"
110 elif extension in ["cpp", "cc"]:
111 return "c++"
112 elif extension == "i":
113 return "c-cpp-output"
114 elif extension == "m":
115 return "objective-c"
116 elif extension == "mi":
117 return "objective-c-cpp-output"
118 else:
119 return "unknown"
120
121def main(args):
122 old_args = args
123 action = 'link'
124 output = ''
125 compile_opts = [ ]
126 link_opts = [ ]
127 files = []
128 save_temps = 0
129 language = ''
130
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000131 verbose = 0
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000132 clang = "clang"
133
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000134
135 if os.environ.get('CCC_ANALYZER_VERBOSE') is not None:
136 verbose =1
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000137
138 clang_env = os.environ.get('CLANG')
139
140 if clang_env is not None:
141 clang = clang_env
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000142
143 htmldir = os.environ.get('CCC_ANALYZER_HTML')
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000144
Ted Kremenekb0982882008-03-25 22:35:32 +0000145 i = 0
146 while i < len(args):
147 arg = args[i]
148
149 # Modes ccc supports
150 if arg == '-E':
151 action = 'preprocess'
152 if arg == '-c':
153 action = 'compile'
154 if arg.startswith('-print-prog-name'):
155 action = 'print-prog-name'
156 if arg == '-save-temps':
157 save_temps = 1
158
159 # Options with no arguments that should pass through
160 if arg in ['-v']:
161 compile_opts.append(arg)
162 link_opts.append(arg)
163
164 # Options with one argument that should be ignored
Ted Kremenekd0eef022008-04-21 20:28:01 +0000165 if arg in ['--param', '-u']:
Ted Kremenekb0982882008-03-25 22:35:32 +0000166 i += 1
167
168 # Prefix matches for the compile mode
169 if arg[:2] in ['-D', '-I', '-U', '-F']:
170 if not arg[2:]:
171 arg += args[i+1]
172 i += 1
173 compile_opts.append(arg)
174 if arg[:5] in ['-std=']:
175 compile_opts.append(arg)
176
Nate Begeman4cd36032008-04-22 04:47:32 +0000177 # Options with one argument that should pass through to compiler
178 if arg == 'include':
Ted Kremenekb0982882008-03-25 22:35:32 +0000179 compile_opts.append(arg)
180 compile_opts.append(args[i+1])
181 i += 1
182
Nate Begeman4cd36032008-04-22 04:47:32 +0000183 # Options with one argument that should pass through to linker
184 if arg == 'framework':
185 link_opts.append(arg)
186 link_opts.append(args[i+1])
187 i += 1
188
189 # Options with one argument that should pass through to both
190 if arg in ['-isysroot', '-arch']:
191 compile_opts.append(arg)
192 compile_opts.append(args[i+1])
193 link_opts.append(arg)
194 link_opts.append(args[i+1])
195 i += 1
196
Ted Kremenekb0982882008-03-25 22:35:32 +0000197 # Prefix matches for the link mode
198 if arg[:2] in ['-l', '-L', '-O', '-F']:
199 if arg == '-O': arg = '-O1'
200 if arg == '-Os': arg = '-O2'
201 link_opts.append(arg)
202
Ted Kremenekb0982882008-03-25 22:35:32 +0000203 # Input files
204 if arg == '-filelist':
205 f = open(args[i+1])
206 for line in f:
207 files.append(line.strip())
208 f.close()
209 i += 1
210 if arg == '-x':
211 language = args[i+1]
212 i += 1
213 if arg[0] != '-':
214 files.append(arg)
215
216 # Output file
217 if arg == '-o':
218 output = args[i+1]
219 i += 1
220
221 i += 1
222
223 if action == 'print-prog-name':
224 # assume we can handle everything
225 print sys.argv[0]
226 return
227
228 if not files:
229 error('no input files')
230
231 if action == 'preprocess' or save_temps:
232 compile(args)
233
234 if action == 'compile' or save_temps:
235 for i, file in enumerate(files):
236 if not language:
237 language = inferlanguage(extension(file))
238 if save_temps and action != "compile":
239 # Need a temporary output file
240 coutput = changeextension(file, "o");
241 files[i] = coutput
242 elif not output:
243 coutput = changeextension(file, "o")
244 else:
245 coutput = output
246 analyze_args = [ file ]
247 if language != 'unknown':
248 analyze_args = analyze_args + [ '-x', language ]
249 analyze_args = analyze_args + compile_opts
Ted Kremenekf22eacb2008-04-18 22:00:56 +0000250 analyze(clang, analyze_args, language, output, files, verbose, htmldir)
Ted Kremenekb0982882008-03-25 22:35:32 +0000251 compile(args)
252
253
254 if action == 'link':
255 link(args)
256# analyze(link_opts)
257
258if __name__ == '__main__':
259 main(sys.argv[1:])