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

Unified Diff: tools/win/split_link/split_link.py

Issue 15310002: Identify data exports during split_link (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « build/split_link_partition.py ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/win/split_link/split_link.py
diff --git a/tools/win/split_link/split_link.py b/tools/win/split_link/split_link.py
index 2b035c5418b2a70389ee903fb30820d3a1c4d469..72b6c47290d77c88f004f0db687a4f28229b9e96 100644
--- a/tools/win/split_link/split_link.py
+++ b/tools/win/split_link/split_link.py
@@ -13,6 +13,7 @@ import os
import re
import subprocess
import sys
+import tempfile
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -179,6 +180,50 @@ def RunLinker(flags, index, inputs, phase):
return stdout, popen.returncode, output_name
+def GetLibObjList(lib):
+ """Gets the list of object files contained in a .lib."""
+ link_exe = GetOriginalLinkerPath()
+ popen = subprocess.Popen(
+ [link_exe, '/lib', '/nologo', '/list', lib], stdout=subprocess.PIPE)
+ stdout, _ = popen.communicate()
+ return stdout.splitlines()
+
+
+def ExtractObjFromLib(lib, obj):
+ """Extracts a .obj file contained in a .lib file. Returns the absolute path
+ a temp file."""
+ link_exe = GetOriginalLinkerPath()
+ temp = tempfile.NamedTemporaryFile(
+ prefix='split_link_', suffix='.obj', delete=False)
+ temp.close()
+ subprocess.check_call([
+ link_exe, '/lib', '/nologo', '/extract:' + obj, lib, '/out:' + temp.name])
+ return temp.name
+
+
+def Unmangle(export):
+ "Returns the human-presentable name of a mangled symbol."""
+ # Use dbghelp.dll to demangle the name.
+ # TODO(scottmg): Perhaps a simple cache? Seems pretty fast though.
+ UnDecorateSymbolName = ctypes.windll.dbghelp.UnDecorateSymbolName
+ buffer_size = 2048
+ output_string = ctypes.create_string_buffer(buffer_size)
+ if not UnDecorateSymbolName(
+ export, ctypes.byref(output_string), buffer_size, 0):
+ raise ctypes.WinError()
+ return output_string.value
+
+
+def IsDataDefinition(export):
+ """Determines if a given name is data rather than a function. Always returns
+ False for C-style (as opposed to C++-style names)."""
+ if export[0] != '?':
+ return False
+
+ # If it contains a '(' we assume it's a function.
+ return '(' not in Unmangle(export)
+
+
def GenerateDefFiles(unresolved_by_part):
"""Given a list of unresolved externals, generates a .def file that will
cause all those symbols to be exported."""
@@ -192,7 +237,10 @@ def GenerateDefFiles(unresolved_by_part):
for j, part in enumerate(unresolved_by_part):
if i == j:
continue
- print >> f, '\n'.join(' ' + export for export in part)
+ is_data = [' DATA' if IsDataDefinition(export) else ''
+ for export in part]
+ print >> f, '\n'.join(' ' + export + data
+ for export, data in zip(part, is_data))
deffiles.append(deffile)
return deffiles
@@ -238,6 +286,40 @@ def AttemptLink(flags, inputs_by_part, unresolved_by_part, deffiles,
return all_succeeded, dlls, combined_externals
+def ExtractSubObjsTargetedAtAll(
+ inputs,
+ num_parts,
+ description_parts,
+ description_all,
+ description_all_from_libs):
+ """For (lib, obj) tuples in the all_from_libs section, extract the obj out of
+ the lib and added it to inputs. Returns a list of lists for which part the
+ extracted obj belongs in (which is whichever the .lib isn't in)."""
+ by_parts = [[] for _ in range(num_parts)]
+ for lib_spec, obj_spec in description_all_from_libs:
+ for input_file in inputs:
+ if re.search(lib_spec, input_file):
+ objs = GetLibObjList(input_file)
+ match_count = 0
+ for obj in objs:
+ if re.search(obj_spec, obj, re.I):
+ extracted_obj = ExtractObjFromLib(input_file, obj)
+ #Log('extracted %s (%s %s)' % (extracted_obj, input_file, obj))
+ i = PartFor(input_file, description_parts, description_all)
+ if i == -1:
+ raise SystemExit(
+ '%s is already in all parts, but matched '
+ '%s in all_from_libs' % (input_file, obj))
+ # See note in main().
+ assert num_parts == 2, "Can't handle > 2 dlls currently"
+ by_parts[1 - i].append(obj)
+ match_count += 1
+ if match_count == 0:
+ raise SystemExit(
+ '%s, %s matched a lib, but no objs' % (lib_spec, obj_spec))
+ return by_parts
+
+
def main():
flags, inputs = GetFlagsAndInputs(sys.argv[1:])
partition_file = os.path.normpath(
@@ -246,13 +328,20 @@ def main():
description = eval(partition.read())
inputs_by_part = []
description_parts = description['parts']
- # We currently assume that if a symbols isn't in dll 0, then it's in dll 1
+ # We currently assume that if a symbol isn't in dll 0, then it's in dll 1
# when generating def files. Otherwise, we'd need to do more complex things
# to figure out where each symbol actually is to assign it to the correct
# .def file.
num_parts = len(description_parts)
assert num_parts == 2, "Can't handle > 2 dlls currently"
description_parts.reverse()
+ objs_from_libs = ExtractSubObjsTargetedAtAll(
+ inputs,
+ num_parts,
+ description_parts,
+ description['all'],
+ description['all_from_libs'])
+ objs_from_libs.reverse()
inputs_by_part = [[] for _ in range(num_parts)]
for input_file in inputs:
i = PartFor(input_file, description_parts, description['all'])
@@ -263,21 +352,40 @@ def main():
inputs_by_part[i].append(input_file)
inputs_by_part.reverse()
+ # Put the subobjs on to the main list.
+ for i, part in enumerate(objs_from_libs):
+ Log('%d sub .objs added to part %d' % (len(part), i))
+ inputs_by_part[i].extend(part)
+
unresolved_by_part = [[] for _ in range(num_parts)]
import_libs = [None] * num_parts
deffiles = [None] * num_parts
+ data_exports = 0
for i in range(5):
Log('--- starting pass %d' % i)
ok, dlls, unresolved_by_part = AttemptLink(
flags, inputs_by_part, unresolved_by_part, deffiles, import_libs)
if ok:
break
+ data_exports = 0
+ for i, part in enumerate(unresolved_by_part):
+ for export in part:
+ if IsDataDefinition(export):
+ print 'part %d contains data export: %s (aka %s)' % (
+ i, Unmangle(export), export)
+ data_exports += 1
deffiles = GenerateDefFiles(unresolved_by_part)
import_libs = BuildImportLibs(flags, inputs_by_part, deffiles)
else:
return 1
+ if data_exports:
+ print 'Data exports found, see report above.'
+ print('These cannot be exported, and must be either duplicated to the '
+ 'target DLL, or wrapped in a function.')
+ return 1
+
mt_exe = GetMtPath()
for i, dll in enumerate(dlls):
Log('embedding manifest in %s' % dll)
« no previous file with comments | « build/split_link_partition.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698