| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 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 """Takes the same arguments as Windows link.exe, and a definition of libraries | 5 """Takes the same arguments as Windows link.exe, and a definition of libraries |
| 6 to split into subcomponents. Does multiple passes of link.exe invocation to | 6 to split into subcomponents. Does multiple passes of link.exe invocation to |
| 7 determine exports between parts and generates .def and import libraries to | 7 determine exports between parts and generates .def and import libraries to |
| 8 cause symbols to be available to other parts.""" | 8 cause symbols to be available to other parts.""" |
| 9 | 9 |
| 10 import _winreg | 10 import _winreg |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 ref = ctypes.c_wchar_p * size.value | 42 ref = ctypes.c_wchar_p * size.value |
| 43 raw = ref.from_address(ptr) | 43 raw = ref.from_address(ptr) |
| 44 args = [arg for arg in raw] | 44 args = [arg for arg in raw] |
| 45 finally: | 45 finally: |
| 46 ctypes.windll.kernel32.LocalFree(ptr) | 46 ctypes.windll.kernel32.LocalFree(ptr) |
| 47 | 47 |
| 48 inputs = [] | 48 inputs = [] |
| 49 flags = [] | 49 flags = [] |
| 50 for arg in args: | 50 for arg in args: |
| 51 lower_arg = arg.lower() | 51 lower_arg = arg.lower() |
| 52 # We'll be replacing this ourselves. | 52 # We'll be replacing these ourselves. |
| 53 if lower_arg.startswith('/out:'): | 53 if lower_arg.startswith('/out:'): |
| 54 continue | 54 continue |
| 55 if lower_arg.startswith('/manifestfile:'): |
| 56 continue |
| 55 if (not lower_arg.startswith('/') and | 57 if (not lower_arg.startswith('/') and |
| 56 lower_arg.endswith(('.obj', '.lib', '.res'))): | 58 lower_arg.endswith(('.obj', '.lib', '.res'))): |
| 57 inputs.append(arg) | 59 inputs.append(arg) |
| 58 else: | 60 else: |
| 59 flags.append(arg) | 61 flags.append(arg) |
| 60 | 62 |
| 61 return flags, inputs | 63 return flags, inputs |
| 62 | 64 |
| 63 | 65 |
| 64 def GetOriginalLinkerPath(): | 66 def GetRegistryValue(subkey): |
| 65 try: | 67 try: |
| 66 val = _winreg.QueryValue(_winreg.HKEY_CURRENT_USER, | 68 val = _winreg.QueryValue(_winreg.HKEY_CURRENT_USER, |
| 67 'Software\\Chromium\\split_link_installed') | 69 'Software\\Chromium\\' + subkey) |
| 68 if os.path.exists(val): | 70 if os.path.exists(val): |
| 69 return val | 71 return val |
| 70 except WindowsError: | 72 except WindowsError: |
| 71 pass | 73 pass |
| 72 | 74 |
| 73 raise SystemExit("Couldn't read linker location from registry") | 75 raise SystemExit("Couldn't read from registry") |
| 76 |
| 77 |
| 78 def GetOriginalLinkerPath(): |
| 79 return GetRegistryValue('split_link_installed') |
| 80 |
| 81 |
| 82 def GetMtPath(): |
| 83 return GetRegistryValue('split_link_mt_path') |
| 74 | 84 |
| 75 | 85 |
| 76 def PartFor(input_file, description_parts, description_all): | 86 def PartFor(input_file, description_parts, description_all): |
| 77 """Determines which part a given link input should be put into (or all).""" | 87 """Determines which part a given link input should be put into (or all).""" |
| 78 # Check if it should go in all parts. | 88 # Check if it should go in all parts. |
| 79 input_file = input_file.lower() | 89 input_file = input_file.lower() |
| 80 if any(re.search(spec, input_file) for spec in description_all): | 90 if any(re.search(spec, input_file) for spec in description_all): |
| 81 return -1 | 91 return -1 |
| 82 # Or pick which particular one it belongs in. | 92 # Or pick which particular one it belongs in. |
| 83 for i, spec_list in enumerate(description_parts): | 93 for i, spec_list in enumerate(description_parts): |
| (...skipping 27 matching lines...) Expand all Loading... |
| 111 mo = regex.search(line) | 121 mo = regex.search(line) |
| 112 if mo: | 122 if mo: |
| 113 if strip_leading_underscore: | 123 if strip_leading_underscore: |
| 114 result.add(mo.group(1)[1:]) | 124 result.add(mo.group(1)[1:]) |
| 115 else: | 125 else: |
| 116 result.add(mo.group(1)) | 126 result.add(mo.group(1)) |
| 117 break | 127 break |
| 118 | 128 |
| 119 mo = re.search(r'fatal error LNK1120: (\d+) unresolved externals', output) | 129 mo = re.search(r'fatal error LNK1120: (\d+) unresolved externals', output) |
| 120 # Make sure we have the same number that the linker thinks we have. | 130 # Make sure we have the same number that the linker thinks we have. |
| 121 assert mo or not result | 131 if mo is None and result: |
| 132 raise SystemExit(output) |
| 122 if len(result) != int(mo.group(1)): | 133 if len(result) != int(mo.group(1)): |
| 123 print output | 134 print output |
| 124 print 'Expecting %d, got %d' % (int(mo.group(1)), len(result)) | 135 print 'Expecting %d, got %d' % (int(mo.group(1)), len(result)) |
| 125 assert len(result) == int(mo.group(1)) | 136 assert len(result) == int(mo.group(1)) |
| 126 return sorted(result) | 137 return sorted(result) |
| 127 | 138 |
| 128 | 139 |
| 129 def AsCommandLineArgs(items): | 140 def AsCommandLineArgs(items): |
| 130 """Intended for output to a response file. Quotes all arguments.""" | 141 """Intended for output to a response file. Quotes all arguments.""" |
| 131 return '\n'.join('"' + x + '"' for x in items) | 142 return '\n'.join('"' + x + '"' for x in items) |
| 132 | 143 |
| 133 | 144 |
| 134 def OutputNameForIndex(index): | 145 def OutputNameForIndex(index): |
| 135 """Gets the final output DLL name, given a zero-based index.""" | 146 """Gets the final output DLL name, given a zero-based index.""" |
| 136 if index == 0: | 147 if index == 0: |
| 137 return "chrome.dll" | 148 return "chrome.dll" |
| 138 else: | 149 else: |
| 139 return 'chrome%d.dll' % index | 150 return 'chrome%d.dll' % index |
| 140 | 151 |
| 141 | 152 |
| 153 def ManifestNameForIndex(index): |
| 154 return OutputNameForIndex(index) + '.intermediate.manifest' |
| 155 |
| 156 |
| 142 def RunLinker(flags, index, inputs, phase): | 157 def RunLinker(flags, index, inputs, phase): |
| 143 """Invokes the linker and returns the stdout, returncode and target name.""" | 158 """Invokes the linker and returns the stdout, returncode and target name.""" |
| 144 rspfile = 'part%d_%s.rsp' % (index, phase) | 159 rspfile = 'part%d_%s.rsp' % (index, phase) |
| 145 with open(rspfile, 'w') as f: | 160 with open(rspfile, 'w') as f: |
| 146 print >> f, AsCommandLineArgs(inputs) | 161 print >> f, AsCommandLineArgs(inputs) |
| 147 print >> f, AsCommandLineArgs(flags) | 162 print >> f, AsCommandLineArgs(flags) |
| 148 output_name = OutputNameForIndex(index) | 163 output_name = OutputNameForIndex(index) |
| 164 manifest_name = ManifestNameForIndex(index) |
| 149 print >> f, '/ENTRY:ChromeEmptyEntry@12' | 165 print >> f, '/ENTRY:ChromeEmptyEntry@12' |
| 150 print >> f, '/OUT:' + output_name | 166 print >> f, '/OUT:' + output_name |
| 167 print >> f, '/MANIFESTFILE:' + manifest_name |
| 151 # Log('[[[\n' + open(rspfile).read() + '\n]]]') | 168 # Log('[[[\n' + open(rspfile).read() + '\n]]]') |
| 152 link_exe = GetOriginalLinkerPath() | 169 link_exe = GetOriginalLinkerPath() |
| 153 popen = subprocess.Popen([link_exe, '@' + rspfile], stdout=subprocess.PIPE) | 170 popen = subprocess.Popen([link_exe, '@' + rspfile], stdout=subprocess.PIPE) |
| 154 stdout, _ = popen.communicate() | 171 stdout, _ = popen.communicate() |
| 155 return stdout, popen.returncode, output_name | 172 return stdout, popen.returncode, output_name |
| 156 | 173 |
| 157 | 174 |
| 158 def GenerateDefFiles(unresolved_by_part): | 175 def GenerateDefFiles(unresolved_by_part): |
| 159 """Given a list of unresolved externals, generates a .def file that will | 176 """Given a list of unresolved externals, generates a .def file that will |
| 160 cause all those symbols to be exported.""" | 177 cause all those symbols to be exported.""" |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 for i in range(5): | 263 for i in range(5): |
| 247 Log('--- starting pass %d' % i) | 264 Log('--- starting pass %d' % i) |
| 248 ok, dlls, unresolved_by_part = AttemptLink( | 265 ok, dlls, unresolved_by_part = AttemptLink( |
| 249 flags, inputs_by_part, unresolved_by_part, deffiles, import_libs) | 266 flags, inputs_by_part, unresolved_by_part, deffiles, import_libs) |
| 250 if ok: | 267 if ok: |
| 251 break | 268 break |
| 252 deffiles = GenerateDefFiles(unresolved_by_part) | 269 deffiles = GenerateDefFiles(unresolved_by_part) |
| 253 import_libs = BuildImportLibs(flags, inputs_by_part, deffiles) | 270 import_libs = BuildImportLibs(flags, inputs_by_part, deffiles) |
| 254 else: | 271 else: |
| 255 return 1 | 272 return 1 |
| 273 |
| 274 mt_exe = GetMtPath() |
| 275 for i, dll in enumerate(dlls): |
| 276 Log('embedding manifest in %s' % dll) |
| 277 args = [mt_exe, '-nologo', '-manifest'] |
| 278 args.append(ManifestNameForIndex(i)) |
| 279 args.append(description['manifest']) |
| 280 args.append('-outputresource:%s;2' % dll) |
| 281 subprocess.check_call(args) |
| 282 |
| 256 Log('built %r' % dlls) | 283 Log('built %r' % dlls) |
| 257 | 284 |
| 258 return 0 | 285 return 0 |
| 259 | 286 |
| 260 | 287 |
| 261 if __name__ == '__main__': | 288 if __name__ == '__main__': |
| 262 sys.exit(main()) | 289 sys.exit(main()) |
| OLD | NEW |