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 8 from toolchain import * 9 10 11 def 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 22 def 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 29 def 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 37 def 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 48 def 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 75 def 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 106 def 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 157 def 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 181 def 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 228 if __name__ == '__main__': 229 main() 230