Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / tools / win / toolchain / toolchain.py
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 ctypes
10 from optparse import OptionParser
11 import os
12 import shutil
13 import subprocess
14 import sys
15 import tempfile
16 import urllib2
17
18
19 g_temp_dirs = []
20
21
22 def 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
31 def RunOrDie(command):
32   rc = subprocess.call(command, shell=True)
33   if rc != 0:
34     raise SystemExit('%s failed.' % command)
35
36
37 def 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
46 def 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
57 def 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
79 def 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
89 def 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
99 def 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
109 def 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
119 def 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
129 def 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 = subprocess.call([target_path, '/quiet', '/features',
150                          '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
159 def 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
170 class 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
179 def 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
200 class 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
207 def 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
224 def 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
237 ExtractExe = ExtractIso
238
239
240 def 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
248 class 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
269 def 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
326 class 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
347 def 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
414 def 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
426 def 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
503 def 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
556 def 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
572 def 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
626 def 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
660 def 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
713 if __name__ == '__main__':
714   main()