You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			286 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			286 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
# Copyright 2014 The Chromium Authors. All rights reserved.
 | 
						|
# Use of this source code is governed by a BSD-style license that can be
 | 
						|
# found in the LICENSE file.
 | 
						|
 | 
						|
"""
 | 
						|
From a system-installed copy of the toolchain, packages all the required bits
 | 
						|
into a .zip file.
 | 
						|
 | 
						|
It assumes default install locations for tools, in particular:
 | 
						|
- C:\Program Files (x86)\Microsoft Visual Studio 12.0\...
 | 
						|
- C:\Program Files (x86)\Windows Kits\10\...
 | 
						|
 | 
						|
1. Start from a fresh Win7 VM image.
 | 
						|
2. Install VS Pro. Deselect everything except MFC.
 | 
						|
3. Install Windows 10 SDK. Select only the Windows SDK and Debugging Tools for
 | 
						|
Windows.
 | 
						|
4. Run this script, which will build a <sha1>.zip.
 | 
						|
 | 
						|
Express is not yet supported by this script, but patches welcome (it's not too
 | 
						|
useful as the resulting zip can't be redistributed, and most will presumably
 | 
						|
have a Pro license anyway).
 | 
						|
"""
 | 
						|
 | 
						|
import os
 | 
						|
import shutil
 | 
						|
import sys
 | 
						|
import tempfile
 | 
						|
import zipfile
 | 
						|
 | 
						|
import get_toolchain_if_necessary
 | 
						|
 | 
						|
 | 
						|
VS_VERSION = None
 | 
						|
 | 
						|
 | 
						|
def BuildFileList():
 | 
						|
  result = []
 | 
						|
 | 
						|
  # Subset of VS corresponding roughly to VC.
 | 
						|
  paths = [
 | 
						|
      'DIA SDK/bin',
 | 
						|
      'DIA SDK/idl',
 | 
						|
      'DIA SDK/include',
 | 
						|
      'DIA SDK/lib',
 | 
						|
      'VC/atlmfc',
 | 
						|
      'VC/bin',
 | 
						|
      'VC/crt',
 | 
						|
      'VC/include',
 | 
						|
      'VC/lib',
 | 
						|
      'VC/redist',
 | 
						|
  ]
 | 
						|
 | 
						|
  if VS_VERSION == '2013':
 | 
						|
    paths += [
 | 
						|
        ('VC/redist/x86/Microsoft.VC120.CRT', 'sys32'),
 | 
						|
        ('VC/redist/x86/Microsoft.VC120.MFC', 'sys32'),
 | 
						|
        ('VC/redist/Debug_NonRedist/x86/Microsoft.VC120.DebugCRT', 'sys32'),
 | 
						|
        ('VC/redist/Debug_NonRedist/x86/Microsoft.VC120.DebugMFC', 'sys32'),
 | 
						|
        ('VC/redist/x64/Microsoft.VC120.CRT', 'sys64'),
 | 
						|
        ('VC/redist/x64/Microsoft.VC120.MFC', 'sys64'),
 | 
						|
        ('VC/redist/Debug_NonRedist/x64/Microsoft.VC120.DebugCRT', 'sys64'),
 | 
						|
        ('VC/redist/Debug_NonRedist/x64/Microsoft.VC120.DebugMFC', 'sys64'),
 | 
						|
    ]
 | 
						|
  elif VS_VERSION == '2015':
 | 
						|
    paths += [
 | 
						|
        ('VC/redist/x86/Microsoft.VC140.CRT', 'sys32'),
 | 
						|
        ('VC/redist/x86/Microsoft.VC140.MFC', 'sys32'),
 | 
						|
        ('VC/redist/debug_nonredist/x86/Microsoft.VC140.DebugCRT', 'sys32'),
 | 
						|
        ('VC/redist/debug_nonredist/x86/Microsoft.VC140.DebugMFC', 'sys32'),
 | 
						|
        ('VC/redist/x64/Microsoft.VC140.CRT', 'sys64'),
 | 
						|
        ('VC/redist/x64/Microsoft.VC140.MFC', 'sys64'),
 | 
						|
        ('VC/redist/debug_nonredist/x64/Microsoft.VC140.DebugCRT', 'sys64'),
 | 
						|
        ('VC/redist/debug_nonredist/x64/Microsoft.VC140.DebugMFC', 'sys64'),
 | 
						|
    ]
 | 
						|
  else:
 | 
						|
    raise ValueError('VS_VERSION %s' % VS_VERSION)
 | 
						|
 | 
						|
  if VS_VERSION == '2013':
 | 
						|
    vs_path = r'C:\Program Files (x86)\Microsoft Visual Studio 12.0'
 | 
						|
  else:
 | 
						|
    vs_path = r'C:\Program Files (x86)\Microsoft Visual Studio 14.0'
 | 
						|
 | 
						|
  for path in paths:
 | 
						|
    src = path[0] if isinstance(path, tuple) else path
 | 
						|
    combined = os.path.join(vs_path, src)
 | 
						|
    assert os.path.exists(combined) and os.path.isdir(combined)
 | 
						|
    for root, _, files in os.walk(combined):
 | 
						|
      for f in files:
 | 
						|
        final_from = os.path.normpath(os.path.join(root, f))
 | 
						|
        if isinstance(path, tuple):
 | 
						|
          result.append(
 | 
						|
              (final_from, os.path.normpath(os.path.join(path[1], f))))
 | 
						|
        else:
 | 
						|
          assert final_from.startswith(vs_path)
 | 
						|
          dest = final_from[len(vs_path) + 1:]
 | 
						|
          if VS_VERSION == '2013' and dest.lower().endswith('\\xtree'):
 | 
						|
            # Patch for C4702 in xtree on VS2013. http://crbug.com/346399.
 | 
						|
            (handle, patched) = tempfile.mkstemp()
 | 
						|
            with open(final_from, 'rb') as unpatched_f:
 | 
						|
              unpatched_contents = unpatched_f.read()
 | 
						|
            os.write(handle,
 | 
						|
                unpatched_contents.replace('warning(disable: 4127)',
 | 
						|
                                           'warning(disable: 4127 4702)'))
 | 
						|
            result.append((patched, dest))
 | 
						|
          else:
 | 
						|
            result.append((final_from, dest))
 | 
						|
 | 
						|
  # Just copy the whole SDK.
 | 
						|
  sdk_path = r'C:\Program Files (x86)\Windows Kits\10'
 | 
						|
  for root, _, files in os.walk(sdk_path):
 | 
						|
    for f in files:
 | 
						|
      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.
 | 
						|
      tail = combined[len(sdk_path) + 1:]
 | 
						|
      if tail.startswith('References\\'):
 | 
						|
        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',
 | 
						|
        'api-ms-win-core-file-l2-1-0.dll',
 | 
						|
        'api-ms-win-core-localization-l1-2-0.dll',
 | 
						|
        'api-ms-win-core-processthreads-l1-1-1.dll',
 | 
						|
        'api-ms-win-core-synch-l1-2-0.dll',
 | 
						|
        'api-ms-win-core-timezone-l1-1-0.dll',
 | 
						|
        'api-ms-win-core-xstate-l2-1-0.dll',
 | 
						|
        'api-ms-win-crt-conio-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-convert-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-environment-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-filesystem-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-heap-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-locale-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-math-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-multibyte-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-private-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-process-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-runtime-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-stdio-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-string-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-time-l1-1-0.dll',
 | 
						|
        'api-ms-win-crt-utility-l1-1-0.dll',
 | 
						|
        'api-ms-win-eventing-provider-l1-1-0.dll',
 | 
						|
        'ucrtbase.dll',
 | 
						|
        'ucrtbased.dll',
 | 
						|
    ]
 | 
						|
    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),
 | 
						|
                       os.path.join('sys64', system_crt_file)))
 | 
						|
 | 
						|
  # Generically drop all arm stuff that we don't need.
 | 
						|
  return [(f, t) for f, t in result if 'arm\\' not in f.lower() and
 | 
						|
                                       'arm64\\' not in f.lower()]
 | 
						|
 | 
						|
 | 
						|
def GenerateSetEnvCmd(target_dir):
 | 
						|
  """Generate a batch file that gyp expects to exist to set up the compiler
 | 
						|
  environment.
 | 
						|
 | 
						|
  This is normally generated by a full install of the SDK, but we
 | 
						|
  do it here manually since we do not do a full install."""
 | 
						|
  with open(os.path.join(
 | 
						|
        target_dir, r'win_sdk\bin\SetEnv.cmd'), 'w') as f:
 | 
						|
    f.write('@echo off\n'
 | 
						|
            ':: 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;'
 | 
						|
               '%~dp0..\\..\\VC\\include;'
 | 
						|
               '%~dp0..\\..\\VC\\atlmfc\\include\n'
 | 
						|
            'if "%1"=="/x64" goto x64\n')
 | 
						|
 | 
						|
    # x86. Always use amd64_x86 cross, not x86 on x86.
 | 
						|
    f.write('set PATH=%~dp0..\\..\\win_sdk\\bin\\x86;'
 | 
						|
              '%~dp0..\\..\\VC\\bin\\amd64_x86;'
 | 
						|
              '%~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..\\..\\VC\\atlmfc\\lib\n'
 | 
						|
            'goto :EOF\n')
 | 
						|
 | 
						|
    # x64.
 | 
						|
    f.write(':x64\n'
 | 
						|
            'set PATH=%~dp0..\\..\\win_sdk\\bin\\x64;'
 | 
						|
                '%~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')
 | 
						|
 | 
						|
 | 
						|
def AddEnvSetup(files):
 | 
						|
  """We need to generate this file in the same way that the "from pieces"
 | 
						|
  script does, so pull that in here."""
 | 
						|
  tempdir = tempfile.mkdtemp()
 | 
						|
  os.makedirs(os.path.join(tempdir, 'win_sdk', 'bin'))
 | 
						|
  GenerateSetEnvCmd(tempdir)
 | 
						|
  files.append((os.path.join(tempdir, 'win_sdk', 'bin', 'SetEnv.cmd'),
 | 
						|
                'win_sdk\\bin\\SetEnv.cmd'))
 | 
						|
  vs_version_file = os.path.join(tempdir, 'VS_VERSION')
 | 
						|
  with open(vs_version_file, 'wb') as version:
 | 
						|
    print >>version, VS_VERSION
 | 
						|
  files.append((vs_version_file, 'VS_VERSION'))
 | 
						|
 | 
						|
 | 
						|
def RenameToSha1(output):
 | 
						|
  """Determine the hash in the same way that the unzipper does to rename the
 | 
						|
  # .zip file."""
 | 
						|
  print 'Extracting to determine hash...'
 | 
						|
  tempdir = tempfile.mkdtemp()
 | 
						|
  old_dir = os.getcwd()
 | 
						|
  os.chdir(tempdir)
 | 
						|
  if VS_VERSION == '2013':
 | 
						|
    rel_dir = 'vs2013_files'
 | 
						|
  else:
 | 
						|
    rel_dir = 'vs_files'
 | 
						|
  with zipfile.ZipFile(
 | 
						|
      os.path.join(old_dir, output), 'r', zipfile.ZIP_DEFLATED, True) as zf:
 | 
						|
    zf.extractall(rel_dir)
 | 
						|
  print 'Hashing...'
 | 
						|
  sha1 = get_toolchain_if_necessary.CalculateHash(rel_dir)
 | 
						|
  os.chdir(old_dir)
 | 
						|
  shutil.rmtree(tempdir)
 | 
						|
  final_name = sha1 + '.zip'
 | 
						|
  os.rename(output, final_name)
 | 
						|
  print 'Renamed %s to %s.' % (output, final_name)
 | 
						|
 | 
						|
 | 
						|
def main():
 | 
						|
  if len(sys.argv) != 2 or sys.argv[1] not in ('2013', '2015'):
 | 
						|
    print 'Usage: package_from_installed.py 2013|2015'
 | 
						|
    return 1
 | 
						|
 | 
						|
  global VS_VERSION
 | 
						|
  VS_VERSION = sys.argv[1]
 | 
						|
 | 
						|
  print 'Building file list...'
 | 
						|
  files = BuildFileList()
 | 
						|
 | 
						|
  AddEnvSetup(files)
 | 
						|
 | 
						|
  if False:
 | 
						|
    for f in files:
 | 
						|
      print f[0], '->', f[1]
 | 
						|
    return 0
 | 
						|
 | 
						|
  output = 'out.zip'
 | 
						|
  if os.path.exists(output):
 | 
						|
    os.unlink(output)
 | 
						|
  count = 0
 | 
						|
  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)
 | 
						|
  sys.stdout.write('\rWrote to %s.%s\n' % (output, ' '*50))
 | 
						|
  sys.stdout.flush()
 | 
						|
 | 
						|
  RenameToSha1(output)
 | 
						|
 | 
						|
  return 0
 | 
						|
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
  sys.exit(main())
 |