| 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 |