• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2013 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 VS2013 toolchain from various downloadable pieces.
6
7
8from toolchain import *
9
10
11def GetIsoUrl(pro):
12  """Get the .iso path."""
13  prefix = 'http://download.microsoft.com/download/'
14  if pro:
15    return (prefix +
16        'A/F/1/AF128362-A6A8-4DB3-A39A-C348086472CC/VS2013_RTM_PRO_ENU.iso')
17  else:
18    return (prefix +
19        '7/2/E/72E0F986-D247-4289-B9DC-C4FB07374894/VS2013_RTM_DskExp_ENU.iso')
20
21
22def DownloadMainIso(url):
23  temp_dir = TempDir()
24  target_path = os.path.join(temp_dir, os.path.basename(url))
25  Download(url, target_path)
26  return target_path
27
28
29def GetSourceImage(local_dir, pro):
30  url = GetIsoUrl(pro)
31  if local_dir:
32    return os.path.join(local_dir, os.path.basename(url))
33  else:
34    return DownloadMainIso(url)
35
36
37def ExtractMsiList(iso_dir, packages):
38  results = []
39  for (package, skippable) in packages:
40    path_to_package = os.path.join(iso_dir, 'packages', package)
41    if not os.path.exists(path_to_package) and skippable:
42      sys.stdout.write('Pro-only %s skipped.\n' % package)
43      continue
44    results.append(ExtractMsi(path_to_package))
45  return results
46
47
48def ExtractComponents(image):
49  extracted_iso = ExtractIso(image)
50  results = ExtractMsiList(extracted_iso, [
51      (r'vcRuntimeAdditional_amd64\vc_runtimeAdditional_x64.msi', False),
52      (r'vcRuntimeAdditional_x86\vc_runtimeAdditional_x86.msi', False),
53      (r'vcRuntimeDebug_amd64\vc_runtimeDebug_x64.msi', False),
54      (r'vcRuntimeDebug_x86\vc_runtimeDebug_x86.msi', False),
55      (r'vcRuntimeMinimum_amd64\vc_runtimeMinimum_x64.msi', False),
56      (r'vcRuntimeMinimum_x86\vc_runtimeMinimum_x86.msi', False),
57      (r'vc_compilerCore86\vc_compilerCore86.msi', False),
58      (r'vc_compilerCore86res\vc_compilerCore86res.msi', False),
59      (r'vc_compilerx64nat\vc_compilerx64nat.msi', True),
60      (r'vc_compilerx64natres\vc_compilerx64natres.msi', True),
61      (r'vc_compilerx64x86\vc_compilerx64x86.msi', True),
62      (r'vc_compilerx64x86res\vc_compilerx64x86res.msi', True),
63      (r'vc_librarycore86\vc_librarycore86.msi', False),
64      (r'vc_libraryDesktop\x64\vc_LibraryDesktopX64.msi', False),
65      (r'vc_libraryDesktop\x86\vc_LibraryDesktopX86.msi', False),
66      (r'vc_libraryextended\vc_libraryextended.msi', True),
67      (r'Windows_SDK\Windows Software Development Kit-x86_en-us.msi', False),
68      ('Windows_SDK\\'
69       r'Windows Software Development Kit for Metro style Apps-x86_en-us.msi',
70          False),
71    ])
72  return results
73
74
75def CopyToFinalLocation(extracted_dirs, target_dir):
76  sys.stdout.write('Copying to final location...\n')
77  mappings = {
78      'Program Files\\Microsoft Visual Studio 12.0\\': '.\\',
79      'Windows Kits\\8.0\\': 'win8sdk\\',
80      'System64\\': 'sys64\\',
81      'System\\': 'sys32\\',
82  }
83  matches = []
84  for extracted_dir in extracted_dirs:
85    for root, dirnames, filenames in os.walk(extracted_dir):
86      for filename in filenames:
87        matches.append((extracted_dir, os.path.join(root, filename)))
88
89  copies = []
90  for prefix, full_path in matches:
91    partial_path = full_path[len(prefix) + 1:]  # +1 for trailing \
92    #print 'partial_path', partial_path
93    for map_from, map_to in mappings.iteritems():
94      #print 'map_from:', map_from, ', map_to:', map_to
95      if partial_path.startswith(map_from):
96        target_path = os.path.join(map_to, partial_path[len(map_from):])
97        copies.append((full_path, os.path.join(target_dir, target_path)))
98
99  for full_source, full_target in copies:
100    target_dir = os.path.dirname(full_target)
101    if not os.path.isdir(target_dir):
102      os.makedirs(target_dir)
103    shutil.copy2(full_source, full_target)
104
105
106def GenerateSetEnvCmd(target_dir, pro):
107  """Generate a batch file that gyp expects to exist to set up the compiler
108  environment. This is normally generated by a full install of the SDK, but we
109  do it here manually since we do not do a full install."""
110  with open(os.path.join(
111        target_dir, r'win8sdk\bin\SetEnv.cmd'), 'w') as file:
112    file.write('@echo off\n')
113    file.write(':: Generated by tools\\win\\toolchain\\toolchain2013.py.\n')
114    # Common to x86 and x64
115    file.write('set PATH=%~dp0..\\..\\Common7\\IDE;%PATH%\n')
116    file.write('set INCLUDE=%~dp0..\\..\\win8sdk\\Include\\um;'
117               '%~dp0..\\..\\win8sdk\\Include\\shared;'
118               '%~dp0..\\..\\VC\\include;'
119               '%~dp0..\\..\\VC\\atlmfc\\include\n')
120    file.write('if "%1"=="/x64" goto x64\n')
121
122    # x86. If we're Pro, then use the amd64_x86 cross (we don't support x86
123    # host at all).
124    if pro:
125      file.write('set PATH=%~dp0..\\..\\win8sdk\\bin\\x86;'
126                '%~dp0..\\..\\VC\\bin\\amd64_x86;'
127                '%~dp0..\\..\\VC\\bin\\amd64;'  # Needed for mspdb120.dll.
128                '%PATH%\n')
129    else:
130      file.write('set PATH=%~dp0..\\..\\win8sdk\\bin\\x86;'
131                '%~dp0..\\..\\VC\\bin;%PATH%\n')
132    file.write('set LIB=%~dp0..\\..\\VC\\lib;'
133               '%~dp0..\\..\\win8sdk\\Lib\\win8\\um\\x86;'
134               '%~dp0..\\..\\VC\\atlmfc\\lib\n')
135    file.write('goto done\n')
136
137    # Express does not include a native 64 bit compiler, so we have to use
138    # the x86->x64 cross.
139    if not pro:
140      # x86->x64 cross.
141      file.write(':x64\n')
142      file.write('set PATH=%~dp0..\\..\\win8sdk\\bin\\x64;'
143                 '%~dp0..\\..\\VC\\bin\\x86_amd64;'
144                 '%PATH%\n')
145    else:
146      # x64 native.
147      file.write(':x64\n')
148      file.write('set PATH=%~dp0..\\..\\win8sdk\\bin\\x64;'
149                 '%~dp0..\\..\\VC\\bin\\amd64;'
150                 '%PATH%\n')
151    file.write('set LIB=%~dp0..\\..\\VC\\lib\\amd64;'
152               '%~dp0..\\..\\win8sdk\\Lib\\win8\\um\\x64;'
153               '%~dp0..\\..\\VC\\atlmfc\\lib\\amd64\n')
154    file.write(':done\n')
155
156
157def GenerateTopLevelEnv(target_dir, pro):
158  """Generate a batch file that sets up various environment variables that let
159  the Chromium build files and gyp find SDKs and tools."""
160  with open(os.path.join(target_dir, r'env.bat'), 'w') as file:
161    file.write('@echo off\n')
162    file.write(':: Generated by tools\\win\\toolchain\\toolchain2013.py.\n')
163    file.write('set GYP_DEFINES=windows_sdk_path="%~dp0win8sdk" '
164               'component=shared_library\n')
165    file.write('set GYP_MSVS_VERSION=2013%s\n' % '' if pro else 'e')
166    file.write('set GYP_MSVS_OVERRIDE_PATH=%~dp0\n')
167    file.write('set GYP_GENERATORS=ninja\n')
168    file.write('set WindowsSDKDir=%~dp0win8sdk\n')
169    paths = [
170        r'Debug_NonRedist\x64\Microsoft.VC120.DebugCRT',
171        r'Debug_NonRedist\x86\Microsoft.VC120.DebugCRT',
172        r'x64\Microsoft.VC120.CRT',
173        r'x86\Microsoft.VC120.CRT',
174      ]
175    additions = ';'.join(('%~dp0' + x) for x in paths)
176    file.write('set PATH=%s;%%PATH%%\n' % additions)
177    file.write('echo Environment set for toolchain in %~dp0.\n')
178    file.write('cd /d %~dp0..\n')
179
180
181def main():
182  parser = OptionParser()
183  parser.add_option('--targetdir', metavar='DIR',
184                    help='put toolchain into DIR',
185                    default=os.path.abspath('win_toolchain_2013'))
186  parser.add_option('--noclean', action='store_false', dest='clean',
187                    help='do not remove temp files',
188                    default=True)
189  parser.add_option('--local', metavar='DIR',
190                    help='use downloaded files from DIR')
191  parser.add_option('--express', metavar='EXPRESS',
192                    help='use VS Express instead of Pro', action='store_true')
193  options, args = parser.parse_args()
194  try:
195    target_dir = os.path.abspath(options.targetdir)
196    if os.path.exists(target_dir):
197      sys.stderr.write('%s already exists. Please [re]move it or use '
198                       '--targetdir to select a different target.\n' %
199                       target_dir)
200      return 1
201    pro = not options.express
202    # Set the working directory to 7z subdirectory. 7-zip doesn't find its
203    # codec dll very well, so this is the simplest way to make sure it runs
204    # correctly, as we don't otherwise care about working directory.
205    os.chdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), '7z'))
206    image = GetSourceImage(options.local, pro)
207    extracted = ExtractComponents(image)
208    CopyToFinalLocation(extracted, target_dir)
209
210    GenerateSetEnvCmd(target_dir, pro)
211    GenerateTopLevelEnv(target_dir, pro)
212  finally:
213    if options.clean:
214      DeleteAllTempDirs()
215
216  sys.stdout.write(
217      '\nIn a (clean) cmd shell, you can now run\n\n'
218      '  %s\\env.bat\n\n'
219      'then\n\n'
220      "  gclient runhooks (or gclient sync if you haven't pulled deps yet)\n"
221      '  ninja -C out\Debug chrome\n\n'
222      'Note that this script intentionally does not modify any global\n'
223      'settings like the registry, or system environment variables, so you\n'
224      'will need to run the above env.bat whenever you start a new\n'
225      'shell.\n\n' % target_dir)
226
227
228if __name__ == '__main__':
229  main()
230