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

Side by Side 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, 11 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/win/toolchain/7z/LICENSE ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 from optparse import OptionParser
10 import os
11 import shutil
12 import subprocess
13 import sys
14 import tempfile
15 import urllib2
16
17
18 g_temp_dirs = []
19
20
21 def RunOrDie(command):
22 rc = subprocess.call(command, shell=True)
23 if rc != 0:
24 raise SystemExit('%s failed.' % command)
25
26
27 def TempDir():
28 """Generate a temporary directory (for downloading or extracting to) and keep
29 track of the directory that's created for cleaning up later."""
30 global g_temp_dirs
31 temp = tempfile.mkdtemp()
32 g_temp_dirs.append(temp)
33 return temp
34
35
36 def DeleteAllTempDirs():
37 """Remove all temporary directories created by |TempDir()|."""
38 global g_temp_dirs
39 if g_temp_dirs:
40 sys.stdout.write('Cleaning up temporaries...\n')
41 for temp in g_temp_dirs:
42 # shutil.rmtree errors out on read only attributes.
43 RunOrDie('rmdir /s/q "%s"' % temp)
44 g_temp_dirs = []
45
46
47 def Download(url, local_path):
48 """Download a large-ish binary file and print some status information while
49 doing so."""
50 sys.stdout.write('Downloading %s...' % url)
51 req = urllib2.urlopen(url)
52 content_length = int(req.headers.get('Content-Length', 0))
53 bytes_read = 0
54 with open(local_path, 'wb') as file:
55 while True:
56 chunk = req.read(1024 * 1024)
57 if not chunk:
58 break
59 bytes_read += len(chunk)
60 file.write(chunk)
61 sys.stdout.write('.')
62 sys.stdout.write('\n')
63 if content_length and content_length != bytes_read:
64 raise SystemExit('Got incorrect number of bytes downloading %s' % url)
65
66
67 def DownloadSDK71Iso():
68 sdk7_temp_dir = TempDir()
69 target_path = os.path.join(sdk7_temp_dir, 'GRMSDKX_EN_DVD.iso')
70 Download(
71 ('http://download.microsoft.com/download/'
72 'F/1/0/F10113F5-B750-4969-A255-274341AC6BCE/GRMSDKX_EN_DVD.iso'),
73 target_path)
74 return target_path
75
76
77 def DownloadWDKIso():
78 wdk_temp_dir = TempDir()
79 target_path = os.path.join(wdk_temp_dir, 'GRMWDK_EN_7600_1.ISO')
80 Download(
81 ('http://download.microsoft.com/download/'
82 '4/A/2/4A25C7D5-EFBE-4182-B6A9-AE6850409A78/GRMWDK_EN_7600_1.ISO'),
83 target_path)
84 return target_path
85
86
87 def DownloadSDKUpdate():
88 sdk_update_temp_dir = TempDir()
89 target_path = os.path.join(sdk_update_temp_dir, 'VC-Compiler-KB2519277.exe')
90 Download(
91 ('http://download.microsoft.com/download/'
92 '7/5/0/75040801-126C-4591-BCE4-4CD1FD1499AA/VC-Compiler-KB2519277.exe'),
93 target_path)
94 return target_path
95
96
97 def DownloadDirectXSDK():
98 dxsdk_temp_dir = TempDir()
99 target_path = os.path.join(dxsdk_temp_dir, 'DXSDK_Jun10.exe')
100 Download(
101 ('http://download.microsoft.com/download/'
102 'A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe'),
103 target_path)
104 return target_path
105
106
107 def DownloadSDK8():
108 """Download the Win8 SDK. This one is slightly different than the simple
109 ones above. There is no .ISO distribution for the Windows 8 SDK. Rather, a
110 tool is provided that is a download manager. This is used to download the
111 various .msi files to a target location. Unfortunately, this tool requires
112 elevation for no obvious reason even when only downloading, so this function
113 will trigger a UAC elevation if the script is not run from an elevated
114 prompt."""
115 sdk_temp_dir = TempDir()
116 target_path = os.path.join(sdk_temp_dir, 'sdksetup.exe')
117 standalone_path = os.path.join(sdk_temp_dir, 'Standalone')
118 Download(
119 ('http://download.microsoft.com/download/'
120 'F/1/3/F1300C9C-A120-4341-90DF-8A52509B23AC/standalonesdk/sdksetup.exe'),
121 target_path)
122 sys.stdout.write(
123 'Running sdksetup.exe to download Win8 SDK (may request elevation)...\n')
124 count = 0
125 while count < 5:
126 rc = RunOrDie(target_path + ' /quiet '
127 '/features OptionId.WindowsDesktopSoftwareDevelopmentKit '
128 '/layout ' + standalone_path)
129 if rc == 0:
130 return standalone_path
131 break
132 count += 1
133 sys.stdout.write('Windows 8 SDK failed to download, retrying.\n')
134 raise SystemExit("After multiple retries, couldn't download Win8 SDK")
135
136
137 class SourceImages(object):
138 def __init__(self, sdk8_path, wdk_iso, sdk7_update, sdk7_path, dxsdk_path):
139 self.sdk8_path = sdk8_path
140 self.wdk_iso = wdk_iso
141 self.sdk7_update = sdk7_update
142 self.sdk7_path = sdk7_path
143 self.dxsdk_path = dxsdk_path
144
145
146 def GetSourceImages():
147 """Download all distribution archives for the components we need."""
148 if len(sys.argv) >= 2 and sys.argv[1] == 'local':
149 return SourceImages(
150 sdk8_path=r'C:\Users\Scott\Desktop\wee\Standalone',
151 wdk_iso=r'c:\users\scott\desktop\wee\GRMWDK_EN_7600_1.ISO',
152 sdk7_update=r'c:\users\scott\desktop\wee\VC-Compiler-KB2519277.exe',
153 sdk7_path=r'C:\Users\Scott\Desktop\wee\GRMSDKX_EN_DVD.ISO',
154 dxsdk_path=r'C:\Users\Scott\Desktop\wee\DXSDK_Jun10.exe')
155 else:
156 # Note that we do the Win8 SDK first so that its silly UAC prompt
157 # happens before the user wanders off to get coffee.
158 sdk8_path = DownloadSDK8()
159 wdk_iso = DownloadWDKIso()
160 sdk7_update = DownloadSDKUpdate()
161 sdk7_path = DownloadSDK71Iso()
162 dxsdk_path = DownloadDirectXSDK()
163 return SourceImages(sdk8_path, wdk_iso, sdk7_update, sdk7_path, dxsdk_path)
164
165
166 def ExtractIso(iso_path):
167 """Use 7zip to extract the contents of the given .iso (or self-extracting
168 .exe)."""
169 target_path = TempDir()
170 sys.stdout.write('Extracting %s...\n' % iso_path)
171 # TODO(scottmg): Do this (and exe) manually with python code.
172 # Note that at the beginning of main() we set the working directory to 7z's
173 # location.
174 RunOrDie('7z x "%s" -y "-o%s" >nul' % (iso_path, target_path))
175 return target_path
176
177
178 ExtractExe = ExtractIso
179
180
181 def ExtractMsi(msi_path):
182 """Use msiexec to extract the contents of the given .msi file."""
183 sys.stdout.write('Extracting %s...\n' % msi_path)
184 target_path = TempDir()
185 RunOrDie('msiexec /a "%s" /qn TARGETDIR="%s"' % (msi_path, target_path))
186 return target_path
187
188
189 class ExtractedComponents(object):
190 def __init__(self,
191 vc_x86, vc_x64,
192 buildtools_x86, buildtools_x64, libs_x86, libs_x64, headers,
193 update_x86, update_x64,
194 sdk_path, metro_sdk_path,
195 dxsdk):
196 self.vc_x86 = vc_x86
197 self.vc_x64 = vc_x64
198 self.buildtools_x86 = buildtools_x86
199 self.buildtools_x64 = buildtools_x64
200 self.libs_x86 = libs_x86
201 self.libs_x64 = libs_x64
202 self.headers = headers
203 self.update_x86 = update_x86
204 self.update_x64 = update_x64
205 self.sdk_path = sdk_path
206 self.metro_sdk_path = metro_sdk_path
207 self.dxsdk = dxsdk
208
209
210 def ExtractComponents(images):
211 """Given the paths to the images, extract the required parts, and return the
212 an object containing paths to all the pieces."""
213 extracted_sdk7 = ExtractIso(images.sdk7_path)
214 extracted_vc_x86 = \
215 ExtractMsi(os.path.join(extracted_sdk7,
216 r'Setup\vc_stdx86\vc_stdx86.msi'))
217 extracted_vc_x64 = \
218 ExtractMsi(os.path.join(extracted_sdk7,
219 r'Setup\vc_stdamd64\vc_stdamd64.msi'))
220
221 extracted_wdk = ExtractIso(images.wdk_iso)
222 extracted_buildtools_x86 = \
223 ExtractMsi(os.path.join(extracted_wdk, r'WDK\buildtools_x86fre.msi'))
224 extracted_buildtools_x64 = \
225 ExtractMsi(os.path.join(extracted_wdk, r'WDK\buildtools_x64fre.msi'))
226 extracted_libs_x86 = \
227 ExtractMsi(os.path.join(extracted_wdk, r'WDK\libs_x86fre.msi'))
228 extracted_libs_x64 = \
229 ExtractMsi(os.path.join(extracted_wdk, r'WDK\libs_x64fre.msi'))
230 extracted_headers = \
231 ExtractMsi(os.path.join(extracted_wdk, r'WDK\headers.msi'))
232
233 extracted_update = ExtractExe(images.sdk7_update)
234 extracted_update_x86 = \
235 ExtractMsi(os.path.join(extracted_update, 'vc_stdx86.msi'))
236 extracted_update_x64 = \
237 ExtractMsi(os.path.join(extracted_update, 'vc_stdamd64.msi'))
238
239 sdk_msi_path = os.path.join(
240 images.sdk8_path,
241 r'Installers\Windows Software Development Kit-x86_en-us.msi')
242 extracted_sdk_path = ExtractMsi(sdk_msi_path)
243
244 sdk_metro_msi_path = os.path.join(
245 images.sdk8_path,
246 'Installers',
247 'Windows Software Development Kit for Metro style Apps-x86_en-us.msi')
248 extracted_metro_sdk_path = ExtractMsi(sdk_metro_msi_path)
249
250 extracted_dxsdk = ExtractExe(images.dxsdk_path)
251
252 return ExtractedComponents(
253 vc_x86=extracted_vc_x86,
254 vc_x64=extracted_vc_x64,
255 buildtools_x86=extracted_buildtools_x86,
256 buildtools_x64=extracted_buildtools_x64,
257 libs_x86=extracted_libs_x86,
258 libs_x64=extracted_libs_x64,
259 headers=extracted_headers,
260 update_x86=extracted_update_x86,
261 update_x64=extracted_update_x64,
262 sdk_path=extracted_sdk_path,
263 metro_sdk_path=extracted_metro_sdk_path,
264 dxsdk=extracted_dxsdk)
265
266
267 def PullFrom(list_of_path_pairs, source_root, target_dir):
268 """Each pair in |list_of_path_pairs| is (from, to). Join the 'from' with
269 |source_root| and the 'to' with |target_dir| and perform a recursive copy."""
270 for source, destination in list_of_path_pairs:
271 full_source = os.path.join(source_root, source)
272 full_target = os.path.join(target_dir, destination)
273 rc = os.system('robocopy /s "%s" "%s" >nul' % (full_source, full_target))
274 if (rc & 8) != 0 or (rc & 16) != 0:
275 # ref: http://ss64.com/nt/robocopy-exit.html
276 raise SystemExit("Couldn't copy %s to %s" % (full_source, full_target))
277
278
279 def CopyToFinalLocation(extracted, target_dir):
280 """Copy all the directories we need to the target location."""
281 sys.stdout.write('Pulling together required pieces...\n')
282
283 # Note that order is important because some of the older ones are
284 # overwritten by updates.
285 from_sdk = [(r'Windows Kits\8.0', r'win8sdk')]
286 PullFrom(from_sdk, extracted.sdk_path, target_dir)
287
288 from_metro_sdk = [(r'Windows Kits\8.0', r'win8sdk')]
289 PullFrom(from_sdk, extracted.metro_sdk_path, target_dir)
290
291 from_buildtools_x86 = [
292 (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\x86', r'WDK\bin'),
293 (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\amd64', r'WDK\bin'),
294 ]
295 PullFrom(from_buildtools_x86, extracted.buildtools_x86, target_dir)
296
297 from_buildtools_x64 = [
298 (r'WinDDK\7600.16385.win7_wdk.100208-1538\bin\amd64', r'WDK\bin'),
299 ]
300 PullFrom(from_buildtools_x64, extracted.buildtools_x64, target_dir)
301
302 from_libs_x86 = [
303 (r'WinDDK\7600.16385.win7_wdk.100208-1538\lib', r'WDK\lib'),
304 ]
305 PullFrom(from_libs_x86, extracted.libs_x86, target_dir)
306
307 from_libs_x64 = [
308 (r'WinDDK\7600.16385.win7_wdk.100208-1538\lib', r'WDK\lib'),
309 ]
310 PullFrom(from_libs_x64, extracted.libs_x64, target_dir)
311
312 from_headers = [
313 (r'WinDDK\7600.16385.win7_wdk.100208-1538\inc', r'WDK\inc'),
314 ]
315 PullFrom(from_headers, extracted.headers, target_dir)
316
317 # The compiler update to get the SP1 x86 compiler is a bit of a mess. See
318 # http://goo.gl/n1DeO. The summary is that update for the standalone
319 # compiler binary installs a broken set of headers. So, we need to pull the
320 # new binaries from the update, but keep the older set of headers.
321
322 from_vcupdate_x86 = [
323 (r'Program Files\Microsoft Visual Studio 10.0', '.'),
324 (r'Win\System', r'VC\bin'),
325 ]
326 PullFrom(from_vcupdate_x86, extracted.update_x86, target_dir)
327
328 from_vcupdate_x64 = [
329 (r'Program Files(64)\Microsoft Visual Studio 10.0', '.'),
330 (r'Win\System64', r'VC\bin\amd64'),
331 ]
332 PullFrom(from_vcupdate_x64, extracted.update_x64, target_dir)
333
334 from_sdk7_x86 = [
335 (r'Program Files\Microsoft Visual Studio 10.0', '.'),
336 (r'Win\System', r'VC\bin'),
337 ]
338 PullFrom(from_sdk7_x86, extracted.vc_x86, target_dir)
339
340 from_sdk7_x64 =[
341 (r'Program Files(64)\Microsoft Visual Studio 10.0', '.'),
342 (r'Win\System64', r'VC\bin\amd64'),
343 ]
344 PullFrom(from_sdk7_x64, extracted.vc_x64, target_dir)
345
346 # Now, re-get just the binaries from the update.
347 from_vcupdate_x86 = [
348 (r'Program Files\Microsoft Visual Studio 10.0\VC\bin', r'VC\bin'),
349 ]
350 PullFrom(from_vcupdate_x86, extracted.update_x86, target_dir)
351
352 from_vcupdate_x64 = [
353 (r'Program Files(64)\Microsoft Visual Studio 10.0\VC\bin', r'VC\bin'),
354 ]
355 PullFrom(from_vcupdate_x64, extracted.update_x64, target_dir)
356
357 from_dxsdk = [
358 (r'DXSDK\Include', r'DXSDK\Include'),
359 (r'DXSDK\Lib', r'DXSDK\Lib'),
360 (r'DXSDK\Redist', r'DXSDK\Redist'),
361 ]
362 PullFrom(from_dxsdk, extracted.dxsdk, target_dir)
363
364
365 def PatchAsyncInfo(target_dir):
366 """Apply patch from
367 http://www.chromium.org/developers/how-tos/build-instructions-windows for
368 asyncinfo.h."""
369 sys.stdout.write('Patching asyncinfo.h...\n')
370 asyncinfo_h_path = os.path.join(
371 target_dir, r'win8sdk\Include\winrt\asyncinfo.h')
372 with open(asyncinfo_h_path, 'rb') as f:
373 asyncinfo_h = f.read()
374 patched = asyncinfo_h.replace(
375 'enum class AsyncStatus {', 'enum AsyncStatus {')
376 with open(asyncinfo_h_path, 'wb') as f:
377 f.write(patched)
378
379
380 def GenerateSetEnvCmd(target_dir):
381 """Generate a batch file that gyp expects to exist to set up the compiler
382 environment. This is normally generated by a full install of the SDK, but we
383 do it here manually since we do not do a full install."""
384 with open(os.path.join(
385 target_dir, r'win8sdk\bin\SetEnv.cmd'), 'w') as file:
386 file.write('@echo off\n')
387 file.write(':: Generated by tools\\win\\toolchain\\toolchain.py.\n')
388 # Common to x86 and x64
389 file.write('set PATH=%s;%%PATH%%\n' % (
390 os.path.join(target_dir, r'Common7\IDE')))
391 file.write('set INCLUDE=%s;%s;%s\n' % (
392 os.path.join(target_dir, r'win8sdk\Include\um'),
393 os.path.join(target_dir, r'win8sdk\Include\shared'),
394 os.path.join(target_dir, r'VC\include')))
395 file.write('if "%1"=="/x64" goto x64\n')
396
397 # x86 only.
398 file.write('set PATH=%s;%s;%s;%%PATH%%\n' % (
399 os.path.join(target_dir, r'win8sdk\bin\x86'),
400 os.path.join(target_dir, r'VC\bin'),
401 os.path.join(target_dir, r'WDK\bin')))
402 file.write('set LIB=%s;%s\n' % (
403 os.path.join(target_dir, r'VC\lib'),
404 os.path.join(target_dir, r'win8sdk\Lib\win8\um\x86')))
405 file.write('goto done\n')
406
407 # x64 only.
408 file.write(':x64\n')
409 file.write('set PATH=%s;%s;%s;%%PATH%%\n' % (
410 os.path.join(target_dir, r'win8sdk\bin\x64'),
411 os.path.join(target_dir, r'VC\bin\amd64'),
412 os.path.join(target_dir, r'WDK\bin\amd64')))
413 file.write('set LIB=%s;%s\n' % (
414 os.path.join(target_dir, r'VC\lib\amd64'),
415 os.path.join(target_dir, r'win8sdk\Lib\win8\um\x64')))
416
417 file.write(':done\n')
418
419
420 def GenerateTopLevelEnv(target_dir):
421 """Generate a batch file that sets up various environment variables that let
422 the Chromium build files and gyp find SDKs and tools."""
423 with open(os.path.join(target_dir, r'env.bat'), 'w') as file:
424 file.write('@echo off\n')
425 file.write(':: Generated by tools\\win\\toolchain\\toolchain.py.\n')
426 file.write('set GYP_DEFINES=windows_sdk_path="%s" '
427 'component=shared_library\n' % (
428 os.path.join(target_dir, 'win8sdk')))
429 file.write('set GYP_MSVS_VERSION=2010e\n')
430 file.write('set GYP_MSVS_OVERRIDE_PATH=%s\n' % target_dir)
431 file.write('set GYP_GENERATORS=ninja\n')
432 file.write('set WDK_DIR=%s\n' % os.path.join(target_dir, r'WDK'))
433 file.write('set DXSDK_DIR=%s\n' % os.path.join(target_dir, r'DXSDK'))
434 file.write('set WindowsSDKDir=%s\n' %
435 os.path.join(target_dir, r'win8sdk'))
436 file.write('echo Environment set for toolchain in %s.\n' % target_dir)
437 file.write('cd /d %s\\..\n' % target_dir)
438
439
440 def main():
441 try:
442 parser = OptionParser()
443 parser.add_option('--targetdir', metavar='DIR',
444 help='put toolchain into DIR',
445 default=os.path.abspath('win_toolchain'))
446 options, args = parser.parse_args()
447 target_dir = os.path.abspath(options.targetdir)
448 # Set the working directory to 7z subdirectory. 7-zip doesn't find its
449 # codec dll very well, so this is the simplest way to make sure it runs
450 # correctly, as we don't otherwise care about working directory.
451 os.chdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), '7z'))
452 images = GetSourceImages()
453 extracted = ExtractComponents(images)
454 CopyToFinalLocation(extracted, target_dir)
455 PatchAsyncInfo(target_dir)
456 GenerateSetEnvCmd(target_dir)
457 GenerateTopLevelEnv(target_dir)
458 finally:
459 DeleteAllTempDirs()
460
461 sys.stdout.write(
462 '\nIn a (clean) cmd shell, you can now run\n\n'
463 ' %s\\env.bat\n\n'
464 'then\n\n'
465 " gclient runhooks (or gclient sync if you haven't pulled deps yet)\n"
466 ' ninja -C out\Debug chrome\n\n'
467 'Note that this script intentionally does not modify any global\n'
468 'settings like the registry, or system environment variables, so you\n'
469 'will need to run the above env.bat whenever you start a new\n'
470 'shell.\n\n' % target_dir)
471
472
473 if __name__ == '__main__':
474 main()
OLDNEW
« 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