OLD | NEW |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 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 """ | 5 """ |
6 From a system-installed copy of the toolchain, packages all the required bits | 6 From a system-installed copy of the toolchain, packages all the required bits |
7 into a .zip file. | 7 into a .zip file. |
8 | 8 |
9 It assumes default install locations for tools, in particular: | 9 It assumes default install locations for tools, in particular: |
10 - C:\Program Files (x86)\Microsoft Visual Studio 12.0\... | 10 - C:\Program Files (x86)\Microsoft Visual Studio 12.0\... |
11 - C:\Program Files (x86)\Windows Kits\10\... | 11 - C:\Program Files (x86)\Windows Kits\10\... |
12 | 12 |
13 1. Start from a fresh Win7 VM image. | 13 1. Start from a fresh Win7 VM image. |
14 2. Install VS Pro. Deselect everything except MFC. | 14 2. Install VS Pro. Deselect everything except MFC. |
15 3. Install Windows 10 SDK. Select only the Windows SDK and Debugging Tools for | 15 3. Install Windows 10 SDK. Select only the Windows SDK and Debugging Tools for |
16 Windows. | 16 Windows. |
17 4. Run this script, which will build a <sha1>.zip. | 17 4. Run this script, which will build a <sha1>.zip. |
18 | 18 |
19 Express is not yet supported by this script, but patches welcome (it's not too | 19 Express is not yet supported by this script, but patches welcome (it's not too |
20 useful as the resulting zip can't be redistributed, and most will presumably | 20 useful as the resulting zip can't be redistributed, and most will presumably |
21 have a Pro license anyway). | 21 have a Pro license anyway). |
22 """ | 22 """ |
23 | 23 |
| 24 import optparse |
24 import os | 25 import os |
| 26 import platform |
25 import shutil | 27 import shutil |
26 import sys | 28 import sys |
27 import tempfile | 29 import tempfile |
28 import zipfile | 30 import zipfile |
29 | 31 |
30 import get_toolchain_if_necessary | 32 import get_toolchain_if_necessary |
31 | 33 |
32 | 34 |
33 VS_VERSION = None | 35 VS_VERSION = None |
| 36 WIN_VERSION = None |
34 | 37 |
35 | 38 |
36 def BuildFileList(): | 39 def BuildFileList(): |
37 result = [] | 40 result = [] |
38 | 41 |
39 # Subset of VS corresponding roughly to VC. | 42 # Subset of VS corresponding roughly to VC. |
40 paths = [ | 43 paths = [ |
41 'DIA SDK/bin', | 44 'DIA SDK/bin', |
42 'DIA SDK/idl', | 45 'DIA SDK/idl', |
43 'DIA SDK/include', | 46 'DIA SDK/include', |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 else: | 108 else: |
106 result.append((final_from, dest)) | 109 result.append((final_from, dest)) |
107 | 110 |
108 # Just copy the whole SDK. | 111 # Just copy the whole SDK. |
109 sdk_path = r'C:\Program Files (x86)\Windows Kits\10' | 112 sdk_path = r'C:\Program Files (x86)\Windows Kits\10' |
110 for root, _, files in os.walk(sdk_path): | 113 for root, _, files in os.walk(sdk_path): |
111 for f in files: | 114 for f in files: |
112 combined = os.path.normpath(os.path.join(root, f)) | 115 combined = os.path.normpath(os.path.join(root, f)) |
113 # Some of the files in this directory are exceedingly long (and exceed | 116 # Some of the files in this directory are exceedingly long (and exceed |
114 #_MAX_PATH for any moderately long root), so exclude them. We don't need | 117 #_MAX_PATH for any moderately long root), so exclude them. We don't need |
115 # them anyway. | 118 # them anyway. Exclude the Windows Performance Toolkit just to save space. |
116 tail = combined[len(sdk_path) + 1:] | 119 tail = combined[len(sdk_path) + 1:] |
117 if tail.startswith('References\\'): | 120 if (tail.startswith('References\\') or |
| 121 tail.startswith('Windows Performance Toolkit\\')): |
118 continue | 122 continue |
| 123 if VS_VERSION == '2015': |
| 124 # There may be many Include\Lib\Source directories for many different |
| 125 # versions of Windows and packaging them all wastes ~450 MB |
| 126 # (uncompressed) per version and wastes time. Only copy the specified |
| 127 # version. |
| 128 if (tail.startswith('Include\\') or tail.startswith('Lib\\') or |
| 129 tail.startswith('Source\\')): |
| 130 if tail.count(WIN_VERSION) == 0: |
| 131 continue |
119 to = os.path.join('win_sdk', tail) | 132 to = os.path.join('win_sdk', tail) |
120 result.append((combined, to)) | 133 result.append((combined, to)) |
121 | 134 |
122 if VS_VERSION == '2015': | 135 if VS_VERSION == '2015': |
123 for ucrt_path in ( | |
124 (r'C:\Program Files (x86)\Windows Kits\10\Include', 'Include'), | |
125 (r'C:\Program Files (x86)\Windows Kits\10\Lib', 'Lib'), | |
126 (r'C:\Program Files (x86)\Windows Kits\10\Source', 'Source')): | |
127 src, target = ucrt_path | |
128 for root, _, files in os.walk(src): | |
129 for f in files: | |
130 combined = os.path.normpath(os.path.join(root, f)) | |
131 to = os.path.join('ucrt', target, combined[len(src) + 1:]) | |
132 result.append((combined, to)) | |
133 | 136 |
134 system_crt_files = [ | 137 system_crt_files = [ |
135 'api-ms-win-core-file-l1-2-0.dll', | 138 'api-ms-win-core-file-l1-2-0.dll', |
136 'api-ms-win-core-file-l2-1-0.dll', | 139 'api-ms-win-core-file-l2-1-0.dll', |
137 'api-ms-win-core-localization-l1-2-0.dll', | 140 'api-ms-win-core-localization-l1-2-0.dll', |
138 'api-ms-win-core-processthreads-l1-1-1.dll', | 141 'api-ms-win-core-processthreads-l1-1-1.dll', |
139 'api-ms-win-core-synch-l1-2-0.dll', | 142 'api-ms-win-core-synch-l1-2-0.dll', |
140 'api-ms-win-core-timezone-l1-1-0.dll', | 143 'api-ms-win-core-timezone-l1-1-0.dll', |
141 'api-ms-win-core-xstate-l2-1-0.dll', | 144 'api-ms-win-core-xstate-l2-1-0.dll', |
142 'api-ms-win-crt-conio-l1-1-0.dll', | 145 'api-ms-win-crt-conio-l1-1-0.dll', |
143 'api-ms-win-crt-convert-l1-1-0.dll', | 146 'api-ms-win-crt-convert-l1-1-0.dll', |
144 'api-ms-win-crt-environment-l1-1-0.dll', | 147 'api-ms-win-crt-environment-l1-1-0.dll', |
145 'api-ms-win-crt-filesystem-l1-1-0.dll', | 148 'api-ms-win-crt-filesystem-l1-1-0.dll', |
146 'api-ms-win-crt-heap-l1-1-0.dll', | 149 'api-ms-win-crt-heap-l1-1-0.dll', |
147 'api-ms-win-crt-locale-l1-1-0.dll', | 150 'api-ms-win-crt-locale-l1-1-0.dll', |
148 'api-ms-win-crt-math-l1-1-0.dll', | 151 'api-ms-win-crt-math-l1-1-0.dll', |
149 'api-ms-win-crt-multibyte-l1-1-0.dll', | 152 'api-ms-win-crt-multibyte-l1-1-0.dll', |
150 'api-ms-win-crt-private-l1-1-0.dll', | 153 'api-ms-win-crt-private-l1-1-0.dll', |
151 'api-ms-win-crt-process-l1-1-0.dll', | 154 'api-ms-win-crt-process-l1-1-0.dll', |
152 'api-ms-win-crt-runtime-l1-1-0.dll', | 155 'api-ms-win-crt-runtime-l1-1-0.dll', |
153 'api-ms-win-crt-stdio-l1-1-0.dll', | 156 'api-ms-win-crt-stdio-l1-1-0.dll', |
154 'api-ms-win-crt-string-l1-1-0.dll', | 157 'api-ms-win-crt-string-l1-1-0.dll', |
155 'api-ms-win-crt-time-l1-1-0.dll', | 158 'api-ms-win-crt-time-l1-1-0.dll', |
156 'api-ms-win-crt-utility-l1-1-0.dll', | 159 'api-ms-win-crt-utility-l1-1-0.dll', |
157 'api-ms-win-eventing-provider-l1-1-0.dll', | 160 'api-ms-win-eventing-provider-l1-1-0.dll', |
158 'ucrtbase.dll', | 161 'ucrtbase.dll', |
159 'ucrtbased.dll', | 162 'ucrtbased.dll', |
160 ] | 163 ] |
| 164 bitness = platform.architecture()[0] |
| 165 # When running 64-bit python the x64 DLLs will be in System32 |
| 166 x64_path = 'System32' if bitness == '64bit' else 'Sysnative' |
| 167 x64_path = os.path.join(r'C:\Windows', x64_path) |
161 for system_crt_file in system_crt_files: | 168 for system_crt_file in system_crt_files: |
162 result.append((os.path.join(r'C:\Windows\SysWOW64', system_crt_file), | 169 result.append((os.path.join(r'C:\Windows\SysWOW64', system_crt_file), |
163 os.path.join('sys32', system_crt_file))) | 170 os.path.join('sys32', system_crt_file))) |
164 result.append((os.path.join(r'C:\Windows\Sysnative', system_crt_file), | 171 result.append((os.path.join(x64_path, system_crt_file), |
165 os.path.join('sys64', system_crt_file))) | 172 os.path.join('sys64', system_crt_file))) |
166 | 173 |
167 # Generically drop all arm stuff that we don't need. | 174 # Generically drop all arm stuff that we don't need, and |
| 175 # drop .msi files because we don't need installers. |
168 return [(f, t) for f, t in result if 'arm\\' not in f.lower() and | 176 return [(f, t) for f, t in result if 'arm\\' not in f.lower() and |
169 'arm64\\' not in f.lower()] | 177 'arm64\\' not in f.lower() and |
| 178 not f.lower().endswith('.msi')] |
170 | 179 |
171 | 180 |
172 def GenerateSetEnvCmd(target_dir): | 181 def GenerateSetEnvCmd(target_dir): |
173 """Generate a batch file that gyp expects to exist to set up the compiler | 182 """Generate a batch file that gyp expects to exist to set up the compiler |
174 environment. | 183 environment. |
175 | 184 |
176 This is normally generated by a full install of the SDK, but we | 185 This is normally generated by a full install of the SDK, but we |
177 do it here manually since we do not do a full install.""" | 186 do it here manually since we do not do a full install.""" |
178 with open(os.path.join( | 187 with open(os.path.join( |
179 target_dir, r'win_sdk\bin\SetEnv.cmd'), 'w') as f: | 188 target_dir, r'win_sdk\bin\SetEnv.cmd'), 'w') as f: |
180 f.write('@echo off\n' | 189 f.write('@echo off\n' |
181 ':: Generated by win_toolchain\\package_from_installed.py.\n' | 190 ':: Generated by win_toolchain\\package_from_installed.py.\n' |
182 # Common to x86 and x64 | 191 # Common to x86 and x64 |
183 'set PATH=%~dp0..\\..\\Common7\\IDE;%PATH%\n' | 192 'set PATH=%~dp0..\\..\\Common7\\IDE;%PATH%\n' |
184 'set INCLUDE=%~dp0..\\..\\win_sdk\\Include\\10.0.10240.0\\um;' | 193 'set INCLUDE=%~dp0..\\..\\win_sdk\\Include\\WINVERSION\\um;' |
185 '%~dp0..\\..\\win_sdk\\Include\\10.0.10240.0\\shared;' | 194 '%~dp0..\\..\\win_sdk\\Include\\WINVERSION\\shared;' |
186 '%~dp0..\\..\\win_sdk\\Include\\10.0.10240.0\\winrt;' | 195 '%~dp0..\\..\\win_sdk\\Include\\WINVERSION\\winrt;' |
| 196 '%~dp0..\\..\\win_sdk\\Include\\WINVERSION\\ucrt;' # VS 2015 |
187 '%~dp0..\\..\\VC\\include;' | 197 '%~dp0..\\..\\VC\\include;' |
188 '%~dp0..\\..\\VC\\atlmfc\\include\n' | 198 '%~dp0..\\..\\VC\\atlmfc\\include\n' |
189 'if "%1"=="/x64" goto x64\n') | 199 'if "%1"=="/x64" goto x64\n'.replace('WINVERSION', WIN_VERSION)) |
190 | 200 |
191 # x86. Always use amd64_x86 cross, not x86 on x86. | 201 # x86. Always use amd64_x86 cross, not x86 on x86. |
192 f.write('set PATH=%~dp0..\\..\\win_sdk\\bin\\x86;' | 202 f.write('set PATH=%~dp0..\\..\\win_sdk\\bin\\x86;' |
193 '%~dp0..\\..\\VC\\bin\\amd64_x86;' | 203 '%~dp0..\\..\\VC\\bin\\amd64_x86;' |
194 '%~dp0..\\..\\VC\\bin\\amd64;' # Needed for mspdb1x0.dll. | 204 '%~dp0..\\..\\VC\\bin\\amd64;' # Needed for mspdb1x0.dll. |
195 '%PATH%\n') | 205 '%PATH%\n') |
196 f.write('set LIB=%~dp0..\\..\\VC\\lib;' | 206 f.write('set LIB=%~dp0..\\..\\VC\\lib;' |
197 '%~dp0..\\..\\win_sdk\\Lib\\10.0.10240.0\\um\\x86;' | 207 '%~dp0..\\..\\win_sdk\\Lib\\WINVERSION\\um\\x86;' |
| 208 '%~dp0..\\..\\win_sdk\\Lib\\WINVERSION\\ucrt\\x86;' # VS 2015 |
198 '%~dp0..\\..\\VC\\atlmfc\\lib\n' | 209 '%~dp0..\\..\\VC\\atlmfc\\lib\n' |
199 'goto :EOF\n') | 210 'goto :EOF\n'.replace('WINVERSION', WIN_VERSION)) |
200 | 211 |
201 # x64. | 212 # x64. |
202 f.write(':x64\n' | 213 f.write(':x64\n' |
203 'set PATH=%~dp0..\\..\\win_sdk\\bin\\x64;' | 214 'set PATH=%~dp0..\\..\\win_sdk\\bin\\x64;' |
204 '%~dp0..\\..\\VC\\bin\\amd64;' | 215 '%~dp0..\\..\\VC\\bin\\amd64;' |
205 '%PATH%\n') | 216 '%PATH%\n') |
206 f.write('set LIB=%~dp0..\\..\\VC\\lib\\amd64;' | 217 f.write('set LIB=%~dp0..\\..\\VC\\lib\\amd64;' |
207 '%~dp0..\\..\\win_sdk\\Lib\\10.0.10240.0\\um\\x64;' | 218 '%~dp0..\\..\\win_sdk\\Lib\\WINVERSION\\um\\x64;' |
208 '%~dp0..\\..\\VC\\atlmfc\\lib\\amd64\n') | 219 '%~dp0..\\..\\win_sdk\\Lib\\WINVERSION\\ucrt\\x64;' # VS 2015 |
| 220 '%~dp0..\\..\\VC\\atlmfc\\lib\\amd64\n' |
| 221 .replace('WINVERSION', WIN_VERSION)) |
209 | 222 |
210 | 223 |
211 def AddEnvSetup(files): | 224 def AddEnvSetup(files): |
212 """We need to generate this file in the same way that the "from pieces" | 225 """We need to generate this file in the same way that the "from pieces" |
213 script does, so pull that in here.""" | 226 script does, so pull that in here.""" |
214 tempdir = tempfile.mkdtemp() | 227 tempdir = tempfile.mkdtemp() |
215 os.makedirs(os.path.join(tempdir, 'win_sdk', 'bin')) | 228 os.makedirs(os.path.join(tempdir, 'win_sdk', 'bin')) |
216 GenerateSetEnvCmd(tempdir) | 229 GenerateSetEnvCmd(tempdir) |
217 files.append((os.path.join(tempdir, 'win_sdk', 'bin', 'SetEnv.cmd'), | 230 files.append((os.path.join(tempdir, 'win_sdk', 'bin', 'SetEnv.cmd'), |
218 'win_sdk\\bin\\SetEnv.cmd')) | 231 'win_sdk\\bin\\SetEnv.cmd')) |
(...skipping 20 matching lines...) Expand all Loading... |
239 print 'Hashing...' | 252 print 'Hashing...' |
240 sha1 = get_toolchain_if_necessary.CalculateHash(rel_dir) | 253 sha1 = get_toolchain_if_necessary.CalculateHash(rel_dir) |
241 os.chdir(old_dir) | 254 os.chdir(old_dir) |
242 shutil.rmtree(tempdir) | 255 shutil.rmtree(tempdir) |
243 final_name = sha1 + '.zip' | 256 final_name = sha1 + '.zip' |
244 os.rename(output, final_name) | 257 os.rename(output, final_name) |
245 print 'Renamed %s to %s.' % (output, final_name) | 258 print 'Renamed %s to %s.' % (output, final_name) |
246 | 259 |
247 | 260 |
248 def main(): | 261 def main(): |
249 if len(sys.argv) != 2 or sys.argv[1] not in ('2013', '2015'): | 262 usage = 'usage: %prog [options] 2013|2015' |
250 print 'Usage: package_from_installed.py 2013|2015' | 263 parser = optparse.OptionParser(usage) |
| 264 parser.add_option('-w', '--winver', action='store', type='string', |
| 265 dest='winver', default='10.0.10586.0', |
| 266 help='Windows SDK version, such as 10.0.10586.0') |
| 267 parser.add_option('-d', '--dryrun', action='store_true', dest='dryrun', |
| 268 default=False, |
| 269 help='scan for file existence and prints statistics') |
| 270 (options, args) = parser.parse_args() |
| 271 |
| 272 if len(args) != 1 or args[0] not in ('2013', '2015'): |
| 273 print 'Must specify 2013 or 2015' |
| 274 parser.print_help(); |
251 return 1 | 275 return 1 |
252 | 276 |
253 global VS_VERSION | 277 global VS_VERSION |
254 VS_VERSION = sys.argv[1] | 278 VS_VERSION = args[0] |
| 279 global WIN_VERSION |
| 280 WIN_VERSION = options.winver |
255 | 281 |
256 print 'Building file list...' | 282 print 'Building file list for VS %s Windows %s...' % (VS_VERSION, WIN_VERSION) |
257 files = BuildFileList() | 283 files = BuildFileList() |
258 | 284 |
259 AddEnvSetup(files) | 285 AddEnvSetup(files) |
260 | 286 |
261 if False: | 287 if False: |
262 for f in files: | 288 for f in files: |
263 print f[0], '->', f[1] | 289 print f[0], '->', f[1] |
264 return 0 | 290 return 0 |
265 | 291 |
266 output = 'out.zip' | 292 output = 'out.zip' |
267 if os.path.exists(output): | 293 if os.path.exists(output): |
268 os.unlink(output) | 294 os.unlink(output) |
269 count = 0 | 295 count = 0 |
| 296 version_match_count = 0 |
| 297 total_size = 0 |
| 298 missing_files = False |
270 with zipfile.ZipFile(output, 'w', zipfile.ZIP_DEFLATED, True) as zf: | 299 with zipfile.ZipFile(output, 'w', zipfile.ZIP_DEFLATED, True) as zf: |
271 for disk_name, archive_name in files: | 300 for disk_name, archive_name in files: |
272 sys.stdout.write('\r%d/%d ...%s' % (count, len(files), disk_name[-40:])) | 301 sys.stdout.write('\r%d/%d ...%s' % (count, len(files), disk_name[-40:])) |
273 sys.stdout.flush() | 302 sys.stdout.flush() |
274 count += 1 | 303 count += 1 |
275 zf.write(disk_name, archive_name) | 304 if disk_name.count(WIN_VERSION) > 0: |
| 305 version_match_count += 1 |
| 306 if os.path.exists(disk_name): |
| 307 if options.dryrun: |
| 308 total_size += os.path.getsize(disk_name) |
| 309 else: |
| 310 zf.write(disk_name, archive_name) |
| 311 else: |
| 312 missing_files = True |
| 313 sys.stdout.write('\r%s does not exist.\n\n' % disk_name) |
| 314 sys.stdout.flush() |
| 315 if options.dryrun: |
| 316 sys.stdout.write('\r%1.3f GB of data in %d files, %d files for %s.%s\n' % |
| 317 (total_size / 1e9, count, version_match_count, WIN_VERSION, ' '*50)) |
| 318 return 0 |
| 319 if missing_files: |
| 320 raise 'One or more files were missing - aborting' |
| 321 if version_match_count == 0: |
| 322 raise 'No files found that match the specified winversion' |
276 sys.stdout.write('\rWrote to %s.%s\n' % (output, ' '*50)) | 323 sys.stdout.write('\rWrote to %s.%s\n' % (output, ' '*50)) |
277 sys.stdout.flush() | 324 sys.stdout.flush() |
278 | 325 |
279 RenameToSha1(output) | 326 RenameToSha1(output) |
280 | 327 |
281 return 0 | 328 return 0 |
282 | 329 |
283 | 330 |
284 if __name__ == '__main__': | 331 if __name__ == '__main__': |
285 sys.exit(main()) | 332 sys.exit(main()) |
OLD | NEW |