Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 | 2 |
| 3 # Copyright (c) 2012 Google Inc. All rights reserved. | 3 # Copyright (c) 2012 Google Inc. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 """Utility functions for Windows builds. | 7 """Utility functions for Windows builds. |
| 8 | 8 |
| 9 These functions are executed via gyp-win-tool when using the ninja generator. | 9 These functions are executed via gyp-win-tool when using the ninja generator. |
| 10 """ | 10 """ |
| 11 | 11 |
| 12 import os | 12 import os |
| 13 import re | |
| 13 import shutil | 14 import shutil |
| 14 import subprocess | 15 import subprocess |
| 15 import sys | 16 import sys |
| 16 | 17 |
| 17 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | 18 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) |
| 18 | 19 |
| 20 # A regex matching an argument corresponding to a PDB filename passed as an | |
| 21 # argument to link.exe. | |
| 22 _LINK_EXE_PDB_ARG = re.compile('/PDB\:(?P<pdb>[^ ]+\.exe\.pdb)', | |
|
Sigurður Ásgeirsson
2013/11/26 14:31:05
Do you need to escape the ":"?
Note that this re w
Sébastien Marchand
2013/11/27 19:26:57
Thanks for the Regex 101 :), fixed.
| |
| 23 re.VERBOSE | re.IGNORECASE) | |
| 19 | 24 |
| 20 def main(args): | 25 def main(args): |
| 21 executor = WinTool() | 26 executor = WinTool() |
| 22 exit_code = executor.Dispatch(args) | 27 exit_code = executor.Dispatch(args) |
| 23 if exit_code is not None: | 28 if exit_code is not None: |
| 24 sys.exit(exit_code) | 29 sys.exit(exit_code) |
| 25 | 30 |
| 26 | 31 |
| 27 class WinTool(object): | 32 class WinTool(object): |
| 28 """This class performs all the Windows tooling steps. The methods can either | 33 """This class performs all the Windows tooling steps. The methods can either |
| 29 be executed directly, or dispatched from an argument list.""" | 34 be executed directly, or dispatched from an argument list.""" |
| 30 | 35 |
| 36 class MsPdbSrvHelper(object): | |
| 37 """This is an helper class to use a unique instance of mspdbsrv.exe for the | |
| 38 linkers linking an .exe target. This helps to reduce the memory pressure one | |
| 39 the shared instance of mspdbsrv.exe.""" | |
| 40 | |
| 41 def __init__(self, env, args): | |
| 42 self.env = env | |
| 43 self.args = args | |
| 44 self.mspdbsrv_process = None | |
| 45 | |
| 46 def __enter__(self): | |
| 47 self._MaybeStartMsPdbSrv() | |
|
Sigurður Ásgeirsson
2013/11/26 14:31:05
Stupid question: do you need to manually start the
Sébastien Marchand
2013/11/27 19:26:57
Yeah, the linker will automatically spawn it but I
| |
| 48 | |
| 49 def __exit__(self, type, value, traceback): | |
| 50 if self.mspdbsrv_process is not None: | |
| 51 self._StopMsPdbSrv() | |
| 52 | |
| 53 def _MaybeStartMsPdbSrv(self): | |
| 54 """Starts an unique instance of mspdbsrv.exe if the given arguments are | |
| 55 those of a linker linking a .exe target.""" | |
| 56 if not os.environ.get('GYP_USE_SEPARATE_MSPDBSRV'): | |
| 57 return False | |
|
scottmg
2013/11/26 00:44:54
just return, not return False
Sébastien Marchand
2013/11/27 19:26:57
Oops, done.
| |
| 58 | |
| 59 if len(self.args) < 1: | |
| 60 raise Exception("Not enough arguments") | |
| 61 | |
| 62 if self.args[0] != 'link.exe': | |
| 63 return False | |
|
scottmg
2013/11/26 00:44:54
and here
Sébastien Marchand
2013/11/27 19:26:57
Done.
| |
| 64 | |
| 65 # Checks if this linker produces a PDB for an .exe target. If so use the | |
| 66 # name of this PDB to generate an endpoint name for mspdbsrv.exe. | |
| 67 endpoint_name = None | |
| 68 for arg in self.args: | |
| 69 m = _LINK_EXE_PDB_ARG.match(arg) | |
| 70 if m: | |
| 71 endpoint_name = m.group('pdb') + '_' + str(os.getpid()) | |
|
Sigurður Ásgeirsson
2013/11/26 14:31:05
IMHO clearer so use string formatting for this, e.
Sébastien Marchand
2013/11/27 19:26:57
Done.
| |
| 72 break | |
| 73 | |
| 74 if endpoint_name is None: | |
| 75 return False | |
|
scottmg
2013/11/26 00:44:54
and here
Sébastien Marchand
2013/11/27 19:26:57
Done.
| |
| 76 | |
| 77 # Adds the appropriate environment variable. This will be read by link.exe | |
| 78 # to know which instance of mspdbsrv.exe it should connect to (if it's | |
| 79 # not set then the default endpoint is used). | |
| 80 self.env['_MSPDBSRV_ENDPOINT_'] = endpoint_name | |
| 81 | |
| 82 # Starts the mspdbsrv.exe instance manually. We could specify the endpoint | |
| 83 # in the command line but it's redundant with setting it in the | |
| 84 # environment block. Starting this process manually allows us to wait for | |
| 85 # its completion once the link step is finished. This is required to | |
| 86 # respect the dependencies between the different targets. | |
| 87 mspdbsrv_args = ('mspdbsrv.exe', '-start', '-spawn') | |
|
Sigurður Ásgeirsson
2013/11/26 14:31:05
I'd be surprised if the stop command isn't synchro
Sébastien Marchand
2013/11/27 19:26:57
It looks like you're right.
| |
| 88 self.mspdbsrv_process = subprocess.Popen(mspdbsrv_args, | |
| 89 shell=True, | |
| 90 env=self.env) | |
| 91 return | |
|
scottmg
2013/11/26 00:44:54
no return
Sébastien Marchand
2013/11/27 19:26:57
Done.
| |
| 92 | |
| 93 def _StopMsPdbSrv(self): | |
| 94 """Stop the instance of mspdbsrv.exe that has been started by this | |
| 95 helper.""" | |
| 96 mspdbsrv_stop_args = ('mspdbsrv.exe', '-stop') | |
| 97 mspdbsrv_stop_process = subprocess.call(mspdbsrv_stop_args, | |
| 98 shell=True, | |
| 99 env=self.env) | |
| 100 self.mspdbsrv_process.wait() | |
| 101 return | |
|
scottmg
2013/11/26 00:44:54
no return
Sébastien Marchand
2013/11/27 19:26:57
Done.
| |
| 102 | |
| 31 def Dispatch(self, args): | 103 def Dispatch(self, args): |
| 32 """Dispatches a string command to a method.""" | 104 """Dispatches a string command to a method.""" |
| 33 if len(args) < 1: | 105 if len(args) < 1: |
| 34 raise Exception("Not enough arguments") | 106 raise Exception("Not enough arguments") |
| 35 | 107 |
| 36 method = "Exec%s" % self._CommandifyName(args[0]) | 108 method = "Exec%s" % self._CommandifyName(args[0]) |
| 37 return getattr(self, method)(*args[1:]) | 109 return getattr(self, method)(*args[1:]) |
| 38 | 110 |
| 39 def _CommandifyName(self, name_string): | 111 def _CommandifyName(self, name_string): |
| 40 """Transforms a tool name like recursive-mirror to RecursiveMirror.""" | 112 """Transforms a tool name like recursive-mirror to RecursiveMirror.""" |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 64 shutil.copytree(source, dest) | 136 shutil.copytree(source, dest) |
| 65 else: | 137 else: |
| 66 shutil.copy2(source, dest) | 138 shutil.copy2(source, dest) |
| 67 | 139 |
| 68 def ExecLinkWrapper(self, arch, *args): | 140 def ExecLinkWrapper(self, arch, *args): |
| 69 """Filter diagnostic output from link that looks like: | 141 """Filter diagnostic output from link that looks like: |
| 70 ' Creating library ui.dll.lib and object ui.dll.exp' | 142 ' Creating library ui.dll.lib and object ui.dll.exp' |
| 71 This happens when there are exports from the dll or exe. | 143 This happens when there are exports from the dll or exe. |
| 72 """ | 144 """ |
| 73 env = self._GetEnv(arch) | 145 env = self._GetEnv(arch) |
| 74 popen = subprocess.Popen(args, shell=True, env=env, | 146 popen = None |
|
scottmg
2013/11/26 00:44:54
this isn't necessary. (i know it looks scary, but
Sigurður Ásgeirsson
2013/11/26 14:31:05
nit: perhaps a more descriptive name, while you're
Sébastien Marchand
2013/11/27 19:26:57
This is scary.
Sébastien Marchand
2013/11/27 19:26:57
Done.
| |
| 75 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | 147 with WinTool.MsPdbSrvHelper(env, args) as mspdbsrv_helper: |
|
scottmg
2013/11/26 00:44:54
you can remove ' as mspdbsrv_helper' since it's ne
Sébastien Marchand
2013/11/27 19:26:57
Done.
| |
| 76 out, _ = popen.communicate() | 148 popen = subprocess.Popen(args, shell=True, env=env, |
| 77 for line in out.splitlines(): | 149 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
| 78 if not line.startswith(' Creating library '): | 150 out, _ = popen.communicate() |
| 79 print line | 151 for line in out.splitlines(): |
| 152 if not line.startswith(' Creating library '): | |
| 153 print line | |
| 80 return popen.returncode | 154 return popen.returncode |
| 81 | 155 |
| 82 def ExecManifestWrapper(self, arch, *args): | 156 def ExecManifestWrapper(self, arch, *args): |
| 83 """Run manifest tool with environment set. Strip out undesirable warning | 157 """Run manifest tool with environment set. Strip out undesirable warning |
| 84 (some XML blocks are recognized by the OS loader, but not the manifest | 158 (some XML blocks are recognized by the OS loader, but not the manifest |
| 85 tool).""" | 159 tool).""" |
| 86 env = self._GetEnv(arch) | 160 env = self._GetEnv(arch) |
| 87 popen = subprocess.Popen(args, shell=True, env=env, | 161 popen = subprocess.Popen(args, shell=True, env=env, |
| 88 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | 162 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
| 89 out, _ = popen.communicate() | 163 out, _ = popen.communicate() |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 161 line): | 235 line): |
| 162 print line | 236 print line |
| 163 return popen.returncode | 237 return popen.returncode |
| 164 | 238 |
| 165 def ExecActionWrapper(self, arch, rspfile, *dir): | 239 def ExecActionWrapper(self, arch, rspfile, *dir): |
| 166 """Runs an action command line from a response file using the environment | 240 """Runs an action command line from a response file using the environment |
| 167 for |arch|. If |dir| is supplied, use that as the working directory.""" | 241 for |arch|. If |dir| is supplied, use that as the working directory.""" |
| 168 env = self._GetEnv(arch) | 242 env = self._GetEnv(arch) |
| 169 args = open(rspfile).read() | 243 args = open(rspfile).read() |
| 170 dir = dir[0] if dir else None | 244 dir = dir[0] if dir else None |
| 171 popen = subprocess.Popen(args, shell=True, env=env, cwd=dir) | 245 popen = subprocess.Popen(args, shell=True, env=env, cwd=dir) |
|
Sigurður Ásgeirsson
2013/11/26 14:31:05
isn't this === return subprocess.call(...)?
Sébastien Marchand
2013/11/27 19:26:57
It looks like it is. Done.
| |
| 172 popen.wait() | 246 popen.wait() |
| 173 return popen.returncode | 247 return popen.returncode |
| 174 | 248 |
| 175 if __name__ == '__main__': | 249 if __name__ == '__main__': |
| 176 sys.exit(main(sys.argv[1:])) | 250 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |