Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(100)

Side by Side Diff: tools/win/linker_verbose_tracking.py

Issue 2863843003: Improve linker_verbose_tracking.py (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2016 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """ 5 """
6 This script parses the /verbose output from the VC++ linker and uses it to 6 This script parses the /verbose output from the VC++ linker and uses it to
7 explain why a particular object file is being linked in. It parses records 7 explain why a particular object file is being linked in. It parses records
8 like these: 8 like these:
9 9
10 Found "public: static void * __cdecl SkTLS::Get(void * (__cdecl*)(void)... 10 Found "public: static void * __cdecl SkTLS::Get(void * (__cdecl*)(void)...
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 43
44 stream_decoder.obj pulled in for symbol "_FLAC__stream_decoder_new" by 44 stream_decoder.obj pulled in for symbol "_FLAC__stream_decoder_new" by
45 stream_encoder.obj 45 stream_encoder.obj
46 bitwriter.obj pulled in for symbol "_FLAC__bitwriter_new" by 46 bitwriter.obj pulled in for symbol "_FLAC__bitwriter_new" by
47 stream_encoder.obj 47 stream_encoder.obj
48 48
49 stream_encoder.obj pulled in for symbol "_FLAC__stream_encoder_new" by 49 stream_encoder.obj pulled in for symbol "_FLAC__stream_encoder_new" by
50 Command-line obj file: audio_encoder.obj 50 Command-line obj file: audio_encoder.obj
51 """ 51 """
52 52
53 import io
53 import pdb 54 import pdb
54 import re 55 import re
55 import sys 56 import sys
56 57
57 def ParseVerbose(input_file): 58 def ParseVerbose(input_file):
58 # This matches line like this: 59 # This matches line like this:
59 # Referenced in skia.lib(SkError.obj) 60 # Referenced in skia.lib(SkError.obj)
60 # with the groups()[0] referring to the object file name without the file 61 # with the groups()[0] referring to the object file name without the file
61 # extension. 62 # extension.
62 obj_match = re.compile('.*\((.*)\.obj\)') 63 obj_match = re.compile('.*\((.*)\.obj\)')
63 # Prefix used for symbols that are referenced: 64 # Prefix used for symbols that are referenced:
64 found_prefix = ' Found' 65 found_prefix = ' Found'
65 66
66 cross_refs = {} 67 cross_refs = {}
67 cross_refed_symbols = {} 68 cross_refed_symbols = {}
68 69
69 references = None 70 references = None
70 for line in open(input_file): 71 # When you redirect the linker output to a file from a command prompt the
71 if line.startswith(found_prefix): 72 # result will be a utf-8 (or ASCII?) output file. However if you do the same
72 references = [] 73 # thing from PowerShell you get a utf-16 file. So, we need to handle both
73 # Grab the symbol name 74 # options. Only the first BOM option (\xff\xfe) has been tested, but it seems
74 symbol = line[len(found_prefix):].strip() 75 # appropriate to handle the other as well.
75 if symbol[0] == '"': 76 file_encoding = 'utf-8'
76 # Strip off leading and trailing quotes if present. 77 with open(input_file) as file_handle:
77 symbol = symbol[1:-1] 78 header = file_handle.read(2)
78 continue 79 if header == '\xff\xfe' or header == '\xfe\xff':
79 if type(references) == type([]): 80 file_encoding = 'utf-16'
80 sub_line = line.strip() 81 with io.open(input_file, encoding=file_encoding) as file_handle:
81 match = obj_match.match(sub_line) 82 for line in file_handle:
82 # See if the line is part of the list of places where this symbol was 83 if line.startswith(found_prefix):
83 # referenced 84 references = []
84 if sub_line.count('Referenced ') > 0: 85 # Grab the symbol name
85 if match: 86 symbol = line[len(found_prefix):].strip()
86 # This indicates a match that is xxx.lib(yyy.obj), so a referencing 87 if symbol[0] == '"':
87 # .obj file that was itself inside of a library. We discard the 88 # Strip off leading and trailing quotes if present.
88 # library name. 89 symbol = symbol[1:-1]
89 reference = match.groups()[0] 90 continue
90 else: 91 if type(references) == type([]):
91 # This indicates a match that is just a pure .obj file name 92 sub_line = line.strip()
92 # I think this means that the .obj file was specified on the linker 93 match = obj_match.match(sub_line)
93 # command line. 94 # See if the line is part of the list of places where this symbol was
94 reference = ('Command-line obj file: ' + 95 # referenced
95 sub_line[len('Referenced in '): -len('.obj')]) 96 if sub_line.count('Referenced ') > 0:
96 references.append(reference) 97 if match:
97 elif sub_line.count('Loaded ') > 0: 98 # This indicates a match that is xxx.lib(yyy.obj), so a referencing
98 if match: 99 # .obj file that was itself inside of a library. We discard the
99 loaded = match.groups()[0] 100 # library name.
100 cross_refs[loaded] = references 101 reference = match.groups()[0]
101 cross_refed_symbols[loaded] = symbol 102 else:
102 references = None 103 # This indicates a match that is just a pure .obj file name
103 if line.startswith('Finished pass 1'): 104 # I think this means that the .obj file was specified on the linker
104 # Stop now because the remaining 90% of the verbose output is 105 # command line.
105 # not of interest. Could probably use /VERBOSE:REF to trim out 106 reference = ('Command-line obj file: ' +
106 # boring information. 107 sub_line[len('Referenced in '): -len('.obj')])
107 break 108 references.append(reference)
109 elif sub_line.count('Loaded ') > 0:
110 if match:
111 loaded = match.groups()[0]
112 cross_refs[loaded] = references
113 cross_refed_symbols[loaded] = symbol
114 references = None
115 if line.startswith('Finished pass 1'):
116 # Stop now because the remaining 90% of the verbose output is
117 # not of interest. Could probably use /VERBOSE:REF to trim out
118 # boring information.
119 break
108 return cross_refs, cross_refed_symbols 120 return cross_refs, cross_refed_symbols
109 121
110 122
111 def TrackObj(cross_refs, cross_refed_symbols, obj_name): 123 def TrackObj(cross_refs, cross_refed_symbols, obj_name):
112 if obj_name.lower().endswith('.obj'): 124 if obj_name.lower().endswith('.obj'):
113 obj_name = obj_name[:-len('.obj')] 125 obj_name = obj_name[:-len('.obj')]
114 126
115 # Keep track of which references we've already followed. 127 # Keep track of which references we've already followed.
116 tracked = {} 128 tracked = {}
117 129
(...skipping 10 matching lines...) Expand all
128 printed = True 140 printed = True
129 print '%s.obj pulled in for symbol "%s" by' % (target, symbol) 141 print '%s.obj pulled in for symbol "%s" by' % (target, symbol)
130 for ref in cross_refs[target]: 142 for ref in cross_refs[target]:
131 print '\t%s.obj' % ref 143 print '\t%s.obj' % ref
132 new_targets[ref] = True 144 new_targets[ref] = True
133 if len(new_targets) == 0: 145 if len(new_targets) == 0:
134 break 146 break
135 print 147 print
136 targets = new_targets.keys() 148 targets = new_targets.keys()
137 if not printed: 149 if not printed:
138 print 'No references to %s.obj found.' % obj_name 150 print ('No references to %s.obj found. Directly specified in sources or a '
151 'source_set?' % obj_name)
139 152
140 153
141 def main(): 154 def main():
142 if len(sys.argv) < 3: 155 if len(sys.argv) < 3:
143 print r'Usage: %s <verbose_output_file> <objfile>' % sys.argv[0] 156 print r'Usage: %s <verbose_output_file> <objfile>' % sys.argv[0]
144 print r'Sample: %s chrome_dll_verbose.txt SkTLS' % sys.argv[0] 157 print r'Sample: %s chrome_dll_verbose.txt SkTLS' % sys.argv[0]
145 return 0 158 return 0
146 cross_refs, cross_refed_symbols = ParseVerbose(sys.argv[1]) 159 cross_refs, cross_refed_symbols = ParseVerbose(sys.argv[1])
147 print 'Database loaded - %d xrefs found' % len(cross_refs) 160 print 'Database loaded - %d xrefs found' % len(cross_refs)
161 if not len(cross_refs):
162 print 'No data found to analyze. Exiting'
163 return 0
148 TrackObj(cross_refs, cross_refed_symbols, sys.argv[2]) 164 TrackObj(cross_refs, cross_refed_symbols, sys.argv[2])
149 165
150 if __name__ == '__main__': 166 if __name__ == '__main__':
151 sys.exit(main()) 167 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698