OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 | 2 |
3 # Copyright 2014 The Chromium Authors. All rights reserved. | 3 # Copyright 2014 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 """Given the output of -t commands from a ninja build for a gyp and GN generated | 7 """Given the output of -t commands from a ninja build for a gyp and GN generated |
8 build, report on differences between the command lines.""" | 8 build, report on differences between the command lines.""" |
9 | 9 |
10 | 10 |
11 import os | 11 import os |
12 import subprocess | 12 import subprocess |
13 import sys | 13 import sys |
14 | 14 |
15 | 15 |
| 16 # Must be in src/. |
| 17 os.chdir(os.path.join(os.path.dirname(__file__), '..', '..', '..')) |
| 18 |
| 19 |
| 20 g_total_differences = 0 |
| 21 |
| 22 |
16 def FindAndRemoveArgWithValue(command_line, argname): | 23 def FindAndRemoveArgWithValue(command_line, argname): |
17 """Given a command line as a list, remove and return the value of an option | 24 """Given a command line as a list, remove and return the value of an option |
18 that takes a value as a separate entry. | 25 that takes a value as a separate entry. |
19 | 26 |
20 Modifies |command_line| in place. | 27 Modifies |command_line| in place. |
21 """ | 28 """ |
22 if argname not in command_line: | 29 if argname not in command_line: |
23 return '' | 30 return '' |
24 location = command_line.index(argname) | 31 location = command_line.index(argname) |
25 value = command_line[location + 1] | 32 value = command_line[location + 1] |
26 command_line[location:location + 2] = [] | 33 command_line[location:location + 2] = [] |
27 return value | 34 return value |
28 | 35 |
29 | 36 |
30 def MergeSpacedArgs(command_line, argname): | 37 def MergeSpacedArgs(command_line, argname): |
31 """Combine all arguments |argname| with their values, separated by a space.""" | 38 """Combine all arguments |argname| with their values, separated by a space.""" |
32 i = 0 | 39 i = 0 |
33 result = [] | 40 result = [] |
34 while i < len(command_line): | 41 while i < len(command_line): |
35 arg = command_line[i] | 42 arg = command_line[i] |
36 if arg == argname: | 43 if arg == argname: |
37 result.append(arg + ' ' + command_line[i + 1]) | 44 result.append(arg + ' ' + command_line[i + 1]) |
38 i += 1 | 45 i += 1 |
39 else: | 46 else: |
40 result.append(arg) | 47 result.append(arg) |
41 i += 1 | 48 i += 1 |
42 return result | 49 return result |
43 | 50 |
44 | 51 |
| 52 def NormalizeSymbolArguments(command_line): |
| 53 """Normalize -g arguments. |
| 54 |
| 55 If there's no -g args, it's equivalent to -g0. -g2 is equivalent to -g. |
| 56 Modifies |command_line| in place. |
| 57 """ |
| 58 # Strip -g0 if there's no symbols. |
| 59 have_some_symbols = False |
| 60 for x in command_line: |
| 61 if x.startswith('-g') and x != '-g0': |
| 62 have_some_symbols = True |
| 63 if not have_some_symbols and '-g0' in command_line: |
| 64 command_line.remove('-g0') |
| 65 |
| 66 # Rename -g2 to -g. |
| 67 if '-g2' in command_line: |
| 68 command_line[index('-g2')] = '-g' |
| 69 |
| 70 |
45 def GetFlags(lines): | 71 def GetFlags(lines): |
46 """Turn a list of command lines into a semi-structured dict.""" | 72 """Turn a list of command lines into a semi-structured dict.""" |
47 flags_by_output = {} | 73 flags_by_output = {} |
48 for line in lines: | 74 for line in lines: |
49 # TODO(scottmg): Hacky way of getting only cc for now. | 75 # TODO(scottmg): Hacky way of getting only cc for now. |
50 if 'clang' not in line: | 76 if 'clang' not in line: |
51 continue | 77 continue |
52 | 78 |
53 # TODO(scottmg): Proper escapes. | 79 # TODO(scottmg): Proper escapes. |
54 command_line = line.strip().split()[1:] | 80 command_line = line.strip().split()[1:] |
55 | 81 |
56 output_name = FindAndRemoveArgWithValue(command_line, '-o') | 82 output_name = FindAndRemoveArgWithValue(command_line, '-o') |
57 dep_name = FindAndRemoveArgWithValue(command_line, '-MF') | 83 dep_name = FindAndRemoveArgWithValue(command_line, '-MF') |
58 | 84 |
| 85 NormalizeSymbolArguments(command_line) |
| 86 |
59 command_line = MergeSpacedArgs(command_line, '-Xclang') | 87 command_line = MergeSpacedArgs(command_line, '-Xclang') |
60 | 88 |
61 defines = [x for x in command_line if x.startswith('-D')] | 89 defines = [x for x in command_line if x.startswith('-D')] |
62 include_dirs = [x for x in command_line if x.startswith('-I')] | 90 include_dirs = [x for x in command_line if x.startswith('-I')] |
63 dash_f = [x for x in command_line if x.startswith('-f')] | 91 dash_f = [x for x in command_line if x.startswith('-f')] |
64 warnings = [x for x in command_line if x.startswith('-W')] | 92 warnings = [x for x in command_line if x.startswith('-W')] |
65 cc_file = [x for x in command_line if x.endswith('.cc') or | 93 cc_file = [x for x in command_line if x.endswith('.cc') or |
66 x.endswith('.c') or | 94 x.endswith('.c') or |
67 x.endswith('.cpp')] | 95 x.endswith('.cpp')] |
68 if len(cc_file) != 1: | 96 if len(cc_file) != 1: |
69 print 'Skipping %s' % command_line | 97 print 'Skipping %s' % command_line |
70 continue | 98 continue |
71 assert len(cc_file) == 1 | 99 assert len(cc_file) == 1 |
72 others = [x for x in command_line if x not in defines and \ | 100 others = [x for x in command_line if x not in defines and \ |
73 x not in include_dirs and \ | 101 x not in include_dirs and \ |
74 x not in dash_f and \ | 102 x not in dash_f and \ |
75 x not in warnings and \ | 103 x not in warnings and \ |
76 x not in cc_file] | 104 x not in cc_file] |
| 105 |
| 106 # Filter for libFindBadConstructs.so having a relative path in one and |
| 107 # absolute path in the other. |
| 108 others_filtered = [] |
| 109 for x in others: |
| 110 if x.startswith('-Xclang ') and x.endswith('libFindBadConstructs.so'): |
| 111 others_filtered.append( |
| 112 '-Xclang ' + |
| 113 os.path.join(os.getcwd(), |
| 114 os.path.normpath( |
| 115 os.path.join('out/gn_flags', x.split(' ', 1)[1])))) |
| 116 else: |
| 117 others_filtered.append(x) |
| 118 others = others_filtered |
| 119 |
77 flags_by_output[cc_file[0]] = { | 120 flags_by_output[cc_file[0]] = { |
78 'output': output_name, | 121 'output': output_name, |
79 'depname': dep_name, | 122 'depname': dep_name, |
80 'defines': sorted(defines), | 123 'defines': sorted(defines), |
81 'include_dirs': sorted(include_dirs), # TODO(scottmg): This is wrong. | 124 'include_dirs': sorted(include_dirs), # TODO(scottmg): This is wrong. |
82 'dash_f': sorted(dash_f), | 125 'dash_f': sorted(dash_f), |
83 'warnings': sorted(warnings), | 126 'warnings': sorted(warnings), |
84 'other': sorted(others), | 127 'other': sorted(others), |
85 } | 128 } |
86 return flags_by_output | 129 return flags_by_output |
87 | 130 |
88 | 131 |
89 def CompareLists(gyp, gn, name, dont_care_gyp=None, dont_care_gn=None): | 132 def CompareLists(gyp, gn, name, dont_care_gyp=None, dont_care_gn=None): |
90 """Return a report of any differences between gyp and gn lists, ignoring | 133 """Return a report of any differences between gyp and gn lists, ignoring |
91 anything in |dont_care_{gyp|gn}| respectively.""" | 134 anything in |dont_care_{gyp|gn}| respectively.""" |
| 135 global g_total_differences |
92 if not dont_care_gyp: | 136 if not dont_care_gyp: |
93 dont_care_gyp = [] | 137 dont_care_gyp = [] |
94 if not dont_care_gn: | 138 if not dont_care_gn: |
95 dont_care_gn = [] | 139 dont_care_gn = [] |
96 output = '' | 140 output = '' |
97 if gyp[name] != gn[name]: | 141 if gyp[name] != gn[name]: |
98 output += ' %s differ:\n' % name | |
99 gyp_set = set(gyp[name]) | 142 gyp_set = set(gyp[name]) |
100 gn_set = set(gn[name]) | 143 gn_set = set(gn[name]) |
101 missing_in_gyp = gyp_set - gn_set | 144 missing_in_gyp = gyp_set - gn_set |
102 missing_in_gn = gn_set - gyp_set | 145 missing_in_gn = gn_set - gyp_set |
103 missing_in_gyp -= set(dont_care_gyp) | 146 missing_in_gyp -= set(dont_care_gyp) |
104 missing_in_gn -= set(dont_care_gn) | 147 missing_in_gn -= set(dont_care_gn) |
| 148 if missing_in_gyp or missing_in_gn: |
| 149 output += ' %s differ:\n' % name |
105 if missing_in_gyp: | 150 if missing_in_gyp: |
106 output += ' In gyp, but not in GN:\n %s' % '\n '.join( | 151 output += ' In gyp, but not in GN:\n %s' % '\n '.join( |
107 sorted(missing_in_gyp)) + '\n' | 152 sorted(missing_in_gyp)) + '\n' |
| 153 g_total_differences += len(missing_in_gyp) |
108 if missing_in_gn: | 154 if missing_in_gn: |
109 output += ' In GN, but not in gyp:\n %s' % '\n '.join( | 155 output += ' In GN, but not in gyp:\n %s' % '\n '.join( |
110 sorted(missing_in_gn)) + '\n\n' | 156 sorted(missing_in_gn)) + '\n\n' |
| 157 g_total_differences += len(missing_in_gn) |
111 return output | 158 return output |
112 | 159 |
113 | 160 |
114 def Run(command_line): | 161 def Run(command_line): |
115 """Run |command_line| as a subprocess and return stdout. Raises on error.""" | 162 """Run |command_line| as a subprocess and return stdout. Raises on error.""" |
116 return subprocess.check_output(command_line, shell=True) | 163 return subprocess.check_output(command_line, shell=True) |
117 | 164 |
118 | 165 |
119 def main(): | 166 def main(): |
120 if len(sys.argv) != 2 and len(sys.argv) != 3: | 167 if len(sys.argv) != 2 and len(sys.argv) != 3: |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 '-Wsign-compare', | 206 '-Wsign-compare', |
160 ]) | 207 ]) |
161 differences += CompareLists(gyp_flags, gn_flags, 'other') | 208 differences += CompareLists(gyp_flags, gn_flags, 'other') |
162 if differences: | 209 if differences: |
163 files_with_given_differences.setdefault(differences, []).append(filename) | 210 files_with_given_differences.setdefault(differences, []).append(filename) |
164 | 211 |
165 for diff, files in files_with_given_differences.iteritems(): | 212 for diff, files in files_with_given_differences.iteritems(): |
166 print '\n'.join(sorted(files)) | 213 print '\n'.join(sorted(files)) |
167 print diff | 214 print diff |
168 | 215 |
| 216 print 'Total differences:', g_total_differences |
169 return 1 if files_with_given_differences or different_source_list else 0 | 217 return 1 if files_with_given_differences or different_source_list else 0 |
170 | 218 |
171 | 219 |
172 if __name__ == '__main__': | 220 if __name__ == '__main__': |
173 sys.exit(main()) | 221 sys.exit(main()) |
OLD | NEW |