Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2020)

Unified Diff: tools/win/toolchain/toolchain.py

Issue 11633012: tools addition to automate setting up windows toolchain (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: shorten url Created 7 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/win/toolchain/7z/LICENSE ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/win/toolchain/toolchain.py
diff --git a/tools/win/toolchain/toolchain.py b/tools/win/toolchain/toolchain.py
new file mode 100644
index 0000000000000000000000000000000000000000..56d29ca9903f23eeb4257e99ce37dcf15070aef6
--- /dev/null
+++ b/tools/win/toolchain/toolchain.py
@@ -0,0 +1,474 @@
+# Copyright 2012 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.
+
+# Extracts a Windows toolchain suitable for building Chrome from various
+# downloadable pieces.
+
+
+from optparse import OptionParser
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import urllib2
+
+
+g_temp_dirs = []
+
+
+def RunOrDie(command):
+ rc = subprocess.call(command, shell=True)
+ if rc != 0:
+ raise SystemExit('%s failed.' % command)
+
+
+def TempDir():
+ """Generate a temporary directory (for downloading or extracting to) and keep
+ track of the directory that's created for cleaning up later."""
+ global g_temp_dirs
+ temp = tempfile.mkdtemp()
+ g_temp_dirs.append(temp)
+ return temp
+
+
+def DeleteAllTempDirs():
+ """Remove all temporary directories created by |TempDir()|."""
+ global g_temp_dirs
+ if g_temp_dirs:
+ sys.stdout.write('Cleaning up temporaries...\n')
+ for temp in g_temp_dirs:
+ # shutil.rmtree errors out on read only attributes.
+ RunOrDie('rmdir /s/q "%s"' % temp)
+ g_temp_dirs = []
+
+
+def Download(url, local_path):
+ """Download a large-ish binary file and print some status information while
+ doing so."""
+ sys.stdout.write('Downloading %s...' % url)
+ req = urllib2.urlopen(url)
+ content_length = int(req.headers.get('Content-Length', 0))
+ bytes_read = 0
+ with open(local_path, 'wb') as file:
+ while True:
+ chunk = req.read(1024 * 1024)
+ if not chunk:
+ break
+ bytes_read += len(chunk)
+ file.write(chunk)
+ sys.stdout.write('.')
+ sys.stdout.write('\n')
+ if content_length and content_length != bytes_read:
+ raise SystemExit('Got incorrect number of bytes downloading %s' % url)
+
+
+def DownloadSDK71Iso():
+ sdk7_temp_dir = TempDir()
+ target_path = os.path.join(sdk7_temp_dir, 'GRMSDKX_EN_DVD.iso')
+ Download(
+ ('http://download.microsoft.com/download/'
+ 'F/1/0/F10113F5-B750-4969-A255-274341AC6BCE/GRMSDKX_EN_DVD.iso'),
+ target_path)
+ return target_path
+
+
+def DownloadWDKIso():
+ wdk_temp_dir = TempDir()
+ target_path = os.path.join(wdk_temp_dir, 'GRMWDK_EN_7600_1.ISO')
+ Download(
+ ('http://download.microsoft.com/download/'
+ '4/A/2/4A25C7D5-EFBE-4182-B6A9-AE6850409A78/GRMWDK_EN_7600_1.ISO'),
+ target_path)
+ return target_path
+
+
+def DownloadSDKUpdate():
+ sdk_update_temp_dir = TempDir()
+ target_path = os.path.join(sdk_update_temp_dir, 'VC-Compiler-KB2519277.exe')
+ Download(
+ ('http://download.microsoft.com/download/'
+ '7/5/0/75040801-126C-4591-BCE4-4CD1FD1499AA/VC-Compiler-KB2519277.exe'),
+ target_path)
+ return target_path
+
+
+def DownloadDirectXSDK():
+ dxsdk_temp_dir = TempDir()
+ target_path = os.path.join(dxsdk_temp_dir, 'DXSDK_Jun10.exe')
+ Download(
+ ('http://download.microsoft.com/download/'
+ 'A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe'),
+ target_path)
+ return target_path
+
+
+def DownloadSDK8():
+ """Download the Win8 SDK. This one is slightly different than the simple
+ ones above. There is no .ISO distribution for the Windows 8 SDK. Rather, a
+ tool is provided that is a download manager. This is used to download the
+ various .msi files to a target location. Unfortunately, this tool requires
+ elevation for no obvious reason even when only downloading, so this function
+ will trigger a UAC elevation if the script is not run from an elevated
+ prompt."""
+ sdk_temp_dir = TempDir()
+ target_path = os.path.join(sdk_temp_dir, 'sdksetup.exe')
+ standalone_path = os.path.join(sdk_temp_dir, 'Standalone')
+ Download(
+ ('http://download.microsoft.com/download/'
+ 'F/1/3/F1300C9C-A120-4341-90DF-8A52509B23AC/standalonesdk/sdksetup.exe'),
+ target_path)
+ sys.stdout.write(
+ 'Running sdksetup.exe to download Win8 SDK (may request elevation)...\n')
+ count = 0
+ while count < 5:
+ rc = RunOrDie(target_path + ' /quiet '
+ '/features OptionId.WindowsDesktopSoftwareDevelopmentKit '
+ '/layout ' + standalone_path)
+ if rc == 0:
+ return standalone_path
+ break
+ count += 1
+ sys.stdout.write('Windows 8 SDK failed to download, retrying.\n')
+ raise SystemExit("After multiple retries, couldn't download Win8 SDK")
+
+
+class SourceImages(object):
+ def __init__(self, sdk8_path, wdk_iso, sdk7_update, sdk7_path, dxsdk_path):
+ self.sdk8_path = sdk8_path
+ self.wdk_iso = wdk_iso
+ self.sdk7_update = sdk7_update
+ self.sdk7_path = sdk7_path
+ self.dxsdk_path = dxsdk_path
+
+
+def GetSourceImages():
+ """Download all distribution archives for the components we need."""
+ if len(sys.argv) >= 2 and sys.argv[1] == 'local':
+ return SourceImages(
+ sdk8_path=r'C:\Users\Scott\Desktop\wee\Standalone',
+ wdk_iso=r'c:\users\scott\desktop\wee\GRMWDK_EN_7600_1.ISO',
+ sdk7_update=r'c:\users\scott\desktop\wee\VC-Compiler-KB2519277.exe',
+ sdk7_path=r'C:\Users\Scott\Desktop\wee\GRMSDKX_EN_DVD.ISO',
+ dxsdk_path=r'C:\Users\Scott\Desktop\wee\DXSDK_Jun10.exe')
+ else:
+ # Note that we do the Win8 SDK first so that its silly UAC prompt
+ # happens before the user wanders off to get coffee.
+ sdk8_path = DownloadSDK8()
+ wdk_iso = DownloadWDKIso()
+ sdk7_update = DownloadSDKUpdate()
+ sdk7_path = DownloadSDK71Iso()
+ dxsdk_path = DownloadDirectXSDK()
+ return SourceImages(sdk8_path, wdk_iso, sdk7_update, sdk7_path, dxsdk_path)
+
+
+def ExtractIso(iso_path):
+ """Use 7zip to extract the contents of the given .iso (or self-extracting
+ .exe)."""
+ target_path = TempDir()
+ sys.stdout.write('Extracting %s...\n' % iso_path)
+ # TODO(scottmg): Do this (and exe) manually with python code.
+ # Note that at the beginning of main() we set the working directory to 7z's
+ # location.
+ RunOrDie('7z x "%s" -y "-o%s" >nul' % (iso_path, target_path))
+ return target_path
+
+
+ExtractExe = ExtractIso
+
+
+def ExtractMsi(msi_path):
+ """Use msiexec to extract the contents of the given .msi file."""
+ sys.stdout.write('Extracting %s...\n' % msi_path)
+ target_path = TempDir()
+ RunOrDie('msiexec /a "%s" /qn TARGETDIR="%s"' % (msi_path, target_path))
+ return target_path
+
+
+class ExtractedComponents(object):
+ def __init__(self,
+ vc_x86, vc_x64,
+ buildtools_x86, buildtools_x64, libs_x86, libs_x64, headers,
+ update_x86, update_x64,
+ sdk_path, metro_sdk_path,
+ dxsdk):
+ self.vc_x86 = vc_x86
+ self.vc_x64 = vc_x64
+ self.buildtools_x86 = buildtools_x86
+ self.buildtools_x64 = buildtools_x64
+ self.libs_x86 = libs_x86
+ self.libs_x64 = libs_x64
+ self.headers = headers
+ self.update_x86 = update_x86
+ self.update_x64 = update_x64
+ self.sdk_path = sdk_path
+ self.metro_sdk_path = metro_sdk_path
+ self.dxsdk = dxsdk
+
+
+def ExtractComponents(images):
+ """Given the paths to the images, extract the required parts, and return the
+ an object containing paths to all the pieces."""
+ extracted_sdk7 = ExtractIso(images.sdk7_path)
+ extracted_vc_x86 = \
+ ExtractMsi(os.path.join(extracted_sdk7,
+ r'Setup\vc_stdx86\vc_stdx86.msi'))
+ extracted_vc_x64 = \
+ ExtractMsi(os.path.join(extracted_sdk7,
+ r'Setup\vc_stdamd64\vc_stdamd64.msi'))
+
+ extracted_wdk = ExtractIso(images.wdk_iso)
+ extracted_buildtools_x86 = \
+ ExtractMsi(os.path.join(extracted_wdk, r'WDK\buildtools_x86fre.msi'))
+ extracted_buildtools_x64 = \
+ ExtractMsi(os.path.join(extracted_wdk, r'WDK\buildtools_x64fre.msi'))
+ extracted_libs_x86 = \
+ ExtractMsi(os.path.join(extracted_wdk, r'WDK\libs_x86fre.msi'))
+ extracted_libs_x64 = \
+ ExtractMsi(os.path.join(extracted_wdk, r'WDK\libs_x64fre.msi'))
+ extracted_headers = \
+ ExtractMsi(os.path.join(extracted_wdk, r'WDK\headers.msi'))
+
+ extracted_update = ExtractExe(images.sdk7_update)
+ extracted_update_x86 = \
+ ExtractMsi(os.path.join(extracted_update, 'vc_stdx86.msi'))
+ extracted_update_x64 = \
+ ExtractMsi(os.path.join(extracted_update, 'vc_stdamd64.msi'))
+
+ sdk_msi_path = os.path.join(
+ images.sdk8_path,
+ r'Installers\Windows Software Development Kit-x86_en-us.msi')
+ extracted_sdk_path = ExtractMsi(sdk_msi_path)
+
+ sdk_metro_msi_path = os.path.join(
+ images.sdk8_path,
+ 'Installers',
+ 'Windows Software Development Kit for Metro style Apps-x86_en-us.msi')
+ extracted_metro_sdk_path = ExtractMsi(sdk_metro_msi_path)
+
+ extracted_dxsdk = ExtractExe(images.dxsdk_path)
+
+ return ExtractedComponents(
+ vc_x86=extracted_vc_x86,
+ vc_x64=extracted_vc_x64,
+ buildtools_x86=extracted_buildtools_x86,
+ buildtools_x64=extracted_buildtools_x64,
+ libs_x86=extracted_libs_x86,
+ libs_x64=extracted_libs_x64,
+ headers=extracted_headers,
+ update_x86=extracted_update_x86,
+ update_x64=extracted_update_x64,
+ sdk_path=extracted_sdk_path,
+ metro_sdk_path=extracted_metro_sdk_path,
+ dxsdk=extracted_dxsdk)
+
+
+def PullFrom(list_of_path_pairs, source_root, target_dir):
+ """Each pair in |list_of_path_pairs| is (from, to). Join the 'from' with
+ |source_root| and the 'to' with |target_dir| and perform a recursive copy."""
+ for source, destination in list_of_path_pairs:
+ full_source = os.path.join(source_root, source)
+ full_target = os.path.join(target_dir, destination)
+ rc = os.system('robocopy /s "%s" "%s" >nul' % (full_source, full_target))
+ if (rc & 8) != 0 or (rc & 16) != 0:
+ # ref: http://ss64.com/nt/robocopy-exit.html
+ raise SystemExit("Couldn't copy %s to %s" % (full_source, full_target))
+
+
+def CopyToFinalLocation(extracted, target_dir):
+ """Copy all the directories we need to the target location."""
+ sys.stdout.write('Pulling together required pieces...\n')
+
+ # Note that order is important because some of the older ones are
+ # overwritten by updates.
+ from_sdk = [(r'Windows Kits\8.0', r'win8sdk')]
+ PullFrom(from_sdk, extracted.sdk_path, target_dir)
+
+ from_metro_sdk = [(r'Windows Kits\8.0', r'win8sdk')]
+ PullFrom(from_sdk, extracted.metro_sdk_path, target_dir)
+
+ from_buildtools_x86 = [
+ (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\x86', r'WDK\bin'),
+ (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\amd64', r'WDK\bin'),
+ ]
+ PullFrom(from_buildtools_x86, extracted.buildtools_x86, target_dir)
+
+ from_buildtools_x64 = [
+ (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\amd64', r'WDK\bin'),
+ ]
+ PullFrom(from_buildtools_x64, extracted.buildtools_x64, target_dir)
+
+ from_libs_x86 = [
+ (r'WinDDK\7600.16385.win7_wdk.100208-1538\lib', r'WDK\lib'),
+ ]
+ PullFrom(from_libs_x86, extracted.libs_x86, target_dir)
+
+ from_libs_x64 = [
+ (r'WinDDK\7600.16385.win7_wdk.100208-1538\lib', r'WDK\lib'),
+ ]
+ PullFrom(from_libs_x64, extracted.libs_x64, target_dir)
+
+ from_headers = [
+ (r'WinDDK\7600.16385.win7_wdk.100208-1538\inc', r'WDK\inc'),
+ ]
+ PullFrom(from_headers, extracted.headers, target_dir)
+
+ # The compiler update to get the SP1 x86 compiler is a bit of a mess. See
+ # http://goo.gl/n1DeO. The summary is that update for the standalone
+ # compiler binary installs a broken set of headers. So, we need to pull the
+ # new binaries from the update, but keep the older set of headers.
+
+ from_vcupdate_x86 = [
+ (r'Program Files\Microsoft Visual Studio 10.0', '.'),
+ (r'Win\System', r'VC\bin'),
+ ]
+ PullFrom(from_vcupdate_x86, extracted.update_x86, target_dir)
+
+ from_vcupdate_x64 = [
+ (r'Program Files(64)\Microsoft Visual Studio 10.0', '.'),
+ (r'Win\System64', r'VC\bin\amd64'),
+ ]
+ PullFrom(from_vcupdate_x64, extracted.update_x64, target_dir)
+
+ from_sdk7_x86 = [
+ (r'Program Files\Microsoft Visual Studio 10.0', '.'),
+ (r'Win\System', r'VC\bin'),
+ ]
+ PullFrom(from_sdk7_x86, extracted.vc_x86, target_dir)
+
+ from_sdk7_x64 =[
+ (r'Program Files(64)\Microsoft Visual Studio 10.0', '.'),
+ (r'Win\System64', r'VC\bin\amd64'),
+ ]
+ PullFrom(from_sdk7_x64, extracted.vc_x64, target_dir)
+
+ # Now, re-get just the binaries from the update.
+ from_vcupdate_x86 = [
+ (r'Program Files\Microsoft Visual Studio 10.0\VC\bin', r'VC\bin'),
+ ]
+ PullFrom(from_vcupdate_x86, extracted.update_x86, target_dir)
+
+ from_vcupdate_x64 = [
+ (r'Program Files(64)\Microsoft Visual Studio 10.0\VC\bin', r'VC\bin'),
+ ]
+ PullFrom(from_vcupdate_x64, extracted.update_x64, target_dir)
+
+ from_dxsdk = [
+ (r'DXSDK\Include', r'DXSDK\Include'),
+ (r'DXSDK\Lib', r'DXSDK\Lib'),
+ (r'DXSDK\Redist', r'DXSDK\Redist'),
+ ]
+ PullFrom(from_dxsdk, extracted.dxsdk, target_dir)
+
+
+def PatchAsyncInfo(target_dir):
+ """Apply patch from
+ http://www.chromium.org/developers/how-tos/build-instructions-windows for
+ asyncinfo.h."""
+ sys.stdout.write('Patching asyncinfo.h...\n')
+ asyncinfo_h_path = os.path.join(
+ target_dir, r'win8sdk\Include\winrt\asyncinfo.h')
+ with open(asyncinfo_h_path, 'rb') as f:
+ asyncinfo_h = f.read()
+ patched = asyncinfo_h.replace(
+ 'enum class AsyncStatus {', 'enum AsyncStatus {')
+ with open(asyncinfo_h_path, 'wb') as f:
+ f.write(patched)
+
+
+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'win8sdk\bin\SetEnv.cmd'), 'w') as file:
+ file.write('@echo off\n')
+ file.write(':: Generated by tools\\win\\toolchain\\toolchain.py.\n')
+ # Common to x86 and x64
+ file.write('set PATH=%s;%%PATH%%\n' % (
+ os.path.join(target_dir, r'Common7\IDE')))
+ file.write('set INCLUDE=%s;%s;%s\n' % (
+ os.path.join(target_dir, r'win8sdk\Include\um'),
+ os.path.join(target_dir, r'win8sdk\Include\shared'),
+ os.path.join(target_dir, r'VC\include')))
+ file.write('if "%1"=="/x64" goto x64\n')
+
+ # x86 only.
+ file.write('set PATH=%s;%s;%s;%%PATH%%\n' % (
+ os.path.join(target_dir, r'win8sdk\bin\x86'),
+ os.path.join(target_dir, r'VC\bin'),
+ os.path.join(target_dir, r'WDK\bin')))
+ file.write('set LIB=%s;%s\n' % (
+ os.path.join(target_dir, r'VC\lib'),
+ os.path.join(target_dir, r'win8sdk\Lib\win8\um\x86')))
+ file.write('goto done\n')
+
+ # x64 only.
+ file.write(':x64\n')
+ file.write('set PATH=%s;%s;%s;%%PATH%%\n' % (
+ os.path.join(target_dir, r'win8sdk\bin\x64'),
+ os.path.join(target_dir, r'VC\bin\amd64'),
+ os.path.join(target_dir, r'WDK\bin\amd64')))
+ file.write('set LIB=%s;%s\n' % (
+ os.path.join(target_dir, r'VC\lib\amd64'),
+ os.path.join(target_dir, r'win8sdk\Lib\win8\um\x64')))
+
+ file.write(':done\n')
+
+
+def GenerateTopLevelEnv(target_dir):
+ """Generate a batch file that sets up various environment variables that let
+ the Chromium build files and gyp find SDKs and tools."""
+ with open(os.path.join(target_dir, r'env.bat'), 'w') as file:
+ file.write('@echo off\n')
+ file.write(':: Generated by tools\\win\\toolchain\\toolchain.py.\n')
+ file.write('set GYP_DEFINES=windows_sdk_path="%s" '
+ 'component=shared_library\n' % (
+ os.path.join(target_dir, 'win8sdk')))
+ file.write('set GYP_MSVS_VERSION=2010e\n')
+ file.write('set GYP_MSVS_OVERRIDE_PATH=%s\n' % target_dir)
+ file.write('set GYP_GENERATORS=ninja\n')
+ file.write('set WDK_DIR=%s\n' % os.path.join(target_dir, r'WDK'))
+ file.write('set DXSDK_DIR=%s\n' % os.path.join(target_dir, r'DXSDK'))
+ file.write('set WindowsSDKDir=%s\n' %
+ os.path.join(target_dir, r'win8sdk'))
+ file.write('echo Environment set for toolchain in %s.\n' % target_dir)
+ file.write('cd /d %s\\..\n' % target_dir)
+
+
+def main():
+ try:
+ parser = OptionParser()
+ parser.add_option('--targetdir', metavar='DIR',
+ help='put toolchain into DIR',
+ default=os.path.abspath('win_toolchain'))
+ options, args = parser.parse_args()
+ target_dir = os.path.abspath(options.targetdir)
+ # Set the working directory to 7z subdirectory. 7-zip doesn't find its
+ # codec dll very well, so this is the simplest way to make sure it runs
+ # correctly, as we don't otherwise care about working directory.
+ os.chdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), '7z'))
+ images = GetSourceImages()
+ extracted = ExtractComponents(images)
+ CopyToFinalLocation(extracted, target_dir)
+ PatchAsyncInfo(target_dir)
+ GenerateSetEnvCmd(target_dir)
+ GenerateTopLevelEnv(target_dir)
+ finally:
+ DeleteAllTempDirs()
+
+ sys.stdout.write(
+ '\nIn a (clean) cmd shell, you can now run\n\n'
+ ' %s\\env.bat\n\n'
+ 'then\n\n'
+ " gclient runhooks (or gclient sync if you haven't pulled deps yet)\n"
+ ' ninja -C out\Debug chrome\n\n'
+ 'Note that this script intentionally does not modify any global\n'
+ 'settings like the registry, or system environment variables, so you\n'
+ 'will need to run the above env.bat whenever you start a new\n'
+ 'shell.\n\n' % target_dir)
+
+
+if __name__ == '__main__':
+ main()
« no previous file with comments | « tools/win/toolchain/7z/LICENSE ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698