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 re |
14 import shutil | 14 import shutil |
15 import subprocess | 15 import subprocess |
| 16 import string |
16 import sys | 17 import sys |
17 | 18 |
18 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | 19 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) |
19 | 20 |
20 # A regex matching an argument corresponding to a PDB filename passed as an | 21 # A regex matching an argument corresponding to a PDB filename passed as an |
21 # argument to link.exe. | 22 # argument to link.exe. |
22 _LINK_EXE_PDB_ARG = re.compile('/PDB:(?P<pdb>.+\.exe\.pdb)$', re.IGNORECASE) | 23 _LINK_EXE_PDB_ARG = re.compile('/PDB:(?P<pdb>.+\.exe\.pdb)$', re.IGNORECASE) |
23 | 24 |
24 def main(args): | 25 def main(args): |
25 executor = WinTool() | 26 executor = WinTool() |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 shell=True, | 110 shell=True, |
110 env=env, | 111 env=env, |
111 stdout=subprocess.PIPE, | 112 stdout=subprocess.PIPE, |
112 stderr=subprocess.STDOUT) | 113 stderr=subprocess.STDOUT) |
113 out, _ = link.communicate() | 114 out, _ = link.communicate() |
114 for line in out.splitlines(): | 115 for line in out.splitlines(): |
115 if not line.startswith(' Creating library '): | 116 if not line.startswith(' Creating library '): |
116 print line | 117 print line |
117 return link.returncode | 118 return link.returncode |
118 | 119 |
| 120 def ExecLinkWithManifests(self, arch, embed_manifest, out, ldcmd, resname, |
| 121 mt, rc, intermediate_manifest, *manifests): |
| 122 """A wrapper for handling creating a manifest resource and then executing |
| 123 a link command.""" |
| 124 # The 'normal' way to do manifests is to have link generate a manifest |
| 125 # based on gathering dependencies from the object files, then merge that |
| 126 # manifest with other manifests supplied as sources, convert the merged |
| 127 # manifest to a resource, and then *relink*, including the compiled |
| 128 # version of the manifest resource. This breaks incremental linking, and |
| 129 # is generally overly complicated. Instead, we merge all the manifests |
| 130 # provided (along with one that includes what would normally be in the |
| 131 # linker-generated one, see msvs_emulation.py), and include that into the |
| 132 # first and only link. We still tell link to generate a manifest, but we |
| 133 # only use that to assert that our simpler process did not miss anything. |
| 134 variables = { |
| 135 'python': sys.executable, |
| 136 'arch': arch, |
| 137 'out': out, |
| 138 'ldcmd': ldcmd, |
| 139 'resname': resname, |
| 140 'mt': mt, |
| 141 'rc': rc, |
| 142 'intermediate_manifest': intermediate_manifest, |
| 143 'manifests': ' '.join(manifests), |
| 144 } |
| 145 add_to_ld = '' |
| 146 if manifests: |
| 147 subprocess.check_call( |
| 148 '%(python)s gyp-win-tool manifest-wrapper %(arch)s %(mt)s -nologo ' |
| 149 '-manifest %(manifests)s -out:%(out)s.manifest' % variables) |
| 150 if embed_manifest == 'True': |
| 151 subprocess.check_call( |
| 152 '%(python)s gyp-win-tool manifest-to-rc %(arch)s %(out)s.manifest' |
| 153 ' %(out)s.manifest.rc %(resname)s' % variables) |
| 154 subprocess.check_call( |
| 155 '%(python)s gyp-win-tool rc-wrapper %(arch)s %(rc)s ' |
| 156 '%(out)s.manifest.rc' % variables) |
| 157 add_to_ld = ' %(out)s.manifest.res' % variables |
| 158 subprocess.check_call(ldcmd + add_to_ld) |
| 159 |
| 160 # Run mt.exe on the theoretically complete manifest we generated, merging |
| 161 # it with the one the linker generated to confirm that the linker |
| 162 # generated one does not add anything. This is strictly unnecessary for |
| 163 # correctness, it's only to verify that e.g. /MANIFESTDEPENDENCY was not |
| 164 # used in a #pragma comment. |
| 165 if manifests: |
| 166 # Merge the intermediate one with ours to .assert.manifest, then check |
| 167 # that .assert.manifest is identical to ours. |
| 168 subprocess.check_call( |
| 169 '%(python)s gyp-win-tool manifest-wrapper %(arch)s %(mt)s -nologo ' |
| 170 '-manifest %(out)s.manifest %(intermediate_manifest)s ' |
| 171 '-out:%(out)s.assert.manifest' % variables) |
| 172 assert_manifest = '%(out)s.assert.manifest' % variables |
| 173 our_manifest = '%(out)s.manifest' % variables |
| 174 # Load and normalize the manifests. mt.exe sometimes removes whitespace, |
| 175 # and sometimes doesn't unfortunately. |
| 176 with open(our_manifest, 'rb') as our_f: |
| 177 with open(assert_manifest, 'rb') as assert_f: |
| 178 our_data = our_f.read().translate(None, string.whitespace) |
| 179 assert_data = assert_f.read().translate(None, string.whitespace) |
| 180 if our_data != assert_data: |
| 181 os.unlink(out) |
| 182 def dump(filename): |
| 183 sys.stderr.write('%s\n-----\n' % filename) |
| 184 with open(filename, 'rb') as f: |
| 185 sys.stderr.write(f.read() + '\n-----\n') |
| 186 dump(intermediate_manifest) |
| 187 dump(our_manifest) |
| 188 dump(assert_manifest) |
| 189 sys.stderr.write( |
| 190 'Linker generated manifest "%s" added to final manifest "%s" ' |
| 191 '(result in "%s"). ' |
| 192 'Were /MANIFEST switches used in #pragma statements? ' % ( |
| 193 intermediate_manifest, our_manifest, assert_manifest)) |
| 194 return 1 |
| 195 |
119 def ExecManifestWrapper(self, arch, *args): | 196 def ExecManifestWrapper(self, arch, *args): |
120 """Run manifest tool with environment set. Strip out undesirable warning | 197 """Run manifest tool with environment set. Strip out undesirable warning |
121 (some XML blocks are recognized by the OS loader, but not the manifest | 198 (some XML blocks are recognized by the OS loader, but not the manifest |
122 tool).""" | 199 tool).""" |
123 env = self._GetEnv(arch) | 200 env = self._GetEnv(arch) |
124 popen = subprocess.Popen(args, shell=True, env=env, | 201 popen = subprocess.Popen(args, shell=True, env=env, |
125 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | 202 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
126 out, _ = popen.communicate() | 203 out, _ = popen.communicate() |
127 for line in out.splitlines(): | 204 for line in out.splitlines(): |
128 if line and 'manifest authoring warning 81010002' not in line: | 205 if line and 'manifest authoring warning 81010002' not in line: |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 def ExecActionWrapper(self, arch, rspfile, *dir): | 279 def ExecActionWrapper(self, arch, rspfile, *dir): |
203 """Runs an action command line from a response file using the environment | 280 """Runs an action command line from a response file using the environment |
204 for |arch|. If |dir| is supplied, use that as the working directory.""" | 281 for |arch|. If |dir| is supplied, use that as the working directory.""" |
205 env = self._GetEnv(arch) | 282 env = self._GetEnv(arch) |
206 args = open(rspfile).read() | 283 args = open(rspfile).read() |
207 dir = dir[0] if dir else None | 284 dir = dir[0] if dir else None |
208 return subprocess.call(args, shell=True, env=env, cwd=dir) | 285 return subprocess.call(args, shell=True, env=env, cwd=dir) |
209 | 286 |
210 if __name__ == '__main__': | 287 if __name__ == '__main__': |
211 sys.exit(main(sys.argv[1:])) | 288 sys.exit(main(sys.argv[1:])) |
OLD | NEW |