Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright 2012 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 # Extracts a Windows toolchain suitable for building Chrome from various | |
| 6 # downloadable pieces. | |
| 7 | |
| 8 | |
| 9 import os | |
| 10 import shutil | |
| 11 import sys | |
| 12 import tempfile | |
| 13 import urllib2 | |
| 14 | |
| 15 | |
| 16 g_temp_dirs = [] | |
| 17 | |
| 18 | |
| 19 def TempDir(): | |
| 20 """Generate a temporary directory (for downloading or extracting to) and keep | |
| 21 track of the directory that's created for cleaning up later.""" | |
| 22 global g_temp_dirs | |
| 23 temp = tempfile.mkdtemp() | |
| 24 g_temp_dirs.append(temp) | |
| 25 return temp | |
| 26 | |
| 27 | |
| 28 def DeleteAllTempDirs(): | |
| 29 """Remove all temporary directories created by |TempDir()|.""" | |
| 30 global g_temp_dirs | |
| 31 print 'Cleaning up temporaries...' | |
| 32 for temp in g_temp_dirs: | |
| 33 # shutil.rmtree errors out on read only attributes. | |
| 34 os.system('rmdir /s/q "%s"' % temp) | |
| 35 g_temp_dirs = [] | |
| 36 | |
| 37 | |
| 38 def Download(url, local_path): | |
| 39 """Download a large-ish binary file and print some status information while | |
| 40 doing so.""" | |
| 41 sys.stdout.write('Downloading %s...' % url) | |
|
Roger McFarlane (Chromium)
2013/01/02 18:46:23
You're got print and sys.stdout.write() used in va
scottmg
2013/01/02 21:00:47
Yeah, I had that in ps #17, but it also needs sys.
| |
| 42 req = urllib2.urlopen(url) | |
| 43 with open(local_path, 'wb') as file: | |
| 44 while True: | |
| 45 chunk = req.read(1024 * 1024) | |
| 46 if not chunk: | |
| 47 break | |
| 48 file.write(chunk) | |
| 49 sys.stdout.write('.') | |
| 50 print | |
|
Roger McFarlane (Chromium)
2013/01/02 18:46:23
an errant "print"?
It would be nice to track the
scottmg
2013/01/02 21:00:47
was for \n.
| |
| 51 | |
| 52 | |
| 53 def DownloadSDK71Iso(): | |
| 54 sdk7_temp_dir = TempDir() | |
| 55 target_path = os.path.join(sdk7_temp_dir, 'GRMSDKX_EN_DVD.iso') | |
| 56 Download( | |
| 57 ('http://download.microsoft.com/download/' | |
| 58 'F/1/0/F10113F5-B750-4969-A255-274341AC6BCE/GRMSDKX_EN_DVD.iso'), | |
| 59 target_path) | |
| 60 return target_path | |
| 61 | |
| 62 | |
| 63 def DownloadWDKIso(): | |
| 64 wdk_temp_dir = TempDir() | |
| 65 target_path = os.path.join(wdk_temp_dir, 'GRMWDK_EN_7600_1.ISO') | |
| 66 Download( | |
| 67 ('http://download.microsoft.com/download/' | |
| 68 '4/A/2/4A25C7D5-EFBE-4182-B6A9-AE6850409A78/GRMWDK_EN_7600_1.ISO'), | |
| 69 target_path) | |
| 70 return target_path | |
| 71 | |
| 72 | |
| 73 def DownloadWDKUpdate(): | |
| 74 wdk_update_temp_dir = TempDir() | |
| 75 target_path = os.path.join(wdk_update_temp_dir, 'VC-Compiler-KB2519277.exe') | |
| 76 Download( | |
| 77 ('http://download.microsoft.com/download/' | |
| 78 '7/5/0/75040801-126C-4591-BCE4-4CD1FD1499AA/VC-Compiler-KB2519277.exe'), | |
| 79 target_path) | |
| 80 return target_path | |
| 81 | |
| 82 | |
| 83 def DownloadDirectXSDK(): | |
| 84 dxsdk_temp_dir = TempDir() | |
| 85 target_path = os.path.join(dxsdk_temp_dir, 'DXSDK_Jun10.exe') | |
| 86 Download( | |
| 87 ('http://download.microsoft.com/download/' | |
| 88 'A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe'), | |
| 89 target_path) | |
| 90 return target_path | |
| 91 | |
| 92 | |
| 93 def DownloadSDK8(): | |
| 94 """Download the Win8 SDK. This one is slightly different than the simple ones | |
| 95 above. There is no .ISO distribution for the Windows 8 SDK. Rather, a tool | |
| 96 is provided that is a download manager. This is used to download the various | |
| 97 .msis to a target location. Unfortunately, this tool requires elevation for | |
|
Roger McFarlane (Chromium)
2013/01/02 18:46:23
.MSIs or .msi files
scottmg
2013/01/02 21:00:47
Done.
| |
| 98 no obvious reason even when only downloading, so this function will trigger | |
| 99 a UAC elevation if the script is not run from an elevated prompt.""" | |
| 100 sdk_temp_dir = TempDir() | |
| 101 target_path = os.path.join(sdk_temp_dir, 'sdksetup.exe') | |
| 102 standalone_path = os.path.join(sdk_temp_dir, 'Standalone') | |
| 103 Download( | |
| 104 ('http://download.microsoft.com/download/' | |
| 105 'F/1/3/F1300C9C-A120-4341-90DF-8A52509B23AC/standalonesdk/sdksetup.exe'), | |
| 106 target_path) | |
| 107 count = 0 | |
| 108 while count < 5: | |
| 109 rc = os.system(target_path + ' /quiet ' | |
| 110 '/features OptionId.WindowsDesktopSoftwareDevelopmentKit ' | |
| 111 '/layout ' + standalone_path) | |
| 112 if rc == 0: | |
| 113 return standalone_path | |
| 114 break | |
| 115 count += 1 | |
| 116 print 'Windows 8 SDK failed to download, retrying.' | |
| 117 raise SystemExit("After multiple retries, couldn't download Win8 SDK") | |
| 118 | |
| 119 | |
| 120 def ExtractIso(iso_path): | |
| 121 """Use 7zip to extract the contents of the given .iso (or self-extracting | |
| 122 .exe).""" | |
| 123 target_path = TempDir() | |
| 124 print 'Extracting %s...' % iso_path | |
| 125 # TODO(scottmg): Do this (and exe) manually with python code. | |
| 126 if os.system('7z x "%s" -y "-o%s" > nul' % (iso_path, target_path)) != 0: | |
| 127 raise SystemExit("Couldn't extract %s" % iso_path) | |
|
Roger McFarlane (Chromium)
2013/01/02 18:46:23
maybe infer the path to 7z; otherwise, you're assu
scottmg
2013/01/02 21:00:47
Done.
| |
| 128 return target_path | |
| 129 | |
| 130 | |
| 131 ExtractExe = ExtractIso | |
| 132 | |
| 133 | |
| 134 def ExtractMsi(msi_path): | |
| 135 """Use msiexec to extract the contents of the given .msi file.""" | |
| 136 print 'Extracting %s...' % msi_path | |
| 137 target_path = TempDir() | |
| 138 if os.system( | |
| 139 'msiexec /a "%s" /qn TARGETDIR=%s' % (msi_path, target_path)) != 0: | |
| 140 raise SystemExit("Couldn't extract %s" % msi_path) | |
| 141 os.unlink(os.path.join(target_path, os.path.basename(msi_path))) | |
| 142 return target_path | |
| 143 | |
| 144 | |
| 145 def PullFrom(list_of_path_pairs, source_root, target_dir): | |
| 146 """Each pair in |list_of_path_pairs| is (from, to). Join the 'from' with | |
| 147 |source_root| and the 'to' with |target_dir| and perform a recursive copy.""" | |
| 148 for source, destination in list_of_path_pairs: | |
| 149 full_source = os.path.join(source_root, source) | |
| 150 full_target = os.path.join(target_dir, destination) | |
| 151 rc = os.system('robocopy /s "%s" "%s" >nul' % (full_source, full_target)) | |
| 152 if (rc & 8) != 0 or (rc & 16) != 0: | |
| 153 # ref: http://ss64.com/nt/robocopy-exit.html | |
| 154 raise SystemExit("Couldn't copy %s to %s" % (full_source, full_target)) | |
| 155 | |
| 156 | |
| 157 def GenerateSetEnvCmd(target_dir): | |
| 158 """Generate a batch file that gyp expects to exist to set up the compiler | |
| 159 environment. This is normally generated by a full install of the SDK, but we | |
| 160 do it here manually since we do not do a full install.""" | |
| 161 with open(os.path.join( | |
| 162 target_dir, r'win8sdk\bin\SetEnv.cmd'), 'w') as file: | |
| 163 file.write('@echo off\n') | |
| 164 file.write(':: Generated by tools\\win\\toolchain\\toolchain.py.\n') | |
| 165 # Common to x86 and x64 | |
| 166 file.write('set PATH=%s;%%PATH%%\n' % ( | |
| 167 os.path.join(target_dir, r'Common7\IDE'))) | |
| 168 file.write('set INCLUDE=%s;%s;%s\n' % ( | |
| 169 os.path.join(target_dir, r'win8sdk\Include\um'), | |
| 170 os.path.join(target_dir, r'win8sdk\Include\shared'), | |
| 171 os.path.join(target_dir, r'VC\include'))) | |
| 172 file.write('if "%1"=="/x64" goto x64\n') | |
| 173 | |
| 174 # x86 only. | |
| 175 file.write('set PATH=%s;%s;%s;%%PATH%%\n' % ( | |
| 176 os.path.join(target_dir, r'win8sdk\bin\x86'), | |
| 177 os.path.join(target_dir, r'VC\bin'), | |
| 178 os.path.join(target_dir, r'WDK\bin'))) | |
| 179 file.write('set LIB=%s;%s\n' % ( | |
| 180 os.path.join(target_dir, r'VC\lib'), | |
| 181 os.path.join(target_dir, r'win8sdk\Lib\win8\um\x86'))) | |
| 182 file.write('goto done\n') | |
| 183 | |
| 184 # x64 only. | |
| 185 file.write(':x64\n') | |
| 186 file.write('set PATH=%s;%s;%s;%%PATH%%\n' % ( | |
| 187 os.path.join(target_dir, r'win8sdk\bin\x64'), | |
| 188 os.path.join(target_dir, r'VC\bin\amd64'), | |
| 189 os.path.join(target_dir, r'WDK\bin\amd64'))) | |
| 190 file.write('set LIB=%s;%s\n' % ( | |
| 191 os.path.join(target_dir, r'VC\lib\amd64'), | |
| 192 os.path.join(target_dir, r'win8sdk\Lib\win8\um\x64'))) | |
| 193 | |
| 194 file.write(':done\n') | |
| 195 | |
| 196 | |
| 197 def GenerateTopLevelEnv(target_dir): | |
| 198 """Generate a batch file that sets up various environment variables that let | |
| 199 the Chromium build files and gyp find SDKs and tools.""" | |
| 200 with open(os.path.join(target_dir, r'env.bat'), 'w') as file: | |
| 201 file.write('@echo off\n') | |
| 202 file.write(':: Generated by tools\\win\\toolchain\\toolchain.py.\n') | |
| 203 file.write('set GYP_DEFINES=windows_sdk_path="%s" ' | |
| 204 'component=shared_library\n' % ( | |
| 205 os.path.join(target_dir, 'win8sdk'))) | |
| 206 file.write('set GYP_MSVS_VERSION=2010e\n') | |
| 207 file.write('set GYP_MSVS_OVERRIDE_PATH=%s\n' % target_dir) | |
| 208 file.write('set GYP_GENERATORS=ninja\n') | |
| 209 file.write('set WDK_DIR=%s\n' % os.path.join(target_dir, r'WDK')) | |
| 210 file.write('set DXSDK_DIR=%s\n' % os.path.join(target_dir, r'DXSDK')) | |
| 211 file.write('set WindowsSDKDir=%s\n' % | |
| 212 os.path.join(target_dir, r'win8sdk')) | |
| 213 file.write('echo Environment set for toolchain in %s.\n' % target_dir) | |
| 214 file.write('cd /d %s\\..\n' % target_dir) | |
| 215 | |
| 216 | |
| 217 def main(): | |
|
Roger McFarlane (Chromium)
2013/01/02 18:46:23
nit: Can this easiliy be broken down further? mayb
scottmg
2013/01/02 21:00:47
Done.
| |
| 218 try: | |
| 219 target_dir = os.path.abspath('win_toolchain') | |
| 220 os.chdir(os.path.dirname(os.path.abspath(__file__))) | |
| 221 | |
| 222 if len(sys.argv) == 2 and sys.argv[1] == 'local': | |
|
scottmg
2013/01/02 17:32:10
will remove this after reviewed
| |
| 223 sdk_path = r'C:\Users\Scott\Desktop\wee\Standalone' | |
| 224 wdk_iso = r'c:\users\scott\desktop\wee\GRMWDK_EN_7600_1.ISO' | |
| 225 wdk_update = r'c:\users\scott\desktop\wee\VC-Compiler-KB2519277.exe' | |
| 226 sdk7_path = r'C:\Users\Scott\Desktop\wee\GRMSDKX_EN_DVD.ISO' | |
| 227 dxsdk_path = r'C:\Users\Scott\Desktop\wee\DXSDK_Jun10.exe' | |
| 228 else: | |
| 229 # Note that we do the Win8 SDK first so that its silly UAC prompt | |
| 230 # happens before the user wanders off to get coffee. | |
|
Roger McFarlane (Chromium)
2013/01/02 18:46:23
Ha! Nice comment.
| |
| 231 sdk_path = DownloadSDK8() | |
| 232 wdk_iso = DownloadWDKIso() | |
| 233 wdk_update = DownloadWDKUpdate() | |
| 234 sdk7_path = DownloadSDK71Iso() | |
| 235 dxsdk_path = DownloadDirectXSDK() | |
| 236 | |
| 237 extracted_sdk7 = ExtractIso(sdk7_path) | |
| 238 extracted_vc_x86 = \ | |
| 239 ExtractMsi(os.path.join(extracted_sdk7, | |
| 240 r'Setup\vc_stdx86\vc_stdx86.msi')) | |
| 241 extracted_vc_x64 = \ | |
| 242 ExtractMsi(os.path.join(extracted_sdk7, | |
| 243 r'Setup\\vc_stdamd64\vc_stdamd64.msi')) | |
| 244 | |
| 245 extracted_wdk = ExtractIso(wdk_iso) | |
| 246 extracted_buildtools_x86 = \ | |
| 247 ExtractMsi(os.path.join(extracted_wdk, 'WDK\\buildtools_x86fre.msi')) | |
| 248 extracted_buildtools_x64 = \ | |
| 249 ExtractMsi(os.path.join(extracted_wdk, 'WDK\\buildtools_x64fre.msi')) | |
| 250 extracted_libs_x86 = \ | |
| 251 ExtractMsi(os.path.join(extracted_wdk, 'WDK\\libs_x86fre.msi')) | |
| 252 extracted_libs_x64 = \ | |
| 253 ExtractMsi(os.path.join(extracted_wdk, 'WDK\\libs_x64fre.msi')) | |
| 254 extracted_headers = \ | |
| 255 ExtractMsi(os.path.join(extracted_wdk, 'WDK\\headers.msi')) | |
| 256 | |
| 257 extracted_update = ExtractExe(wdk_update) | |
| 258 extracted_update_x86 = \ | |
| 259 ExtractMsi(os.path.join(extracted_update, 'vc_stdx86.msi')) | |
| 260 extracted_update_x64 = \ | |
| 261 ExtractMsi(os.path.join(extracted_update, 'vc_stdamd64.msi')) | |
| 262 | |
| 263 sdk_msi_path = os.path.join( | |
| 264 sdk_path, 'Installers\\Windows Software Development Kit-x86_en-us.msi') | |
| 265 extracted_sdk_path = ExtractMsi(sdk_msi_path) | |
| 266 | |
| 267 sdk_metro_msi_path = os.path.join( | |
| 268 sdk_path, | |
| 269 'Installers', | |
| 270 'Windows Software Development Kit for Metro style Apps-x86_en-us.msi') | |
| 271 extracted_metro_sdk_path = ExtractMsi(sdk_metro_msi_path) | |
| 272 | |
| 273 extracted_dxsdk = ExtractExe(dxsdk_path) | |
| 274 | |
| 275 print 'Pulling together required pieces...' | |
| 276 | |
| 277 # Note that order is important because some of the older ones are | |
| 278 # overwritten by updates. | |
| 279 from_vcupdate_x86 = [ | |
| 280 (r'Program Files\Microsoft Visual Studio 10.0', '.'), | |
| 281 (r'Win\System', r'VC\bin'), | |
| 282 ] | |
| 283 PullFrom(from_vcupdate_x86, extracted_update_x86, target_dir) | |
| 284 | |
| 285 from_vcupdate_x64 = [ | |
| 286 (r'Program Files(64)\Microsoft Visual Studio 10.0', '.'), | |
| 287 (r'Win\System64', r'VC\bin\amd64'), | |
| 288 ] | |
| 289 PullFrom(from_vcupdate_x64, extracted_update_x64, target_dir) | |
| 290 | |
| 291 from_sdk7_x86 =[ | |
| 292 (r'Program Files\Microsoft Visual Studio 10.0', '.'), | |
| 293 (r'Win\System', r'VC\bin'), | |
| 294 ] | |
| 295 PullFrom(from_sdk7_x86, extracted_vc_x86, target_dir) | |
| 296 | |
| 297 from_sdk7_x64 =[ | |
| 298 (r'Program Files(64)\Microsoft Visual Studio 10.0', '.'), | |
| 299 (r'Win\System64', r'VC\bin\amd64'), | |
| 300 ] | |
| 301 PullFrom(from_sdk7_x64, extracted_vc_x64, target_dir) | |
| 302 | |
| 303 from_sdk = [(r'Windows Kits\8.0', r'win8sdk')] | |
| 304 PullFrom(from_sdk, extracted_sdk_path, target_dir) | |
| 305 | |
| 306 from_metro_sdk = [(r'Windows Kits\8.0', r'win8sdk')] | |
| 307 PullFrom(from_sdk, extracted_metro_sdk_path, target_dir) | |
| 308 | |
| 309 from_buildtools_x86 = [ | |
| 310 (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\x86', r'WDK\bin'), | |
| 311 (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\amd64', r'WDK\bin'), | |
| 312 ] | |
| 313 PullFrom(from_buildtools_x86, extracted_buildtools_x86, target_dir) | |
| 314 | |
| 315 from_buildtools_x64 = [ | |
| 316 (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\amd64', r'WDK\bin'), | |
| 317 ] | |
| 318 PullFrom(from_buildtools_x64, extracted_buildtools_x64, target_dir) | |
| 319 | |
| 320 from_libs_x86 = [ | |
| 321 (r'WinDDK\7600.16385.win7_wdk.100208-1538\lib', r'WDK\lib'), | |
| 322 ] | |
| 323 PullFrom(from_libs_x86, extracted_libs_x86, target_dir) | |
| 324 | |
| 325 from_libs_x64 = [ | |
| 326 (r'WinDDK\7600.16385.win7_wdk.100208-1538\lib', r'WDK\lib'), | |
| 327 ] | |
| 328 PullFrom(from_libs_x64, extracted_libs_x64, target_dir) | |
| 329 | |
| 330 from_headers = [ | |
| 331 (r'WinDDK\7600.16385.win7_wdk.100208-1538\inc', r'WDK\inc'), | |
| 332 ] | |
| 333 PullFrom(from_headers, extracted_headers, target_dir) | |
| 334 | |
| 335 from_dxsdk = [ | |
| 336 (r'DXSDK\Include', r'DXSDK\Include'), | |
| 337 (r'DXSDK\Lib', r'DXSDK\Lib'), | |
| 338 (r'DXSDK\Redist', r'DXSDK\Redist'), | |
| 339 ] | |
| 340 PullFrom(from_dxsdk, extracted_dxsdk, target_dir) | |
| 341 | |
| 342 # Apply patch from | |
|
Roger McFarlane (Chromium)
2013/01/02 18:46:23
put this in its own function?
scottmg
2013/01/02 21:00:47
Done.
| |
| 343 # http://www.chromium.org/developers/how-tos/build-instructions-windows | |
| 344 # for asyncinfo.h: | |
| 345 print 'Patching asyncinfo.h...' | |
| 346 asyncinfo_h_path = os.path.join( | |
| 347 target_dir, r'win8sdk\Include\winrt\asyncinfo.h') | |
| 348 asyncinfo_h = open(asyncinfo_h_path, 'rb').read() | |
|
Roger McFarlane (Chromium)
2013/01/02 18:46:23
Do the read inside a with clause?
scottmg
2013/01/02 21:00:47
Sure. (fwiw, in "regular" CPython, it's guaranteed
| |
| 349 patched = asyncinfo_h.replace( | |
| 350 'enum class AsyncStatus {', 'enum AsyncStatus {') | |
| 351 open(asyncinfo_h_path, 'wb').write(patched) | |
|
Roger McFarlane (Chromium)
2013/01/02 18:46:23
Do the write inside a with clause?
scottmg
2013/01/02 21:00:47
Done.
| |
| 352 | |
| 353 GenerateSetEnvCmd(target_dir) | |
| 354 GenerateTopLevelEnv(target_dir) | |
| 355 finally: | |
| 356 DeleteAllTempDirs() | |
| 357 | |
| 358 print ('\nIn a (clean) cmd shell, you can now run\n\n' | |
| 359 ' %s\\env.bat\n\n' | |
| 360 'then\n\n' | |
| 361 " gclient runhooks (or gclient sync if you haven't pulled deps yet)\n" | |
| 362 ' ninja -C out\Debug chrome\n\n' | |
| 363 'Note that this script intentionally does not modify any global\n' | |
| 364 'settings like the registry, or system environment variables, so you\n' | |
| 365 'will need to run the above env.bat whenever you start a new\n' | |
| 366 'shell.\n' % target_dir) | |
| 367 | |
| 368 | |
| 369 if __name__ == '__main__': | |
| 370 main() | |
| OLD | NEW |