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

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

Powered by Google App Engine
This is Rietveld 408576698