blob: 4442c18e56a06bef032f500319bb42e3d52a6ab0 [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
40def preprocess(args):
41 command = 'clang -E'.split()
42 run(command + args)
43
44def compile(args):
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000045 # We MUST print to stderr. Some clients use the stdout output of
46 # gcc for various purposes.
Ted Kremenekb0982882008-03-25 22:35:32 +000047 print >> sys.stderr, '\n'
48 command = 'gcc'.split()
49 run(command + args)
50
51def remove_pch_extension(path):
52 i = path.rfind('.gch')
53 if i < 0:
54 return path
55 return path[:i]
56
Ted Kremenek09c2ad62008-03-31 18:25:05 +000057def analyze(args,language,output,files,verbose,htmldir):
Ted Kremenek8cb53fb2008-04-03 21:29:11 +000058 if language.find("c++") > 0:
Ted Kremenekb0982882008-03-25 22:35:32 +000059 return
60
Ted Kremenekb0982882008-03-25 22:35:32 +000061 print_args = []
62
Ted Kremenek09c2ad62008-03-31 18:25:05 +000063 if verbose:
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000064 # We MUST print to stderr. Some clients use the stdout output of
65 # gcc for various purposes.
Ted Kremenek09c2ad62008-03-31 18:25:05 +000066 print >> sys.stderr, ' '.join(['\n[LOCATION]:', os.getcwd(), '\n' ])
67 i = 0
68 while i < len(args):
Ted Kremenekb0982882008-03-25 22:35:32 +000069 print_args.append(''.join([ '\'', args[i], '\'' ]))
70 i += 1
71
72 if language.find("header") > 0:
73 target = remove_pch_extension(output)
74 command = 'cp'.split()
75 args = command + files + target.split()
76 else:
Ted Kremenekaf79c112008-04-18 21:53:01 +000077 command = 'clang -checker-cfref'.split()
Ted Kremenek69b64422008-03-31 21:20:32 +000078 args = command + args;
79
80 if htmldir is not None:
81 args.append('-o')
82 print_args.append('-o')
83 args.append(htmldir)
84 print_args.append(htmldir)
Ted Kremenek09c2ad62008-03-31 18:25:05 +000085
Ted Kremenek6e9d38e2008-04-07 23:27:54 +000086 if verbose:
87 # We MUST print to stderr. Some clients use the stdout output of
88 # gcc for various purposes.
Ted Kremenek09c2ad62008-03-31 18:25:05 +000089 print >> sys.stderr, ' '.join(command+print_args)
90 print >> sys.stderr, '\n'
Ted Kremenekb0982882008-03-25 22:35:32 +000091
Ted Kremenekb0982882008-03-25 22:35:32 +000092 subprocess.call(args)
93
94def link(args):
95 command = 'gcc'.split()
96 run(command + args)
97
98def extension(path):
99 return path.split(".")[-1]
100
101def changeextension(path, newext):
102 i = path.rfind('.')
103 if i < 0:
104 return path
105 j = path.rfind('/', 0, i)
106 print path
107 if j < 0:
108 return path[:i] + "." + newext
109 return path[j+1:i] + "." + newext
110
111def inferlanguage(extension):
112 if extension == "c":
113 return "c"
114 elif extension in ["cpp", "cc"]:
115 return "c++"
116 elif extension == "i":
117 return "c-cpp-output"
118 elif extension == "m":
119 return "objective-c"
120 elif extension == "mi":
121 return "objective-c-cpp-output"
122 else:
123 return "unknown"
124
125def main(args):
126 old_args = args
127 action = 'link'
128 output = ''
129 compile_opts = [ ]
130 link_opts = [ ]
131 files = []
132 save_temps = 0
133 language = ''
134
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000135 verbose = 0
136
137 if os.environ.get('CCC_ANALYZER_VERBOSE') is not None:
138 verbose =1
139
140 htmldir = os.environ.get('CCC_ANALYZER_HTML')
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000141
Ted Kremenekb0982882008-03-25 22:35:32 +0000142 i = 0
143 while i < len(args):
144 arg = args[i]
145
146 # Modes ccc supports
147 if arg == '-E':
148 action = 'preprocess'
149 if arg == '-c':
150 action = 'compile'
151 if arg.startswith('-print-prog-name'):
152 action = 'print-prog-name'
153 if arg == '-save-temps':
154 save_temps = 1
155
156 # Options with no arguments that should pass through
157 if arg in ['-v']:
158 compile_opts.append(arg)
159 link_opts.append(arg)
160
161 # Options with one argument that should be ignored
162 if arg in ['--param', '-arch', '-u']:
163 i += 1
164
165 # Prefix matches for the compile mode
166 if arg[:2] in ['-D', '-I', '-U', '-F']:
167 if not arg[2:]:
168 arg += args[i+1]
169 i += 1
170 compile_opts.append(arg)
171 if arg[:5] in ['-std=']:
172 compile_opts.append(arg)
173
174 # Options with one argument that should pass through
175 if arg in ['-include']:
176 compile_opts.append(arg)
177 compile_opts.append(args[i+1])
178 i += 1
179
180 # Prefix matches for the link mode
181 if arg[:2] in ['-l', '-L', '-O', '-F']:
182 if arg == '-O': arg = '-O1'
183 if arg == '-Os': arg = '-O2'
184 link_opts.append(arg)
185
186 # Options with one argument that should pass through
187 if arg in ['-framework']:
188 link_opts.append(arg)
189 link_opts.append(args[i+1])
190 i += 1
191
192 # Input files
193 if arg == '-filelist':
194 f = open(args[i+1])
195 for line in f:
196 files.append(line.strip())
197 f.close()
198 i += 1
199 if arg == '-x':
200 language = args[i+1]
201 i += 1
202 if arg[0] != '-':
203 files.append(arg)
204
205 # Output file
206 if arg == '-o':
207 output = args[i+1]
208 i += 1
209
210 i += 1
211
212 if action == 'print-prog-name':
213 # assume we can handle everything
214 print sys.argv[0]
215 return
216
217 if not files:
218 error('no input files')
219
220 if action == 'preprocess' or save_temps:
221 compile(args)
222
223 if action == 'compile' or save_temps:
224 for i, file in enumerate(files):
225 if not language:
226 language = inferlanguage(extension(file))
227 if save_temps and action != "compile":
228 # Need a temporary output file
229 coutput = changeextension(file, "o");
230 files[i] = coutput
231 elif not output:
232 coutput = changeextension(file, "o")
233 else:
234 coutput = output
235 analyze_args = [ file ]
236 if language != 'unknown':
237 analyze_args = analyze_args + [ '-x', language ]
238 analyze_args = analyze_args + compile_opts
Ted Kremenek09c2ad62008-03-31 18:25:05 +0000239 analyze(analyze_args, language, output, files, verbose, htmldir)
Ted Kremenekb0982882008-03-25 22:35:32 +0000240 compile(args)
241
242
243 if action == 'link':
244 link(args)
245# analyze(link_opts)
246
247if __name__ == '__main__':
248 main(sys.argv[1:])