Index: win_toolchain/package_from_installed.py |
diff --git a/win_toolchain/package_from_installed.py b/win_toolchain/package_from_installed.py |
index 2762201284115e82e17d5d8457fcb508df7e2b90..19d3e706c1b4925c349464c7b138de2f5008a271 100644 |
--- a/win_toolchain/package_from_installed.py |
+++ b/win_toolchain/package_from_installed.py |
@@ -21,7 +21,9 @@ useful as the resulting zip can't be redistributed, and most will presumably |
have a Pro license anyway). |
""" |
+import optparse |
import os |
+import platform |
import shutil |
import sys |
import tempfile |
@@ -31,6 +33,7 @@ import get_toolchain_if_necessary |
VS_VERSION = None |
+WIN_VERSION = None |
def BuildFileList(): |
@@ -112,24 +115,24 @@ def BuildFileList(): |
combined = os.path.normpath(os.path.join(root, f)) |
# Some of the files in this directory are exceedingly long (and exceed |
#_MAX_PATH for any moderately long root), so exclude them. We don't need |
- # them anyway. |
+ # them anyway. Exclude the Windows Performance Toolkit just to save space. |
tail = combined[len(sdk_path) + 1:] |
- if tail.startswith('References\\'): |
+ if (tail.startswith('References\\') or |
+ tail.startswith('Windows Performance Toolkit\\')): |
continue |
+ if VS_VERSION == '2015': |
+ # There may be many Include\Lib\Source directories for many different |
+ # versions of Windows and packaging them all wastes ~450 MB |
+ # (uncompressed) per version and wastes time. Only copy the specified |
+ # version. |
+ if (tail.startswith('Include\\') or tail.startswith('Lib\\') or |
+ tail.startswith('Source\\')): |
+ if tail.count(WIN_VERSION) == 0: |
+ continue |
to = os.path.join('win_sdk', tail) |
result.append((combined, to)) |
if VS_VERSION == '2015': |
- for ucrt_path in ( |
- (r'C:\Program Files (x86)\Windows Kits\10\Include', 'Include'), |
- (r'C:\Program Files (x86)\Windows Kits\10\Lib', 'Lib'), |
- (r'C:\Program Files (x86)\Windows Kits\10\Source', 'Source')): |
- src, target = ucrt_path |
- for root, _, files in os.walk(src): |
- for f in files: |
- combined = os.path.normpath(os.path.join(root, f)) |
- to = os.path.join('ucrt', target, combined[len(src) + 1:]) |
- result.append((combined, to)) |
system_crt_files = [ |
'api-ms-win-core-file-l1-2-0.dll', |
@@ -158,15 +161,21 @@ def BuildFileList(): |
'ucrtbase.dll', |
'ucrtbased.dll', |
] |
+ bitness = platform.architecture()[0] |
+ # When running 64-bit python the x64 DLLs will be in System32 |
+ x64_path = 'System32' if bitness == '64bit' else 'Sysnative' |
+ x64_path = os.path.join(r'C:\Windows', x64_path) |
for system_crt_file in system_crt_files: |
result.append((os.path.join(r'C:\Windows\SysWOW64', system_crt_file), |
os.path.join('sys32', system_crt_file))) |
- result.append((os.path.join(r'C:\Windows\Sysnative', system_crt_file), |
+ result.append((os.path.join(x64_path, system_crt_file), |
os.path.join('sys64', system_crt_file))) |
- # Generically drop all arm stuff that we don't need. |
+ # Generically drop all arm stuff that we don't need, and |
+ # drop .msi files because we don't need installers. |
return [(f, t) for f, t in result if 'arm\\' not in f.lower() and |
- 'arm64\\' not in f.lower()] |
+ 'arm64\\' not in f.lower() and |
+ not f.lower().endswith('.msi')] |
def GenerateSetEnvCmd(target_dir): |
@@ -181,12 +190,13 @@ def GenerateSetEnvCmd(target_dir): |
':: Generated by win_toolchain\\package_from_installed.py.\n' |
# Common to x86 and x64 |
'set PATH=%~dp0..\\..\\Common7\\IDE;%PATH%\n' |
- 'set INCLUDE=%~dp0..\\..\\win_sdk\\Include\\10.0.10240.0\\um;' |
- '%~dp0..\\..\\win_sdk\\Include\\10.0.10240.0\\shared;' |
- '%~dp0..\\..\\win_sdk\\Include\\10.0.10240.0\\winrt;' |
+ 'set INCLUDE=%~dp0..\\..\\win_sdk\\Include\\WINVERSION\\um;' |
+ '%~dp0..\\..\\win_sdk\\Include\\WINVERSION\\shared;' |
+ '%~dp0..\\..\\win_sdk\\Include\\WINVERSION\\winrt;' |
+ '%~dp0..\\..\\win_sdk\\Include\\WINVERSION\\ucrt;' # VS 2015 |
'%~dp0..\\..\\VC\\include;' |
'%~dp0..\\..\\VC\\atlmfc\\include\n' |
- 'if "%1"=="/x64" goto x64\n') |
+ 'if "%1"=="/x64" goto x64\n'.replace('WINVERSION', WIN_VERSION)) |
# x86. Always use amd64_x86 cross, not x86 on x86. |
f.write('set PATH=%~dp0..\\..\\win_sdk\\bin\\x86;' |
@@ -194,9 +204,10 @@ def GenerateSetEnvCmd(target_dir): |
'%~dp0..\\..\\VC\\bin\\amd64;' # Needed for mspdb1x0.dll. |
'%PATH%\n') |
f.write('set LIB=%~dp0..\\..\\VC\\lib;' |
- '%~dp0..\\..\\win_sdk\\Lib\\10.0.10240.0\\um\\x86;' |
+ '%~dp0..\\..\\win_sdk\\Lib\\WINVERSION\\um\\x86;' |
+ '%~dp0..\\..\\win_sdk\\Lib\\WINVERSION\\ucrt\\x86;' # VS 2015 |
'%~dp0..\\..\\VC\\atlmfc\\lib\n' |
- 'goto :EOF\n') |
+ 'goto :EOF\n'.replace('WINVERSION', WIN_VERSION)) |
# x64. |
f.write(':x64\n' |
@@ -204,8 +215,10 @@ def GenerateSetEnvCmd(target_dir): |
'%~dp0..\\..\\VC\\bin\\amd64;' |
'%PATH%\n') |
f.write('set LIB=%~dp0..\\..\\VC\\lib\\amd64;' |
- '%~dp0..\\..\\win_sdk\\Lib\\10.0.10240.0\\um\\x64;' |
- '%~dp0..\\..\\VC\\atlmfc\\lib\\amd64\n') |
+ '%~dp0..\\..\\win_sdk\\Lib\\WINVERSION\\um\\x64;' |
+ '%~dp0..\\..\\win_sdk\\Lib\\WINVERSION\\ucrt\\x64;' # VS 2015 |
+ '%~dp0..\\..\\VC\\atlmfc\\lib\\amd64\n' |
+ .replace('WINVERSION', WIN_VERSION)) |
def AddEnvSetup(files): |
@@ -246,14 +259,27 @@ def RenameToSha1(output): |
def main(): |
- if len(sys.argv) != 2 or sys.argv[1] not in ('2013', '2015'): |
- print 'Usage: package_from_installed.py 2013|2015' |
+ usage = 'usage: %prog [options] 2013|2015' |
+ parser = optparse.OptionParser(usage) |
+ parser.add_option('-w', '--winver', action='store', type='string', |
+ dest='winver', default='10.0.10586.0', |
+ help='Windows SDK version, such as 10.0.10586.0') |
+ parser.add_option('-d', '--dryrun', action='store_true', dest='dryrun', |
+ default=False, |
+ help='scan for file existence and prints statistics') |
+ (options, args) = parser.parse_args() |
+ |
+ if len(args) != 1 or args[0] not in ('2013', '2015'): |
+ print 'Must specify 2013 or 2015' |
+ parser.print_help(); |
return 1 |
global VS_VERSION |
- VS_VERSION = sys.argv[1] |
+ VS_VERSION = args[0] |
+ global WIN_VERSION |
+ WIN_VERSION = options.winver |
- print 'Building file list...' |
+ print 'Building file list for VS %s Windows %s...' % (VS_VERSION, WIN_VERSION) |
files = BuildFileList() |
AddEnvSetup(files) |
@@ -267,12 +293,33 @@ def main(): |
if os.path.exists(output): |
os.unlink(output) |
count = 0 |
+ version_match_count = 0 |
+ total_size = 0 |
+ missing_files = False |
with zipfile.ZipFile(output, 'w', zipfile.ZIP_DEFLATED, True) as zf: |
for disk_name, archive_name in files: |
sys.stdout.write('\r%d/%d ...%s' % (count, len(files), disk_name[-40:])) |
sys.stdout.flush() |
count += 1 |
- zf.write(disk_name, archive_name) |
+ if disk_name.count(WIN_VERSION) > 0: |
+ version_match_count += 1 |
+ if os.path.exists(disk_name): |
+ if options.dryrun: |
+ total_size += os.path.getsize(disk_name) |
+ else: |
+ zf.write(disk_name, archive_name) |
+ else: |
+ missing_files = True |
+ sys.stdout.write('\r%s does not exist.\n\n' % disk_name) |
+ sys.stdout.flush() |
+ if options.dryrun: |
+ sys.stdout.write('\r%1.3f GB of data in %d files, %d files for %s.%s\n' % |
+ (total_size / 1e9, count, version_match_count, WIN_VERSION, ' '*50)) |
+ return 0 |
+ if missing_files: |
+ raise 'One or more files were missing - aborting' |
+ if version_match_count == 0: |
+ raise 'No files found that match the specified winversion' |
sys.stdout.write('\rWrote to %s.%s\n' % (output, ' '*50)) |
sys.stdout.flush() |