|
1 #!/usr/bin/python |
|
2 # |
|
3 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 # All rights reserved. |
|
5 # This component and the accompanying materials are made available |
|
6 # under the terms of "Eclipse Public License v1.0" |
|
7 # which accompanies this distribution, and is available |
|
8 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
9 # |
|
10 # Initial Contributors: |
|
11 # Nokia Corporation - initial contribution. |
|
12 # |
|
13 # Contributors: |
|
14 # |
|
15 # Description: This script checks the build logs for warnings and categorizes |
|
16 # them into various categories. Returns 1 if there are BAD warnings. |
|
17 # |
|
18 |
|
19 import sys |
|
20 from optparse import OptionParser |
|
21 |
|
22 |
|
23 class WarningHandler: |
|
24 |
|
25 # Counters for various warnings |
|
26 totalWarnings = 0 |
|
27 badOnes = 0 |
|
28 deprecatedWarnings = 0 |
|
29 compilerWarnings = 0 |
|
30 linkerWarnings = 0 |
|
31 postlinkerWarnings = 0 |
|
32 flmWarnings = 0 |
|
33 |
|
34 # Constants for matching warnings related to deprecation |
|
35 deprecatedStart = "warning: preprocessor #warning directive" |
|
36 deprecatedSecondLine = "warning: #warning This header file has been deprecated. Will be removed in one of the next SDK releases." |
|
37 deprecatedOptionalThirdLine = "warning: (included from:" |
|
38 deprecatedOptionalRest = "warning: " |
|
39 |
|
40 # This list includes strings from which the BAD warnings can be recognized. |
|
41 # Note that these must be in lower case! |
|
42 badWarnings = [ |
|
43 "#111-d", "#1166-d", "#117-d", "#128-d", "#1293-d", "#1441-d", "#170-d", |
|
44 "#174-d", "#175-d", "#185-d", "#186-d", "#223-d", "#231-d", "#257-d", |
|
45 "#284-d", "#368-d", "#414-d", "#430-d", "#47-d", "#514-d", "#546-d", |
|
46 "#68-d", "#69-d", "#830-d", "#940-d", "c2874w", "c4127", "c4355", "c4530", |
|
47 "c4702", "c4786", "lnk4049", "#836-d", "a1495e", "l6318w" ] |
|
48 |
|
49 |
|
50 def IsBadWarning(self, lowerCasedLine): |
|
51 for bad in self.badWarnings: |
|
52 if bad in lowerCasedLine: |
|
53 return True |
|
54 return False |
|
55 |
|
56 |
|
57 def PrintResults(self): |
|
58 print "\n-------------------------------\n" |
|
59 print "Total warnings:", self.totalWarnings |
|
60 print "Bad ones: ", self.badOnes |
|
61 print "" |
|
62 print "Details:" |
|
63 print " FLM warnings: ", self.flmWarnings |
|
64 print " Use of deprecated api: ", self.deprecatedWarnings |
|
65 print " Other compiler warnings: ", self.compilerWarnings |
|
66 print " Linker warnings: ", self.linkerWarnings |
|
67 print " Post-linker warnings: ", self.postlinkerWarnings |
|
68 |
|
69 |
|
70 |
|
71 class PrintSettings: |
|
72 """Class parsing and maintaining the printing settings related to warnings""" |
|
73 |
|
74 printDeprecatedWarnings = False |
|
75 printCompilerWarnings = False |
|
76 printLinkerWarnings = False |
|
77 printFlmWarnings = False |
|
78 |
|
79 def parseArgs(self): |
|
80 parser = OptionParser( |
|
81 usage = "python -u %prog [options] <logfile>", |
|
82 description = "Analyzes warnings from the given log file. " + \ |
|
83 "By default prints only BAD warnings and statistics.") |
|
84 parser.add_option("--printall", dest="printall", action="store_true", |
|
85 default=False, help="Prints all the warnings") |
|
86 parser.add_option("--pc", dest="printcompilerwarnings", action="store_true", |
|
87 default=False, help="Prints compiler warnings") |
|
88 parser.add_option("--pl", dest="printlinkerwarnings", action="store_true", |
|
89 default=False, help="Prints linker warnings") |
|
90 parser.add_option("--pd", dest="printdeprecatedwarnings", action="store_true", |
|
91 default=False, help="Prints deprecation warnings") |
|
92 parser.add_option("--pf", dest="printflmwarnings", action="store_true", |
|
93 default=False, help="Prints FLM warnings") |
|
94 (opts, args) = parser.parse_args() |
|
95 |
|
96 if len(args) != 1: |
|
97 parser.print_help() |
|
98 sys.exit(-1) |
|
99 |
|
100 if opts.printall: |
|
101 self.printDeprecatedWarnings = True |
|
102 self.printCompilerWarnings = True |
|
103 self.printLinkerWarnings = True |
|
104 self.printFlmWarnings = True |
|
105 else: |
|
106 self.printDeprecatedWarnings = opts.printdeprecatedwarnings |
|
107 self.printCompilerWarnings = opts.printcompilerwarnings |
|
108 self.printLinkerWarnings = opts.printlinkerwarnings |
|
109 self.printFlmWarnings = opts.printflmwarnings |
|
110 |
|
111 return args[0] |
|
112 |
|
113 |
|
114 |
|
115 # Calculates the number of various warnings from the given file containing |
|
116 # the console output from a Raptor build. |
|
117 # |
|
118 # BAD warnings are those warnings that are considered so important that builds |
|
119 # should have always zero of them. The related log message strings are defined |
|
120 # in the variable badWarnings above. |
|
121 # |
|
122 # The warnings are further categorized as deprecated API warnings, compiler |
|
123 # warnings, linker, and post-linker warnings. |
|
124 # |
|
125 def main(): |
|
126 |
|
127 # Parse command line options and log file name. |
|
128 settings = PrintSettings() |
|
129 path = settings.parseArgs() |
|
130 |
|
131 # Read in the lines |
|
132 f = open(path) |
|
133 lines = f.readlines() |
|
134 f.close() |
|
135 |
|
136 # Initialize the warning handler |
|
137 wh = WarningHandler() |
|
138 |
|
139 # Initial state for the state machine, see the method stateMachine for |
|
140 # information about the other states |
|
141 state = 0 |
|
142 underCompilation = "" |
|
143 |
|
144 # Check all the lines for possible warnings |
|
145 for line in lines: |
|
146 |
|
147 # Reset the target always when having line of form " xyz" |
|
148 # Works also with empty lines as the newline is counted in |
|
149 if line[0] == ' ' and line[1] != ' ': |
|
150 underCompilation = line |
|
151 state = 1; |
|
152 continue |
|
153 |
|
154 state = stateMachine(state, line, underCompilation, settings, wh) |
|
155 |
|
156 # Done with the parsing, just dump the statistics |
|
157 wh.PrintResults() |
|
158 |
|
159 if wh.badOnes > 0: |
|
160 sys.exit(1) |
|
161 else: |
|
162 sys.exit(0) |
|
163 |
|
164 |
|
165 # The state machine function doing the actual work |
|
166 def stateMachine(state, line, underCompilation, settings, wh): |
|
167 |
|
168 # Looking for any warning related to the current target |
|
169 if state == 1: |
|
170 |
|
171 # Check first for the start of a multiline deprecation warning |
|
172 if wh.deprecatedStart in line: |
|
173 if settings.printDeprecatedWarnings: |
|
174 print underCompilation, |
|
175 print line, |
|
176 wh.deprecatedWarnings += 1 |
|
177 wh.totalWarnings += 1 |
|
178 return 2 |
|
179 |
|
180 else: |
|
181 |
|
182 # Then check for all the other warnings |
|
183 lowerCasedLine = line.lower() |
|
184 if "warning:" in lowerCasedLine: |
|
185 wh.totalWarnings += 1 |
|
186 |
|
187 # Check for bad warnings |
|
188 isBad = wh.IsBadWarning(lowerCasedLine) |
|
189 if isBad: |
|
190 wh.badOnes += 1 |
|
191 |
|
192 # Categorize and print the warning (BAD warnings are printed always) |
|
193 if ("mwldsym2.exe: warning" in lowerCasedLine): |
|
194 wh.linkerWarnings += 1 |
|
195 if settings.printLinkerWarnings or isBad: |
|
196 print underCompilation, |
|
197 print line, |
|
198 elif ("elf2e32: warning:" in lowerCasedLine): |
|
199 wh.postlinkerWarnings += 1 |
|
200 if settings.printLinkerWarnings or isBad: |
|
201 print underCompilation, |
|
202 print line, |
|
203 elif ("makedef warning:" in lowerCasedLine): |
|
204 wh.postlinkerWarnings += 1 |
|
205 if settings.printLinkerWarnings: |
|
206 print underCompilation, |
|
207 print line, |
|
208 return 5 # find the rest of the lines |
|
209 elif ("warning: overriding commands for target" in lowerCasedLine or |
|
210 "warning: ignoring old commands for target" in lowerCasedLine): |
|
211 wh.flmWarnings += 1 |
|
212 if settings.printFlmWarnings or isBad: |
|
213 print underCompilation, |
|
214 print line, |
|
215 elif (": warning:" in lowerCasedLine): |
|
216 wh.compilerWarnings += 1 |
|
217 if settings.printCompilerWarnings or isBad: |
|
218 print underCompilation, |
|
219 print line, |
|
220 |
|
221 return 1 |
|
222 |
|
223 # Looking for the second line of the multiline deprecation warning |
|
224 if state == 2: |
|
225 if wh.deprecatedSecondLine in line: |
|
226 if settings.printDeprecatedWarnings: |
|
227 print line, |
|
228 return 3 |
|
229 else: |
|
230 print "Missing second line" |
|
231 return 1 |
|
232 |
|
233 # Looking for the optional third line of the multiline deprecation warning |
|
234 if state == 3: |
|
235 if wh.deprecatedOptionalThirdLine in line: |
|
236 if settings.printDeprecatedWarnings: |
|
237 print line, |
|
238 return 4 |
|
239 else: |
|
240 # Hmm... went one line too far -> need to check the current line again |
|
241 # but now in the state 1 |
|
242 return stateMachine(1, line, underCompilation, settings, wh) |
|
243 |
|
244 # Looking for the optional trailing lines of the multiline deprecation warning |
|
245 if state == 4: |
|
246 if wh.deprecatedOptionalRest in line: |
|
247 if settings.printDeprecatedWarnings: |
|
248 print line, |
|
249 return 4 |
|
250 else: |
|
251 # Hmm... went one line too far -> need to check the current line again |
|
252 # but now in the state 1 |
|
253 return stateMachine(1, line, underCompilation, settings, wh) |
|
254 |
|
255 # Looking for MAKEDEF detailed information lines |
|
256 if state == 5: |
|
257 if settings.printLinkerWarnings: |
|
258 print line, |
|
259 return 1 |
|
260 |
|
261 |
|
262 |
|
263 if __name__ == "__main__": |
|
264 main() |