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 9import ctypes 10from optparse import OptionParser 11import os 12import shutil 13import subprocess 14import sys 15import tempfile 16import urllib2 17 18 19g_temp_dirs = [] 20 21 22def GetLongPathName(path): 23 """Converts any 8dot3 names in the path to the full name.""" 24 buf = ctypes.create_unicode_buffer(260) 25 size = ctypes.windll.kernel32.GetLongPathNameW(unicode(path), buf, 260) 26 if (size > 260): 27 raise SystemExit('Long form of path longer than 260 chars: %s' % path) 28 return buf.value 29 30 31def RunOrDie(command): 32 rc = subprocess.call(command, shell=True) 33 if rc != 0: 34 raise SystemExit('%s failed.' % command) 35 36 37def TempDir(): 38 """Generate a temporary directory (for downloading or extracting to) and keep 39 track of the directory that's created for cleaning up later.""" 40 global g_temp_dirs 41 temp = tempfile.mkdtemp() 42 g_temp_dirs.append(temp) 43 return temp 44 45 46def DeleteAllTempDirs(): 47 """Remove all temporary directories created by |TempDir()|.""" 48 global g_temp_dirs 49 if g_temp_dirs: 50 sys.stdout.write('Cleaning up temporaries...\n') 51 for temp in g_temp_dirs: 52 # shutil.rmtree errors out on read only attributes. 53 RunOrDie('rmdir /s/q "%s"' % temp) 54 g_temp_dirs = [] 55 56 57def Download(url, local_path): 58 """Download a large-ish binary file and print some status information while 59 doing so.""" 60 sys.stdout.write('Downloading %s...\n' % url) 61 req = urllib2.urlopen(url) 62 content_length = int(req.headers.get('Content-Length', 0)) 63 bytes_read = 0 64 terminator = '\r' if sys.stdout.isatty() else '\n' 65 with open(local_path, 'wb') as file: 66 while True: 67 chunk = req.read(1024 * 1024) 68 if not chunk: 69 break 70 bytes_read += len(chunk) 71 file.write(chunk) 72 sys.stdout.write('... %d/%d%s' % (bytes_read, content_length, terminator)) 73 sys.stdout.flush() 74 sys.stdout.write('\n') 75 if content_length and content_length != bytes_read: 76 raise SystemExit('Got incorrect number of bytes downloading %s' % url) 77 78 79def DownloadSDK71Iso(): 80 sdk7_temp_dir = TempDir() 81 target_path = os.path.join(sdk7_temp_dir, 'GRMSDKX_EN_DVD.iso') 82 Download( 83 ('http://download.microsoft.com/download/' 84 'F/1/0/F10113F5-B750-4969-A255-274341AC6BCE/GRMSDKX_EN_DVD.iso'), 85 target_path) 86 return target_path 87 88 89def DownloadWDKIso(): 90 wdk_temp_dir = TempDir() 91 target_path = os.path.join(wdk_temp_dir, 'GRMWDK_EN_7600_1.ISO') 92 Download( 93 ('http://download.microsoft.com/download/' 94 '4/A/2/4A25C7D5-EFBE-4182-B6A9-AE6850409A78/GRMWDK_EN_7600_1.ISO'), 95 target_path) 96 return target_path 97 98 99def DownloadSDKUpdate(): 100 sdk_update_temp_dir = TempDir() 101 target_path = os.path.join(sdk_update_temp_dir, 'VC-Compiler-KB2519277.exe') 102 Download( 103 ('http://download.microsoft.com/download/' 104 '7/5/0/75040801-126C-4591-BCE4-4CD1FD1499AA/VC-Compiler-KB2519277.exe'), 105 target_path) 106 return target_path 107 108 109def DownloadDirectXSDK(): 110 dxsdk_temp_dir = TempDir() 111 target_path = os.path.join(dxsdk_temp_dir, 'DXSDK_Jun10.exe') 112 Download( 113 ('http://download.microsoft.com/download/' 114 'A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe'), 115 target_path) 116 return target_path 117 118 119def DownloadVS2012ExIso(): 120 ex_temp_dir = TempDir() 121 target_path = os.path.join(ex_temp_dir, 'VS2012_WDX_ENU.iso') 122 Download( 123 ('http://download.microsoft.com/download/' 124 '1/F/5/1F519CC5-0B90-4EA3-8159-33BFB97EF4D9/VS2012_WDX_ENU.iso'), 125 target_path) 126 return target_path 127 128 129def DownloadSDK8(): 130 """Download the Win8 SDK. This one is slightly different than the simple 131 ones above. There is no .ISO distribution for the Windows 8 SDK. Rather, a 132 tool is provided that is a download manager. This is used to download the 133 various .msi files to a target location. Unfortunately, this tool requires 134 elevation for no obvious reason even when only downloading, so this function 135 will trigger a UAC elevation if the script is not run from an elevated 136 prompt.""" 137 # Use the long path name here because because 8dot3 names don't seem to work. 138 sdk_temp_dir = GetLongPathName(TempDir()) 139 target_path = os.path.join(sdk_temp_dir, 'sdksetup.exe') 140 standalone_path = os.path.join(sdk_temp_dir, 'Standalone') 141 Download( 142 ('http://download.microsoft.com/download/' 143 'F/1/3/F1300C9C-A120-4341-90DF-8A52509B23AC/standalonesdk/sdksetup.exe'), 144 target_path) 145 sys.stdout.write( 146 'Running sdksetup.exe to download Win8 SDK (may request elevation)...\n') 147 count = 0 148 while count < 5: 149 rc = os.system(target_path + ' /quiet ' 150 '/features OptionId.WindowsDesktopSoftwareDevelopmentKit ' 151 '/layout ' + standalone_path) 152 if rc == 0: 153 return standalone_path 154 count += 1 155 sys.stdout.write('Windows 8 SDK failed to download, retrying.\n') 156 raise SystemExit("After multiple retries, couldn't download Win8 SDK") 157 158 159def DownloadVS2012Update3(): 160 """Download Update3 to VS2012. See notes in DownloadSDK8.""" 161 update3_dir = TempDir() 162 target_path = os.path.join(update3_dir, 'VS2012.3.iso') 163 Download( 164 ('http://download.microsoft.com/download/' 165 'D/4/8/D48D1AC2-A297-4C9E-A9D0-A218E6609F06/VS2012.3.iso'), 166 target_path) 167 return target_path 168 169 170class SourceImages2010(object): 171 def __init__(self, sdk8_path, wdk_iso, sdk7_update, sdk7_path, dxsdk_path): 172 self.sdk8_path = sdk8_path 173 self.wdk_iso = wdk_iso 174 self.sdk7_update = sdk7_update 175 self.sdk7_path = sdk7_path 176 self.dxsdk_path = dxsdk_path 177 178 179def GetSourceImages2010(local_dir): 180 """Download all distribution archives for the components we need.""" 181 if local_dir: 182 return SourceImages2010( 183 sdk8_path=os.path.join(local_dir, 'Standalone'), 184 wdk_iso=os.path.join(local_dir, 'GRMWDK_EN_7600_1.ISO'), 185 sdk7_update=os.path.join(local_dir, 'VC-Compiler-KB2519277.exe'), 186 sdk7_path=os.path.join(local_dir, 'GRMSDKX_EN_DVD.ISO'), 187 dxsdk_path=os.path.join(local_dir, 'DXSDK_Jun10.exe')) 188 else: 189 # Note that we do the Win8 SDK first so that its silly UAC prompt 190 # happens before the user wanders off to get coffee. 191 sdk8_path = DownloadSDK8() 192 wdk_iso = DownloadWDKIso() 193 sdk7_update = DownloadSDKUpdate() 194 sdk7_path = DownloadSDK71Iso() 195 dxsdk_path = DownloadDirectXSDK() 196 return SourceImages2010( 197 sdk8_path, wdk_iso, sdk7_update, sdk7_path, dxsdk_path) 198 199 200class SourceImages2012(): 201 def __init__(self, ex_path, update_path, wdk_iso): 202 self.ex_path = ex_path 203 self.update_path = update_path 204 self.wdk_iso = wdk_iso 205 206 207def GetSourceImages2012(local_dir): 208 """Download all distribution archives for the components we need.""" 209 if local_dir: 210 return SourceImages2012( 211 ex_path=os.path.join(local_dir, 'VS2012_WDX_ENU.iso'), 212 update_path=os.path.join(local_dir, 'VS2012.3.iso'), 213 wdk_iso=os.path.join(local_dir, 'GRMWDK_EN_7600_1.ISO')) 214 else: 215 ex_path = DownloadVS2012ExIso() 216 wdk_iso = DownloadWDKIso() 217 update_path = DownloadVS2012Update3() 218 return SourceImages2012( 219 ex_path=ex_path, 220 update_path=update_path, 221 wdk_iso=wdk_iso) 222 223 224def ExtractIso(iso_path): 225 """Use 7zip to extract the contents of the given .iso (or self-extracting 226 .exe).""" 227 target_path = TempDir() 228 sys.stdout.write('Extracting %s...\n' % iso_path) 229 sys.stdout.flush() 230 # TODO(scottmg): Do this (and exe) manually with python code. 231 # Note that at the beginning of main() we set the working directory to 7z's 232 # location. 233 RunOrDie('7z x "%s" -y "-o%s" >nul' % (iso_path, target_path)) 234 return target_path 235 236 237ExtractExe = ExtractIso 238 239 240def ExtractMsi(msi_path): 241 """Use msiexec to extract the contents of the given .msi file.""" 242 sys.stdout.write('Extracting %s...\n' % msi_path) 243 target_path = TempDir() 244 RunOrDie('msiexec /a "%s" /qn TARGETDIR="%s"' % (msi_path, target_path)) 245 return target_path 246 247 248class ExtractedComponents2010(object): 249 def __init__(self, 250 vc_x86, vc_x64, 251 buildtools_x86, buildtools_x64, libs_x86, libs_x64, headers, 252 update_x86, update_x64, 253 sdk_path, metro_sdk_path, 254 dxsdk): 255 self.vc_x86 = vc_x86 256 self.vc_x64 = vc_x64 257 self.buildtools_x86 = buildtools_x86 258 self.buildtools_x64 = buildtools_x64 259 self.libs_x86 = libs_x86 260 self.libs_x64 = libs_x64 261 self.headers = headers 262 self.update_x86 = update_x86 263 self.update_x64 = update_x64 264 self.sdk_path = sdk_path 265 self.metro_sdk_path = metro_sdk_path 266 self.dxsdk = dxsdk 267 268 269def ExtractComponents2010(images): 270 """Given the paths to the images, extract the required parts, and return 271 an object containing paths to all the pieces.""" 272 extracted_sdk7 = ExtractIso(images.sdk7_path) 273 extracted_vc_x86 = \ 274 ExtractMsi(os.path.join(extracted_sdk7, 275 r'Setup\vc_stdx86\vc_stdx86.msi')) 276 extracted_vc_x64 = \ 277 ExtractMsi(os.path.join(extracted_sdk7, 278 r'Setup\vc_stdamd64\vc_stdamd64.msi')) 279 280 extracted_wdk = ExtractIso(images.wdk_iso) 281 extracted_buildtools_x86 = \ 282 ExtractMsi(os.path.join(extracted_wdk, r'WDK\buildtools_x86fre.msi')) 283 extracted_buildtools_x64 = \ 284 ExtractMsi(os.path.join(extracted_wdk, r'WDK\buildtools_x64fre.msi')) 285 extracted_libs_x86 = \ 286 ExtractMsi(os.path.join(extracted_wdk, r'WDK\libs_x86fre.msi')) 287 extracted_libs_x64 = \ 288 ExtractMsi(os.path.join(extracted_wdk, r'WDK\libs_x64fre.msi')) 289 extracted_headers = \ 290 ExtractMsi(os.path.join(extracted_wdk, r'WDK\headers.msi')) 291 292 extracted_update = ExtractExe(images.sdk7_update) 293 extracted_update_x86 = \ 294 ExtractMsi(os.path.join(extracted_update, 'vc_stdx86.msi')) 295 extracted_update_x64 = \ 296 ExtractMsi(os.path.join(extracted_update, 'vc_stdamd64.msi')) 297 298 sdk_msi_path = os.path.join( 299 images.sdk8_path, 300 r'Installers\Windows Software Development Kit-x86_en-us.msi') 301 extracted_sdk_path = ExtractMsi(sdk_msi_path) 302 303 sdk_metro_msi_path = os.path.join( 304 images.sdk8_path, 305 'Installers', 306 'Windows Software Development Kit for Metro style Apps-x86_en-us.msi') 307 extracted_metro_sdk_path = ExtractMsi(sdk_metro_msi_path) 308 309 extracted_dxsdk = ExtractExe(images.dxsdk_path) 310 311 return ExtractedComponents2010( 312 vc_x86=extracted_vc_x86, 313 vc_x64=extracted_vc_x64, 314 buildtools_x86=extracted_buildtools_x86, 315 buildtools_x64=extracted_buildtools_x64, 316 libs_x86=extracted_libs_x86, 317 libs_x64=extracted_libs_x64, 318 headers=extracted_headers, 319 update_x86=extracted_update_x86, 320 update_x64=extracted_update_x64, 321 sdk_path=extracted_sdk_path, 322 metro_sdk_path=extracted_metro_sdk_path, 323 dxsdk=extracted_dxsdk) 324 325 326class ExtractedComponents2012(object): 327 def __init__(self, 328 vc_x86, vc_x86_res, librarycore, 329 vc_x86_update, vc_x86_res_update, librarycore_update, 330 sdk_path, metro_sdk_path, 331 buildtools_x86, buildtools_x64, libs_x86, libs_x64, headers): 332 self.vc_x86 = vc_x86 333 self.vc_x86_res = vc_x86_res 334 self.librarycore = librarycore 335 self.vc_x86_update = vc_x86_update 336 self.vc_x86_res_update = vc_x86_res_update 337 self.librarycore_update = librarycore_update 338 self.buildtools_x86 = buildtools_x86 339 self.buildtools_x64 = buildtools_x64 340 self.libs_x86 = libs_x86 341 self.libs_x64 = libs_x64 342 self.headers = headers 343 self.sdk_path = sdk_path 344 self.metro_sdk_path = metro_sdk_path 345 346 347def ExtractComponents2012(images): 348 """Given the paths to the images, extract the required parts and return an 349 object containing paths to all the pieces.""" 350 extracted_ex = ExtractIso(images.ex_path) 351 352 extracted_compilercore = ExtractMsi(os.path.join( 353 extracted_ex, 354 r'packages\vc_compilerCore86\vc_compilerCore86.msi')) 355 356 extracted_compilercore_res = ExtractMsi(os.path.join( 357 extracted_ex, 358 r'packages\vc_compilerCore86res\vc_compilerCore86res.msi')) 359 360 extracted_librarycore = ExtractMsi(os.path.join( 361 extracted_ex, 362 r'packages\vc_librarycore86\vc_librarycore86.msi')) 363 364 extracted_wdk = ExtractIso(images.wdk_iso) 365 extracted_buildtools_x86 = \ 366 ExtractMsi(os.path.join(extracted_wdk, r'WDK\buildtools_x86fre.msi')) 367 extracted_buildtools_x64 = \ 368 ExtractMsi(os.path.join(extracted_wdk, r'WDK\buildtools_x64fre.msi')) 369 extracted_libs_x86 = \ 370 ExtractMsi(os.path.join(extracted_wdk, r'WDK\libs_x86fre.msi')) 371 extracted_libs_x64 = \ 372 ExtractMsi(os.path.join(extracted_wdk, r'WDK\libs_x64fre.msi')) 373 extracted_headers = \ 374 ExtractMsi(os.path.join(extracted_wdk, r'WDK\headers.msi')) 375 376 sdk_msi_path = os.path.join( 377 extracted_ex, 'packages', 'Windows_SDK', 378 r'Windows Software Development Kit-x86_en-us.msi') 379 extracted_sdk_path = ExtractMsi(sdk_msi_path) 380 381 sdk_metro_msi_path = os.path.join( 382 extracted_ex, 'packages', 'Windows_SDK', 383 'Windows Software Development Kit for Metro style Apps-x86_en-us.msi') 384 extracted_metro_sdk_path = ExtractMsi(sdk_metro_msi_path) 385 386 extracted_update = ExtractIso(images.update_path) 387 388 extracted_compilercore_update = ExtractMsi(os.path.join( 389 extracted_update, r'packages\vc_compilercore86\vc_compilercore86.msi')) 390 391 extracted_compilercore_res_update = ExtractMsi(os.path.join( 392 extracted_update, 393 r'packages\vc_compilercore86res\enu\vc_compilercore86res.msi')) 394 395 extracted_librarycore_update = ExtractMsi(os.path.join( 396 extracted_update, r'packages\vc_librarycore86\vc_librarycore86.msi')) 397 398 return ExtractedComponents2012( 399 vc_x86=extracted_compilercore, 400 vc_x86_res=extracted_compilercore_res, 401 librarycore=extracted_librarycore, 402 vc_x86_update=extracted_compilercore_update, 403 vc_x86_res_update=extracted_compilercore_res_update, 404 librarycore_update=extracted_compilercore_update, 405 sdk_path=extracted_sdk_path, 406 metro_sdk_path=extracted_metro_sdk_path, 407 buildtools_x86=extracted_buildtools_x86, 408 buildtools_x64=extracted_buildtools_x64, 409 libs_x86=extracted_libs_x86, 410 libs_x64=extracted_libs_x64, 411 headers=extracted_headers) 412 413 414def PullFrom(list_of_path_pairs, source_root, target_dir): 415 """Each pair in |list_of_path_pairs| is (from, to). Join the 'from' with 416 |source_root| and the 'to' with |target_dir| and perform a recursive copy.""" 417 for source, destination in list_of_path_pairs: 418 full_source = os.path.join(source_root, source) 419 full_target = os.path.join(target_dir, destination) 420 rc = os.system('robocopy /s "%s" "%s" >nul' % (full_source, full_target)) 421 if (rc & 8) != 0 or (rc & 16) != 0: 422 # ref: http://ss64.com/nt/robocopy-exit.html 423 raise SystemExit("Couldn't copy %s to %s" % (full_source, full_target)) 424 425 426def CopyToFinalLocation2010(extracted, target_dir): 427 """Copy all the directories we need to the target location.""" 428 sys.stdout.write('Pulling together required pieces...\n') 429 430 # Note that order is important because some of the older ones are 431 # overwritten by updates. 432 from_sdk = [(r'Windows Kits\8.0', r'win8sdk')] 433 PullFrom(from_sdk, extracted.sdk_path, target_dir) 434 435 from_metro_sdk = [(r'Windows Kits\8.0', r'win8sdk')] 436 PullFrom(from_sdk, extracted.metro_sdk_path, target_dir) 437 438 from_buildtools_x86 = [ 439 (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\x86', r'WDK\bin'), 440 ] 441 PullFrom(from_buildtools_x86, extracted.buildtools_x86, target_dir) 442 443 from_buildtools_x64 = [ 444 (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\amd64', r'WDK\bin'), 445 ] 446 PullFrom(from_buildtools_x64, extracted.buildtools_x64, target_dir) 447 448 from_libs_x86 = [ 449 (r'WinDDK\7600.16385.win7_wdk.100208-1538\lib', r'WDK\lib'), 450 ] 451 PullFrom(from_libs_x86, extracted.libs_x86, target_dir) 452 453 from_libs_x64 = [ 454 (r'WinDDK\7600.16385.win7_wdk.100208-1538\lib', r'WDK\lib'), 455 ] 456 PullFrom(from_libs_x64, extracted.libs_x64, target_dir) 457 458 from_headers = [ 459 (r'WinDDK\7600.16385.win7_wdk.100208-1538\inc', r'WDK\inc'), 460 ] 461 PullFrom(from_headers, extracted.headers, target_dir) 462 463 # The compiler update to get the SP1 compiler is a bit of a mess. See 464 # http://goo.gl/n1DeO. The summary is that update for the standalone compiler 465 # binary installs a broken set of headers. So, add an empty ammintrin.h since 466 # we don't actually need the contents of it (for Chromium). 467 468 from_sdk7_x86 = [ 469 (r'Program Files\Microsoft Visual Studio 10.0', '.'), 470 (r'Win\System', r'VC\bin'), 471 ] 472 PullFrom(from_sdk7_x86, extracted.vc_x86, target_dir) 473 474 from_sdk7_x64 =[ 475 (r'Program Files(64)\Microsoft Visual Studio 10.0', '.'), 476 (r'Win\System64', r'VC\bin\amd64'), 477 ] 478 PullFrom(from_sdk7_x64, extracted.vc_x64, target_dir) 479 480 from_vcupdate_x86 = [ 481 (r'Program Files\Microsoft Visual Studio 10.0', '.'), 482 (r'Win\System', r'VC\bin'), 483 ] 484 PullFrom(from_vcupdate_x86, extracted.update_x86, target_dir) 485 486 from_vcupdate_x64 = [ 487 (r'Program Files(64)\Microsoft Visual Studio 10.0', '.'), 488 (r'Win\System64', r'VC\bin\amd64'), 489 ] 490 PullFrom(from_vcupdate_x64, extracted.update_x64, target_dir) 491 492 sys.stdout.write('Stubbing ammintrin.h...\n') 493 open(os.path.join(target_dir, r'VC\include\ammintrin.h'), 'w').close() 494 495 from_dxsdk = [ 496 (r'DXSDK\Include', r'DXSDK\Include'), 497 (r'DXSDK\Lib', r'DXSDK\Lib'), 498 (r'DXSDK\Redist', r'DXSDK\Redist'), 499 ] 500 PullFrom(from_dxsdk, extracted.dxsdk, target_dir) 501 502 503def CopyToFinalLocation2012(extracted, target_dir): 504 """Copy all directories we need to the target location.""" 505 sys.stdout.write('Pulling together required pieces...\n') 506 507 # Note that order is important because some of the older ones are 508 # overwritten by updates. 509 from_sdk = [(r'Windows Kits\8.0', r'win8sdk')] 510 PullFrom(from_sdk, extracted.sdk_path, target_dir) 511 512 from_metro_sdk = [(r'Windows Kits\8.0', r'win8sdk')] 513 PullFrom(from_sdk, extracted.metro_sdk_path, target_dir) 514 515 # Stock compiler. 516 from_compiler = [(r'Program Files\Microsoft Visual Studio 11.0', '.')] 517 PullFrom(from_compiler, extracted.vc_x86, target_dir) 518 519 from_compiler_res = [(r'Program Files\Microsoft Visual Studio 11.0', '.')] 520 PullFrom(from_compiler_res, extracted.vc_x86_res, target_dir) 521 522 from_library = [(r'Program Files\Microsoft Visual Studio 11.0', '.')] 523 PullFrom(from_library, extracted.librarycore, target_dir) 524 525 # WDK. 526 from_buildtools_x86 = [ 527 (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\x86', r'WDK\bin'), 528 ] 529 PullFrom(from_buildtools_x86, extracted.buildtools_x86, target_dir) 530 531 from_buildtools_x64 = [ 532 (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\amd64', r'WDK\bin'), 533 ] 534 PullFrom(from_buildtools_x64, extracted.buildtools_x64, target_dir) 535 536 from_libs_x86 = [(r'WinDDK\7600.16385.win7_wdk.100208-1538\lib', r'WDK\lib')] 537 PullFrom(from_libs_x86, extracted.libs_x86, target_dir) 538 539 from_libs_x64 = [(r'WinDDK\7600.16385.win7_wdk.100208-1538\lib', r'WDK\lib')] 540 PullFrom(from_libs_x64, extracted.libs_x64, target_dir) 541 542 from_headers = [(r'WinDDK\7600.16385.win7_wdk.100208-1538\inc', r'WDK\inc')] 543 PullFrom(from_headers, extracted.headers, target_dir) 544 545 # Update bits. 546 from_compiler = [(r'Program Files\Microsoft Visual Studio 11.0', '.')] 547 PullFrom(from_compiler, extracted.vc_x86_update, target_dir) 548 549 from_compiler_res = [(r'Program Files\Microsoft Visual Studio 11.0', '.')] 550 PullFrom(from_compiler_res, extracted.vc_x86_res_update, target_dir) 551 552 from_library = [(r'Program Files\Microsoft Visual Studio 11.0', '.')] 553 PullFrom(from_library, extracted.librarycore_update, target_dir) 554 555 556def PatchAsyncInfo(target_dir): 557 """Apply patch from 558 http://www.chromium.org/developers/how-tos/build-instructions-windows for 559 asyncinfo.h.""" 560 # This is only required for the 2010 compiler. 561 sys.stdout.write('Patching asyncinfo.h...\n') 562 asyncinfo_h_path = os.path.join( 563 target_dir, r'win8sdk\Include\winrt\asyncinfo.h') 564 with open(asyncinfo_h_path, 'rb') as f: 565 asyncinfo_h = f.read() 566 patched = asyncinfo_h.replace( 567 'enum class AsyncStatus {', 'enum AsyncStatus {') 568 with open(asyncinfo_h_path, 'wb') as f: 569 f.write(patched) 570 571 572def GenerateSetEnvCmd(target_dir, vsversion): 573 """Generate a batch file that gyp expects to exist to set up the compiler 574 environment. This is normally generated by a full install of the SDK, but we 575 do it here manually since we do not do a full install.""" 576 with open(os.path.join( 577 target_dir, r'win8sdk\bin\SetEnv.cmd'), 'w') as file: 578 file.write('@echo off\n') 579 file.write(':: Generated by tools\\win\\toolchain\\toolchain.py.\n') 580 file.write(':: Targeting VS%s.\n' % vsversion) 581 # Common to x86 and x64 582 file.write('set PATH=%s;%%PATH%%\n' % ( 583 os.path.join(target_dir, r'Common7\IDE'))) 584 file.write('set INCLUDE=%s;%s;%s\n' % ( 585 os.path.join(target_dir, r'win8sdk\Include\um'), 586 os.path.join(target_dir, r'win8sdk\Include\shared'), 587 os.path.join(target_dir, r'VC\include'))) 588 file.write('if "%1"=="/x64" goto x64\n') 589 590 # x86 only. 591 file.write('set PATH=%s;%s;%s;%%PATH%%\n' % ( 592 os.path.join(target_dir, r'win8sdk\bin\x86'), 593 os.path.join(target_dir, r'VC\bin'), 594 os.path.join(target_dir, r'WDK\bin'))) 595 file.write('set LIB=%s;%s\n' % ( 596 os.path.join(target_dir, r'VC\lib'), 597 os.path.join(target_dir, r'win8sdk\Lib\win8\um\x86'))) 598 file.write('goto done\n') 599 600 # Unfortunately, 2012 Express does not include a native 64 bit compiler, 601 # so we have to use the x86->x64 cross. 602 if vsversion == '2012': 603 # x64 only. 604 file.write(':x64\n') 605 file.write('set PATH=%s;%s;%s;%%PATH%%\n' % ( 606 os.path.join(target_dir, r'win8sdk\bin\x64'), 607 os.path.join(target_dir, r'VC\bin\x86_amd64'), 608 os.path.join(target_dir, r'WDK\bin\amd64'))) 609 file.write('set LIB=%s;%s\n' % ( 610 os.path.join(target_dir, r'VC\lib\amd64'), 611 os.path.join(target_dir, r'win8sdk\Lib\win8\um\x64'))) 612 else: 613 # x64 only. 614 file.write(':x64\n') 615 file.write('set PATH=%s;%s;%s;%%PATH%%\n' % ( 616 os.path.join(target_dir, r'win8sdk\bin\x64'), 617 os.path.join(target_dir, r'VC\bin\amd64'), 618 os.path.join(target_dir, r'WDK\bin\amd64'))) 619 file.write('set LIB=%s;%s\n' % ( 620 os.path.join(target_dir, r'VC\lib\amd64'), 621 os.path.join(target_dir, r'win8sdk\Lib\win8\um\x64'))) 622 623 file.write(':done\n') 624 625 626def GenerateTopLevelEnv(target_dir, vsversion): 627 """Generate a batch file that sets up various environment variables that let 628 the Chromium build files and gyp find SDKs and tools.""" 629 with open(os.path.join(target_dir, r'env.bat'), 'w') as file: 630 file.write('@echo off\n') 631 file.write(':: Generated by tools\\win\\toolchain\\toolchain.py.\n') 632 file.write(':: Targeting VS%s.\n' % vsversion) 633 file.write('set GYP_DEFINES=windows_sdk_path="%s" ' 634 'component=shared_library\n' % ( 635 os.path.join(target_dir, 'win8sdk'))) 636 file.write('set GYP_MSVS_VERSION=%se\n' % vsversion) 637 file.write('set GYP_MSVS_OVERRIDE_PATH=%s\n' % target_dir) 638 file.write('set GYP_GENERATORS=ninja\n') 639 file.write('set GYP_PARALLEL=1\n') 640 file.write('set WDK_DIR=%s\n' % os.path.join(target_dir, r'WDK')) 641 if vsversion == '2010': 642 file.write('set DXSDK_DIR=%s\n' % os.path.join(target_dir, r'DXSDK')) 643 file.write('set WindowsSDKDir=%s\n' % 644 os.path.join(target_dir, r'win8sdk')) 645 if vsversion == '2012': 646 # TODO: For 2010 too. 647 base = os.path.join(target_dir, r'VC\redist') 648 paths = [ 649 r'Debug_NonRedist\x64\Microsoft.VC110.DebugCRT', 650 r'Debug_NonRedist\x86\Microsoft.VC110.DebugCRT', 651 r'x64\Microsoft.VC110.CRT', 652 r'x86\Microsoft.VC110.CRT', 653 ] 654 additions = ';'.join(os.path.join(base, x) for x in paths) 655 file.write('set PATH=%s;%%PATH%%\n' % additions) 656 file.write('echo Environment set for toolchain in %s.\n' % target_dir) 657 file.write('cd /d %s\\..\n' % target_dir) 658 659 660def main(): 661 parser = OptionParser() 662 parser.add_option('--targetdir', metavar='DIR', 663 help='put toolchain into DIR', 664 default=os.path.abspath('win_toolchain')) 665 parser.add_option('--vsversion', metavar='VSVERSION', 666 help='select VS version: 2010 or 2012', default='2010') 667 parser.add_option('--noclean', action='store_false', dest='clean', 668 help='do not remove temp files', 669 default=True) 670 parser.add_option('--local', metavar='DIR', 671 help='use downloaded files from DIR') 672 options, args = parser.parse_args() 673 try: 674 target_dir = os.path.abspath(options.targetdir) 675 if os.path.exists(target_dir): 676 sys.stderr.write('%s already exists. Please [re]move it or use ' 677 '--targetdir to select a different target.\n' % 678 target_dir) 679 return 1 680 # Set the working directory to 7z subdirectory. 7-zip doesn't find its 681 # codec dll very well, so this is the simplest way to make sure it runs 682 # correctly, as we don't otherwise care about working directory. 683 os.chdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), '7z')) 684 assert options.vsversion in ('2010', '2012') 685 if options.vsversion == '2012': 686 images = GetSourceImages2012(options.local) 687 extracted = ExtractComponents2012(images) 688 CopyToFinalLocation2012(extracted, target_dir) 689 else: 690 images = GetSourceImages2010(options.local) 691 extracted = ExtractComponents2010(images) 692 CopyToFinalLocation2010(extracted, target_dir) 693 PatchAsyncInfo(target_dir) 694 695 GenerateSetEnvCmd(target_dir, options.vsversion) 696 GenerateTopLevelEnv(target_dir, options.vsversion) 697 finally: 698 if options.clean: 699 DeleteAllTempDirs() 700 701 sys.stdout.write( 702 '\nIn a (clean) cmd shell, you can now run\n\n' 703 ' %s\\env.bat\n\n' 704 'then\n\n' 705 " gclient runhooks (or gclient sync if you haven't pulled deps yet)\n" 706 ' ninja -C out\Debug chrome\n\n' 707 'Note that this script intentionally does not modify any global\n' 708 'settings like the registry, or system environment variables, so you\n' 709 'will need to run the above env.bat whenever you start a new\n' 710 'shell.\n\n' % target_dir) 711 712 713if __name__ == '__main__': 714 main() 715