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
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import shutil
15a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)import subprocess
16a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)import sys
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import tempfile
18a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
19a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
20a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)BASE_DIR = os.path.dirname(os.path.abspath(__file__))
21a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
22a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)# This can be set to ignore data exports. The resulting DLLs will probably not
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)# run, but at least they can be generated. The log of data exports will still
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)# be output.
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)IGNORE_DATA = 0
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
29a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def Log(message):
30a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  print 'split_link:', message
31a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
32a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
33a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def GetFlagsAndInputs(argv):
34a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Parses the command line intended for link.exe and return the flags and
35a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  input files."""
36a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  rsp_expanded = []
37a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for arg in argv:
38a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if arg[0] == '@':
39a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      with open(arg[1:]) as rsp:
40a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        rsp_expanded.extend(rsp.read().splitlines())
41a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    else:
42a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      rsp_expanded.append(arg)
43a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
44a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Use CommandLineToArgvW so we match link.exe parsing.
45a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  try:
46a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    size = ctypes.c_int()
47a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    ptr = ctypes.windll.shell32.CommandLineToArgvW(
48a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        ctypes.create_unicode_buffer(' '.join(rsp_expanded)),
49a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        ctypes.byref(size))
50a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    ref = ctypes.c_wchar_p * size.value
51a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    raw = ref.from_address(ptr)
52a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    args = [arg for arg in raw]
53a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  finally:
54a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    ctypes.windll.kernel32.LocalFree(ptr)
55a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
56a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  inputs = []
57a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  flags = []
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  intermediate_manifest = ''
59a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for arg in args:
60a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    lower_arg = arg.lower()
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    # We'll be replacing these ourselves.
62a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if lower_arg.startswith('/out:'):
63a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      continue
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if lower_arg.startswith('/manifestfile:'):
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      intermediate_manifest = arg[arg.index(':')+1:]
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if lower_arg.startswith('/pdb:'):
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue
69a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (not lower_arg.startswith('/') and
70a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        lower_arg.endswith(('.obj', '.lib', '.res'))):
71a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      inputs.append(arg)
72a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    else:
73a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      flags.append(arg)
74a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return flags, inputs, intermediate_manifest
76a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
77a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def GetRegistryValue(subkey):
79a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  try:
80a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    val = _winreg.QueryValue(_winreg.HKEY_CURRENT_USER,
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                             'Software\\Chromium\\' + subkey)
82a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if os.path.exists(val):
83a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return val
84a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  except WindowsError:
85a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    pass
86a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  raise SystemExit("Couldn't read from registry")
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def GetOriginalLinkerPath():
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return GetRegistryValue('split_link_installed')
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def GetMtPath():
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return GetRegistryValue('split_link_mt_path')
96a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
97a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
98a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def PartFor(input_file, description_parts, description_all):
99a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Determines which part a given link input should be put into (or all)."""
100a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Check if it should go in all parts.
101a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  input_file = input_file.lower()
102a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if any(re.search(spec, input_file) for spec in description_all):
103a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return -1
104a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Or pick which particular one it belongs in.
105a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for i, spec_list in enumerate(description_parts):
106a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if any(re.search(spec, input_file) for spec in spec_list):
107a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return i
108a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  raise ValueError("couldn't find location for %s" % input_file)
109a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
110a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
111a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def ParseOutExternals(output):
112a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Given the stdout of link.exe, parses the error messages to retrieve all
113a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  symbols that are unresolved."""
114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  result = set()
115a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Styles of messages for unresolved externals, and a boolean to indicate
116a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # whether the error message emits the symbols with or without a leading
117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # underscore.
118a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  unresolved_regexes = [
119a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    (re.compile(r' : error LNK2019: unresolved external symbol ".*" \((.*)\)'
120a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                r' referenced in function'),
121a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)     False),
122a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    (re.compile(r' : error LNK2001: unresolved external symbol ".*" \((.*)\)$'),
123a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)     False),
124a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    (re.compile(r' : error LNK2019: unresolved external symbol (.*)'
125a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                r' referenced in function '),
126a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)     True),
127a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    (re.compile(r' : error LNK2001: unresolved external symbol (.*)$'),
128a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)     True),
129a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ]
130a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for line in output.splitlines():
131a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    line = line.strip()
132a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    for regex, strip_leading_underscore in unresolved_regexes:
133a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      mo = regex.search(line)
134a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if mo:
135a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        if strip_leading_underscore:
136a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          result.add(mo.group(1)[1:])
137a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        else:
138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          result.add(mo.group(1))
139a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        break
140a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
141a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  mo = re.search(r'fatal error LNK1120: (\d+) unresolved externals', output)
142a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Make sure we have the same number that the linker thinks we have.
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if mo is None and result:
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    raise SystemExit(output)
145a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if len(result) != int(mo.group(1)):
146a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    print output
147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    print 'Expecting %d, got %d' % (int(mo.group(1)), len(result))
148a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  assert len(result) == int(mo.group(1))
149a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return sorted(result)
150a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
151a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
152a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def AsCommandLineArgs(items):
153a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Intended for output to a response file. Quotes all arguments."""
154a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return '\n'.join('"' + x + '"' for x in items)
155a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
156a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
157a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def OutputNameForIndex(index):
158a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Gets the final output DLL name, given a zero-based index."""
159a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if index == 0:
160a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return "chrome.dll"
161a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  else:
162a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return 'chrome%d.dll' % index
163a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
164a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def ManifestNameForIndex(index):
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return OutputNameForIndex(index) + '.intermediate.manifest'
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def PdbNameForIndex(index):
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return OutputNameForIndex(index) + '.pdb'
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def RunLinker(flags, index, inputs, phase, intermediate_manifest):
174a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Invokes the linker and returns the stdout, returncode and target name."""
175a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  rspfile = 'part%d_%s.rsp' % (index, phase)
176a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  with open(rspfile, 'w') as f:
177a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    print >> f, AsCommandLineArgs(inputs)
178a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    print >> f, AsCommandLineArgs(flags)
179a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    output_name = OutputNameForIndex(index)
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    manifest_name = ManifestNameForIndex(index)
181a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    print >> f, '/ENTRY:ChromeEmptyEntry@12'
182a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    print >> f, '/OUT:' + output_name
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    print >> f, '/MANIFESTFILE:' + manifest_name
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    print >> f, '/PDB:' + PdbNameForIndex(index)
185a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Log('[[[\n' + open(rspfile).read() + '\n]]]')
186a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  link_exe = GetOriginalLinkerPath()
187a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  popen = subprocess.Popen([link_exe, '@' + rspfile], stdout=subprocess.PIPE)
188a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  stdout, _ = popen.communicate()
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if index == 0 and popen.returncode == 0 and intermediate_manifest:
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    # Hack for ninja build. After the linker runs, it does some manifest
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    # things and expects there to be a file in this location. We just put it
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    # there so it's happy. This is a no-op.
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if os.path.isdir(os.path.dirname(intermediate_manifest)):
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      shutil.copyfile(manifest_name, intermediate_manifest)
195a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return stdout, popen.returncode, output_name
196a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
197a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def GetLibObjList(lib):
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  """Gets the list of object files contained in a .lib."""
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  link_exe = GetOriginalLinkerPath()
20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  popen = subprocess.Popen(
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      [link_exe, '/lib', '/nologo', '/list', lib], stdout=subprocess.PIPE)
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  stdout, _ = popen.communicate()
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return stdout.splitlines()
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def ExtractObjFromLib(lib, obj):
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  """Extracts a .obj file contained in a .lib file. Returns the absolute path
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  a temp file."""
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  link_exe = GetOriginalLinkerPath()
21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  temp = tempfile.NamedTemporaryFile(
21290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      prefix='split_link_', suffix='.obj', delete=False)
21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  temp.close()
21490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  subprocess.check_call([
21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    link_exe, '/lib', '/nologo', '/extract:' + obj, lib, '/out:' + temp.name])
21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return temp.name
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def Unmangle(export):
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  "Returns the human-presentable name of a mangled symbol."""
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  # Use dbghelp.dll to demangle the name.
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  # TODO(scottmg): Perhaps a simple cache? Seems pretty fast though.
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  UnDecorateSymbolName = ctypes.windll.dbghelp.UnDecorateSymbolName
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  buffer_size = 2048
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  output_string = ctypes.create_string_buffer(buffer_size)
22690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if not UnDecorateSymbolName(
22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      export, ctypes.byref(output_string), buffer_size, 0):
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    raise ctypes.WinError()
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return output_string.value
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def IsDataDefinition(export):
23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  """Determines if a given name is data rather than a function. Always returns
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  False for C-style (as opposed to C++-style names)."""
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if export[0] != '?':
23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return False
23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  # If it contains a '(' we assume it's a function.
23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return '(' not in Unmangle(export)
24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
242a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def GenerateDefFiles(unresolved_by_part):
243a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Given a list of unresolved externals, generates a .def file that will
244a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  cause all those symbols to be exported."""
245a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  deffiles = []
246a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  Log('generating .def files')
247a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for i, part in enumerate(unresolved_by_part):
248a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    deffile = 'part%d.def' % i
249a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    with open(deffile, 'w') as f:
250a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      print >> f, 'LIBRARY %s' % OutputNameForIndex(i)
251a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      print >> f, 'EXPORTS'
252a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      for j, part in enumerate(unresolved_by_part):
253a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        if i == j:
254a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          continue
25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        is_data = \
25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            [' DATA' if IsDataDefinition(export) and not IGNORE_DATA else ''
25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)             for export in part]
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        print >> f, '\n'.join('  ' + export + data
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                              for export, data in zip(part, is_data))
260a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    deffiles.append(deffile)
261a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return deffiles
262a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
263a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
264a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def BuildImportLibs(flags, inputs_by_part, deffiles):
265a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Runs the linker to generate an import library."""
266a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  import_libs = []
267a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  Log('building import libs')
268a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for i, (inputs, deffile) in enumerate(zip(inputs_by_part, deffiles)):
269a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    libfile = 'part%d.lib' % i
270a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    flags_with_implib_and_deffile = flags + ['/IMPLIB:%s' % libfile,
271a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                                             '/DEF:%s' % deffile]
27290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    RunLinker(flags_with_implib_and_deffile, i, inputs, 'implib', None)
273a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    import_libs.append(libfile)
274a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return import_libs
275a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
276a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
277a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def AttemptLink(flags, inputs_by_part, unresolved_by_part, deffiles,
27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                import_libs, intermediate_manifest):
279a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  """Tries to run the linker for all parts using the current round of
280a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  generated import libs and .def files. If the link fails, updates the
281a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  unresolved externals list per part."""
282a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  dlls = []
283a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  all_succeeded = True
284a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  new_externals = []
285a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  Log('unresolveds now: %r' % [len(part) for part in unresolved_by_part])
286a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for i, (inputs, deffile) in enumerate(zip(inputs_by_part, deffiles)):
287a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    Log('running link, part %d' % i)
288a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    others_implibs = import_libs[:]
289a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    others_implibs.pop(i)
290a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    inputs_with_implib = inputs + filter(lambda x: x, others_implibs)
291a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if deffile:
292a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      flags = flags + ['/DEF:%s' % deffile, '/LTCG']
29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    stdout, rc, output = RunLinker(
29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        flags, i, inputs_with_implib, 'final', intermediate_manifest)
295a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if rc != 0:
296a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      all_succeeded = False
297a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      new_externals.append(ParseOutExternals(stdout))
298a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    else:
299a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      new_externals.append([])
300a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      dlls.append(output)
301a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  combined_externals = [sorted(set(prev) | set(new))
302a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                        for prev, new in zip(unresolved_by_part, new_externals)]
303a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return all_succeeded, dlls, combined_externals
304a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
305a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
30690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def ExtractSubObjsTargetedAtAll(
30790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    inputs,
30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    num_parts,
30990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    description_parts,
31090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    description_all,
31190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    description_all_from_libs):
31290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  """For (lib, obj) tuples in the all_from_libs section, extract the obj out of
31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  the lib and added it to inputs. Returns a list of lists for which part the
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  extracted obj belongs in (which is whichever the .lib isn't in)."""
31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  by_parts = [[] for _ in range(num_parts)]
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for lib_spec, obj_spec in description_all_from_libs:
31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for input_file in inputs:
31890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if re.search(lib_spec, input_file):
31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        objs = GetLibObjList(input_file)
32090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        match_count = 0
32190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        for obj in objs:
32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          if re.search(obj_spec, obj, re.I):
32390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            extracted_obj = ExtractObjFromLib(input_file, obj)
32490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            #Log('extracted %s (%s %s)' % (extracted_obj, input_file, obj))
32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            i = PartFor(input_file, description_parts, description_all)
32690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            if i == -1:
32790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              raise SystemExit(
32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  '%s is already in all parts, but matched '
32990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  '%s in all_from_libs' % (input_file, obj))
33090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            # See note in main().
33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            assert num_parts == 2, "Can't handle > 2 dlls currently"
33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            by_parts[1 - i].append(obj)
33390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            match_count += 1
33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if match_count == 0:
33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          raise SystemExit(
33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              '%s, %s matched a lib, but no objs' % (lib_spec, obj_spec))
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return by_parts
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
340a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)def main():
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  flags, inputs, intermediate_manifest = GetFlagsAndInputs(sys.argv[1:])
342a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  partition_file = os.path.normpath(
343a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      os.path.join(BASE_DIR, '../../../build/split_link_partition.py'))
344a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  with open(partition_file) as partition:
345a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    description = eval(partition.read())
346a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  inputs_by_part = []
347a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  description_parts = description['parts']
34890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  # We currently assume that if a symbol isn't in dll 0, then it's in dll 1
349a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # when generating def files. Otherwise, we'd need to do more complex things
350a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # to figure out where each symbol actually is to assign it to the correct
351a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # .def file.
352a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  num_parts = len(description_parts)
353a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  assert num_parts == 2, "Can't handle > 2 dlls currently"
354a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  description_parts.reverse()
35590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  objs_from_libs = ExtractSubObjsTargetedAtAll(
35690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      inputs,
35790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      num_parts,
35890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      description_parts,
35990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      description['all'],
36090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      description['all_from_libs'])
36190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  objs_from_libs.reverse()
362a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  inputs_by_part = [[] for _ in range(num_parts)]
363a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for input_file in inputs:
364a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    i = PartFor(input_file, description_parts, description['all'])
365a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if i == -1:
366a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      for part in inputs_by_part:
367a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        part.append(input_file)
368a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    else:
369a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      inputs_by_part[i].append(input_file)
370a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  inputs_by_part.reverse()
371a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
37290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  # Put the subobjs on to the main list.
37390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for i, part in enumerate(objs_from_libs):
37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    Log('%d sub .objs added to part %d' % (len(part), i))
37590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    inputs_by_part[i].extend(part)
37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
377a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  unresolved_by_part = [[] for _ in range(num_parts)]
378a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  import_libs = [None] * num_parts
379a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  deffiles = [None] * num_parts
380a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
38190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  data_exports = 0
382a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for i in range(5):
383a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    Log('--- starting pass %d' % i)
384a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    ok, dlls, unresolved_by_part = AttemptLink(
38590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        flags, inputs_by_part, unresolved_by_part, deffiles, import_libs,
38690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        intermediate_manifest)
387a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if ok:
388a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      break
38990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    data_exports = 0
39090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for i, part in enumerate(unresolved_by_part):
39190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for export in part:
39290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if IsDataDefinition(export):
39390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          print 'part %d contains data export: %s (aka %s)' % (
39490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              i, Unmangle(export), export)
39590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          data_exports += 1
396a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    deffiles = GenerateDefFiles(unresolved_by_part)
397a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    import_libs = BuildImportLibs(flags, inputs_by_part, deffiles)
398a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  else:
39990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if data_exports and not IGNORE_DATA:
40090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      print '%d data exports found, see report above.' % data_exports
40190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      print('These cannot be exported, and must be either duplicated to the '
40290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            'target DLL (if constant), or wrapped in a function.')
403a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return 1
40490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
40590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  mt_exe = GetMtPath()
40690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for i, dll in enumerate(dlls):
40790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    Log('embedding manifest in %s' % dll)
40890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    args = [mt_exe, '-nologo', '-manifest']
40990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    args.append(ManifestNameForIndex(i))
41090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    args.append(description['manifest'])
41190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    args.append('-outputresource:%s;2' % dll)
41290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    subprocess.check_call(args)
41390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
414a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  Log('built %r' % dlls)
415a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
416a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return 0
417a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
418a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
419a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)if __name__ == '__main__':
420a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  sys.exit(main())
421