split_link.py revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
1a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
2a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
3a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)# found in the LICENSE file.
4a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
5a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)"""Takes the same arguments as Windows link.exe, and a definition of libraries
6a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)to split into subcomponents. Does multiple passes of link.exe invocation to
7a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)determine exports between parts and generates .def and import libraries to
8a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)cause symbols to be available to other parts."""
9a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
10a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)import _winreg
11a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)import ctypes
12a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)import os
13a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)import re
14a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)import subprocess
15a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)import sys
16a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
17a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
18a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)BASE_DIR = os.path.dirname(os.path.abspath(__file__))
19a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
20a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
21a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def Log(message):
22a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  print 'split_link:', message
23a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
24a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
25a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def GetFlagsAndInputs(argv):
26a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Parses the command line intended for link.exe and return the flags and
27a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  input files."""
28a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  rsp_expanded = []
29a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for arg in argv:
30a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if arg[0] == '@':
31a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      with open(arg[1:]) as rsp:
32a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        rsp_expanded.extend(rsp.read().splitlines())
33a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    else:
34a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      rsp_expanded.append(arg)
35a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
36a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Use CommandLineToArgvW so we match link.exe parsing.
37a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  try:
38a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    size = ctypes.c_int()
39a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    ptr = ctypes.windll.shell32.CommandLineToArgvW(
40a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        ctypes.create_unicode_buffer(' '.join(rsp_expanded)),
41a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        ctypes.byref(size))
42a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    ref = ctypes.c_wchar_p * size.value
43a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    raw = ref.from_address(ptr)
44a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    args = [arg for arg in raw]
45a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  finally:
46a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    ctypes.windll.kernel32.LocalFree(ptr)
47a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
48a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  inputs = []
49a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  flags = []
50a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for arg in args:
51a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    lower_arg = arg.lower()
52a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # We'll be replacing this ourselves.
53a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if lower_arg.startswith('/out:'):
54a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      continue
55a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (not lower_arg.startswith('/') and
56a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        lower_arg.endswith(('.obj', '.lib', '.res'))):
57a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      inputs.append(arg)
58a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    else:
59a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      flags.append(arg)
60a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
61a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return flags, inputs
62a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
63a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
64a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def GetOriginalLinkerPath():
65a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  try:
66a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    val = _winreg.QueryValue(_winreg.HKEY_CURRENT_USER,
67a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                             'Software\\Chromium\\split_link_installed')
68a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if os.path.exists(val):
69a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return val
70a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  except WindowsError:
71a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    pass
72a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
73a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  raise SystemExit("Couldn't read linker location from registry")
74a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
75a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
76a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def PartFor(input_file, description_parts, description_all):
77a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Determines which part a given link input should be put into (or all)."""
78a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Check if it should go in all parts.
79a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  input_file = input_file.lower()
80a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if any(re.search(spec, input_file) for spec in description_all):
81a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return -1
82a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Or pick which particular one it belongs in.
83a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for i, spec_list in enumerate(description_parts):
84a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if any(re.search(spec, input_file) for spec in spec_list):
85a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return i
86a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  raise ValueError("couldn't find location for %s" % input_file)
87a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
88a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
89a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def ParseOutExternals(output):
90a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Given the stdout of link.exe, parses the error messages to retrieve all
91a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  symbols that are unresolved."""
92a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  result = set()
93a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Styles of messages for unresolved externals, and a boolean to indicate
94a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # whether the error message emits the symbols with or without a leading
95a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # underscore.
96a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  unresolved_regexes = [
97a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    (re.compile(r' : error LNK2019: unresolved external symbol ".*" \((.*)\)'
98a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                r' referenced in function'),
99a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)     False),
100a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    (re.compile(r' : error LNK2001: unresolved external symbol ".*" \((.*)\)$'),
101a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)     False),
102a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    (re.compile(r' : error LNK2019: unresolved external symbol (.*)'
103a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                r' referenced in function '),
104a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)     True),
105a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    (re.compile(r' : error LNK2001: unresolved external symbol (.*)$'),
106a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)     True),
107a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ]
108a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for line in output.splitlines():
109a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    line = line.strip()
110a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    for regex, strip_leading_underscore in unresolved_regexes:
111a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      mo = regex.search(line)
112a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if mo:
113a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        if strip_leading_underscore:
114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          result.add(mo.group(1)[1:])
115a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        else:
116a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          result.add(mo.group(1))
117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        break
118a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
119a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  mo = re.search(r'fatal error LNK1120: (\d+) unresolved externals', output)
120a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Make sure we have the same number that the linker thinks we have.
121a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  assert mo or not result
122a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if len(result) != int(mo.group(1)):
123a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    print output
124a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    print 'Expecting %d, got %d' % (int(mo.group(1)), len(result))
125a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  assert len(result) == int(mo.group(1))
126a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return sorted(result)
127a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
128a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
129a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def AsCommandLineArgs(items):
130a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Intended for output to a response file. Quotes all arguments."""
131a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return '\n'.join('"' + x + '"' for x in items)
132a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
133a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
134a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def OutputNameForIndex(index):
135a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Gets the final output DLL name, given a zero-based index."""
136a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if index == 0:
137a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return "chrome.dll"
138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  else:
139a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return 'chrome%d.dll' % index
140a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
141a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
142a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def RunLinker(flags, index, inputs, phase):
143a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Invokes the linker and returns the stdout, returncode and target name."""
144a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  rspfile = 'part%d_%s.rsp' % (index, phase)
145a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  with open(rspfile, 'w') as f:
146a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    print >> f, AsCommandLineArgs(inputs)
147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    print >> f, AsCommandLineArgs(flags)
148a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    output_name = OutputNameForIndex(index)
149a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    print >> f, '/ENTRY:ChromeEmptyEntry@12'
150a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    print >> f, '/OUT:' + output_name
151a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Log('[[[\n' + open(rspfile).read() + '\n]]]')
152a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  link_exe = GetOriginalLinkerPath()
153a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  popen = subprocess.Popen([link_exe, '@' + rspfile], stdout=subprocess.PIPE)
154a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  stdout, _ = popen.communicate()
155a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return stdout, popen.returncode, output_name
156a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
157a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
158a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def GenerateDefFiles(unresolved_by_part):
159a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Given a list of unresolved externals, generates a .def file that will
160a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  cause all those symbols to be exported."""
161a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  deffiles = []
162a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  Log('generating .def files')
163a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for i, part in enumerate(unresolved_by_part):
164a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    deffile = 'part%d.def' % i
165a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    with open(deffile, 'w') as f:
166a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      print >> f, 'LIBRARY %s' % OutputNameForIndex(i)
167a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      print >> f, 'EXPORTS'
168a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      for j, part in enumerate(unresolved_by_part):
169a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        if i == j:
170a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          continue
171a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        print >> f, '\n'.join('  ' + export for export in part)
172a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    deffiles.append(deffile)
173a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return deffiles
174a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
175a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
176a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def BuildImportLibs(flags, inputs_by_part, deffiles):
177a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Runs the linker to generate an import library."""
178a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  import_libs = []
179a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  Log('building import libs')
180a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for i, (inputs, deffile) in enumerate(zip(inputs_by_part, deffiles)):
181a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    libfile = 'part%d.lib' % i
182a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    flags_with_implib_and_deffile = flags + ['/IMPLIB:%s' % libfile,
183a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                                             '/DEF:%s' % deffile]
184a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    RunLinker(flags_with_implib_and_deffile, i, inputs, 'implib')
185a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    import_libs.append(libfile)
186a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return import_libs
187a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
188a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
189a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def AttemptLink(flags, inputs_by_part, unresolved_by_part, deffiles,
190a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                import_libs):
191a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Tries to run the linker for all parts using the current round of
192a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  generated import libs and .def files. If the link fails, updates the
193a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  unresolved externals list per part."""
194a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  dlls = []
195a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  all_succeeded = True
196a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  new_externals = []
197a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  Log('unresolveds now: %r' % [len(part) for part in unresolved_by_part])
198a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for i, (inputs, deffile) in enumerate(zip(inputs_by_part, deffiles)):
199a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    Log('running link, part %d' % i)
200a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    others_implibs = import_libs[:]
201a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    others_implibs.pop(i)
202a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    inputs_with_implib = inputs + filter(lambda x: x, others_implibs)
203a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if deffile:
204a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      flags = flags + ['/DEF:%s' % deffile, '/LTCG']
205a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    stdout, rc, output = RunLinker(flags, i, inputs_with_implib, 'final')
206a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if rc != 0:
207a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      all_succeeded = False
208a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      new_externals.append(ParseOutExternals(stdout))
209a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    else:
210a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      new_externals.append([])
211a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      dlls.append(output)
212a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  combined_externals = [sorted(set(prev) | set(new))
213a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                        for prev, new in zip(unresolved_by_part, new_externals)]
214a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return all_succeeded, dlls, combined_externals
215a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
216a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
217a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def main():
218a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  flags, inputs = GetFlagsAndInputs(sys.argv[1:])
219a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  partition_file = os.path.normpath(
220a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      os.path.join(BASE_DIR, '../../../build/split_link_partition.py'))
221a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  with open(partition_file) as partition:
222a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    description = eval(partition.read())
223a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  inputs_by_part = []
224a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  description_parts = description['parts']
225a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # We currently assume that if a symbols isn't in dll 0, then it's in dll 1
226a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # when generating def files. Otherwise, we'd need to do more complex things
227a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # to figure out where each symbol actually is to assign it to the correct
228a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # .def file.
229a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  num_parts = len(description_parts)
230a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  assert num_parts == 2, "Can't handle > 2 dlls currently"
231a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  description_parts.reverse()
232a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  inputs_by_part = [[] for _ in range(num_parts)]
233a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for input_file in inputs:
234a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    i = PartFor(input_file, description_parts, description['all'])
235a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if i == -1:
236a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      for part in inputs_by_part:
237a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        part.append(input_file)
238a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    else:
239a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      inputs_by_part[i].append(input_file)
240a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  inputs_by_part.reverse()
241a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
242a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  unresolved_by_part = [[] for _ in range(num_parts)]
243a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  import_libs = [None] * num_parts
244a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  deffiles = [None] * num_parts
245a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
246a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for i in range(5):
247a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    Log('--- starting pass %d' % i)
248a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    ok, dlls, unresolved_by_part = AttemptLink(
249a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        flags, inputs_by_part, unresolved_by_part, deffiles, import_libs)
250a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if ok:
251a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      break
252a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    deffiles = GenerateDefFiles(unresolved_by_part)
253a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    import_libs = BuildImportLibs(flags, inputs_by_part, deffiles)
254a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  else:
255a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return 1
256a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  Log('built %r' % dlls)
257a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
258a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return 0
259a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
260a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
261a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)if __name__ == '__main__':
262a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  sys.exit(main())
263