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

Unified Diff: tools/win/linker_verbose_tracking.py

Issue 2564543003: Script for parsing of verbose linker output (Closed)
Patch Set: Code review tweaks and improvements Created 4 years 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/win/linker_verbose_tracking.py
diff --git a/tools/win/linker_verbose_tracking.py b/tools/win/linker_verbose_tracking.py
new file mode 100644
index 0000000000000000000000000000000000000000..506a86a4443e3e571e2d22b78700466d349574f5
--- /dev/null
+++ b/tools/win/linker_verbose_tracking.py
@@ -0,0 +1,151 @@
+# Copyright (c) 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+This script parses the /verbose output from the VC++ linker and uses it to
+explain why a particular object file is being linked in. It parses records
+like these:
+
+ Found "public: static void * __cdecl SkTLS::Get(void * (__cdecl*)(void)...
+ Referenced in chrome_crash_reporter_client_win.obj
+ Referenced in skia.lib(SkError.obj)
+ Loaded skia.lib(SkTLS.obj)
+
+and then uses the information to answer questions such as "why is SkTLS.obj
+being linked in. In this case it was requested by SkError.obj, and the process
+is then repeated for SkError.obj. It traces the dependency tree back to a file
+that was specified on the command line. Typically that file is part of a
+source_set, and if that source_set is causing unnecessary code and data to be
+pulled in then changing it to a static_library may reduce the binary size. See
+crrev.com/2556603002 for an example of a ~900 KB savings from such a change.
+
+In other cases the source_set to static_library fix does not work because some
+of the symbols are required, while others are pulling in unwanted object files.
+In these cases it can be necessary to see what symbol is causing one object file
+to reference another. Removing or moving the problematic symbol can fix the
+problem. See crrev.com/2559063002 for an example of such a change.
+
+One complication is that there are sometimes multiple source files with the
+same name, such as crc.c, which can make analysis more difficult or
+ambiguous. If this becomes a blocking issue they it may be necessary to
+temporarily rename the source file.
+
+Object file name matching is case sensitive.
+
+Typical output when run on chrome.dll verbose link output is:
+
+>python tools\win\linker_verbose_tracking.py chrome_verbose_02.txt flac_crc
+Database loaded - 11277 xrefs found
+flac_crc.obj pulled in for symbol "_FLAC__crc8" by
+ stream_decoder.obj
+ bitwriter.obj
+
+stream_decoder.obj pulled in for symbol "_FLAC__stream_decoder_new" by
+ stream_encoder.obj
+bitwriter.obj pulled in for symbol "_FLAC__bitwriter_new" by
+ stream_encoder.obj
+
+stream_encoder.obj pulled in for symbol "_FLAC__stream_encoder_new" by
+ Command-line obj file: audio_encoder.obj
+"""
+
+import pdb
+import re
+import sys
+
+def ParseVerbose(input_file):
+ # This matches line like this:
+ # Referenced in skia.lib(SkError.obj)
+ # with the groups()[0] referring to the object file name without the file
+ # extension.
+ obj_match = re.compile('.*\((.*)\.obj\)')
+ # Prefix used for symbols that are referenced:
+ found_prefix = ' Found'
+
+ cross_refs = {}
+ cross_refed_symbols = {}
+
+ references = None
+ for line in open(input_file):
+ if line.startswith(found_prefix):
+ references = []
+ # Grab the symbol name
+ symbol = line[len(found_prefix):].strip()
+ if symbol[0] == '"':
+ # Strip off leading and trailing quotes if present.
+ symbol = symbol[1:-1]
+ continue
+ if type(references) == type([]):
+ sub_line = line.strip()
+ match = obj_match.match(sub_line)
+ # See if the line is part of the list of places where this symbol was
+ # referenced
+ if sub_line.count('Referenced ') > 0:
+ if match:
+ # This indicates a match that is xxx.lib(yyy.obj), so a referencing
+ # .obj file that was itself inside of a library. We discard the
+ # library name.
+ reference = match.groups()[0]
+ else:
+ # This indicates a match that is just a pure .obj file name
+ # I think this means that the .obj file was specified on the linker
+ # command line.
+ reference = ('Command-line obj file: ' +
+ sub_line[len('Referenced in '): -len('.obj')])
+ references.append(reference)
+ elif sub_line.count('Loaded ') > 0:
+ if match:
+ loaded = match.groups()[0]
+ cross_refs[loaded] = references
+ cross_refed_symbols[loaded] = symbol
+ references = None
+ if line.startswith('Finished pass 1'):
+ # Stop now because the remaining 90% of the verbose output is
+ # not of interest. Could probably use /VERBOSE:REF to trim out
+ # boring information.
+ break
+ return cross_refs, cross_refed_symbols
+
+
+def TrackObj(cross_refs, cross_refed_symbols, obj_name):
+ if obj_name.lower().endswith('.obj'):
+ obj_name = obj_name[:-len('.obj')]
+
+ # Keep track of which references we've already followed.
+ tracked = {}
+
+ # Initial set of object files that we are tracking.
+ targets = [obj_name]
+ printed = False
+ for i in range(100):
+ new_targets = {}
+ for target in targets:
+ if not target in tracked:
+ tracked[target] = True
+ if target in cross_refs.keys():
+ symbol = cross_refed_symbols[target]
+ printed = True
+ print '%s.obj pulled in for symbol "%s" by' % (target, symbol)
+ for ref in cross_refs[target]:
+ print '\t%s.obj' % ref
+ new_targets[ref] = True
+ if len(new_targets) == 0:
+ break
+ print
+ targets = new_targets.keys()
+ if not printed:
+ print 'No references to %s.obj found.' % obj_name
+
+
+def main():
+ if len(sys.argv) < 3:
+ print r'Usage: %s <verbose_output_file> <objfile>' % sys.argv[0]
+ print r'Sample: %s chrome_dll_verbose.txt SkTLS' % sys.argv[0]
+ return 0
+ cross_refs, cross_refed_symbols = ParseVerbose(sys.argv[1])
+ print 'Database loaded - %d xrefs found' % len(cross_refs)
+ TrackObj(cross_refs, cross_refed_symbols, sys.argv[2])
+
+if __name__ == '__main__':
+ sys.exit(main())
« 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