blob: 16f447755656bb5427097660553f8af28f8d74f0 [file] [log] [blame]
James Robinson646469d2014-10-03 15:33:28 -07001# Copyright 2014 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
5import json
6import os
7import pipes
8import shutil
9import subprocess
10import sys
11
12
13script_dir = os.path.dirname(os.path.realpath(__file__))
14chrome_src = os.path.abspath(os.path.join(script_dir, os.pardir))
15SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
16sys.path.insert(1, os.path.join(chrome_src, 'tools'))
17sys.path.insert(0, os.path.join(chrome_src, 'tools', 'gyp', 'pylib'))
18json_data_file = os.path.join(script_dir, 'win_toolchain.json')
19
20
James Robinson1ae030a2014-11-07 08:32:47 -080021import gyp
22
23
James Robinson646469d2014-10-03 15:33:28 -070024def SetEnvironmentAndGetRuntimeDllDirs():
25 """Sets up os.environ to use the depot_tools VS toolchain with gyp, and
26 returns the location of the VS runtime DLLs so they can be copied into
27 the output directory after gyp generation.
28 """
29 vs2013_runtime_dll_dirs = None
30 depot_tools_win_toolchain = \
31 bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
32 if sys.platform in ('win32', 'cygwin') and depot_tools_win_toolchain:
33 if not os.path.exists(json_data_file):
34 Update()
35 with open(json_data_file, 'r') as tempf:
36 toolchain_data = json.load(tempf)
37
38 toolchain = toolchain_data['path']
39 version = toolchain_data['version']
Viet-Trung Luu235cf3d2015-06-11 10:01:25 -070040 win_sdk = toolchain_data.get('win_sdk')
41 if not win_sdk:
42 win_sdk = toolchain_data['win8sdk']
James Robinson646469d2014-10-03 15:33:28 -070043 wdk = toolchain_data['wdk']
44 # TODO(scottmg): The order unfortunately matters in these. They should be
45 # split into separate keys for x86 and x64. (See CopyVsRuntimeDlls call
46 # below). http://crbug.com/345992
47 vs2013_runtime_dll_dirs = toolchain_data['runtime_dirs']
48
49 os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
50 os.environ['GYP_MSVS_VERSION'] = version
James Robinson1ae030a2014-11-07 08:32:47 -080051 # We need to make sure windows_sdk_path is set to the automated
52 # toolchain values in GYP_DEFINES, but don't want to override any
53 # otheroptions.express
54 # values there.
55 gyp_defines_dict = gyp.NameValueListToDict(gyp.ShlexEnv('GYP_DEFINES'))
Viet-Trung Luu235cf3d2015-06-11 10:01:25 -070056 gyp_defines_dict['windows_sdk_path'] = win_sdk
James Robinson1ae030a2014-11-07 08:32:47 -080057 os.environ['GYP_DEFINES'] = ' '.join('%s=%s' % (k, pipes.quote(str(v)))
58 for k, v in gyp_defines_dict.iteritems())
Viet-Trung Luu235cf3d2015-06-11 10:01:25 -070059 os.environ['WINDOWSSDKDIR'] = win_sdk
James Robinson646469d2014-10-03 15:33:28 -070060 os.environ['WDK_DIR'] = wdk
61 # Include the VS runtime in the PATH in case it's not machine-installed.
62 runtime_path = ';'.join(vs2013_runtime_dll_dirs)
63 os.environ['PATH'] = runtime_path + ';' + os.environ['PATH']
64 return vs2013_runtime_dll_dirs
65
66
Viet-Trung Luu235cf3d2015-06-11 10:01:25 -070067def _VersionNumber():
68 """Gets the standard version number ('120', '140', etc.) based on
69 GYP_MSVS_VERSION."""
70 if os.environ['GYP_MSVS_VERSION'] == '2013':
71 return '120'
72 elif os.environ['GYP_MSVS_VERSION'] == '2015':
73 return '140'
74 else:
75 raise ValueError('Unexpected GYP_MSVS_VERSION')
76
77
Benjamin Lerman57998902014-11-18 16:06:02 +010078def _CopyRuntimeImpl(target, source):
79 """Copy |source| to |target| if it doesn't already exist or if it
80 needs to be updated.
81 """
82 if (os.path.isdir(os.path.dirname(target)) and
83 (not os.path.isfile(target) or
84 os.stat(target).st_mtime != os.stat(source).st_mtime)):
85 print 'Copying %s to %s...' % (source, target)
86 if os.path.exists(target):
87 os.unlink(target)
88 shutil.copy2(source, target)
89
90
Viet-Trung Luu235cf3d2015-06-11 10:01:25 -070091def _CopyRuntime2013(target_dir, source_dir, dll_pattern):
92 """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
93 exist, but the target directory does exist."""
94 for file_part in ('p', 'r'):
95 dll = dll_pattern % file_part
96 target = os.path.join(target_dir, dll)
97 source = os.path.join(source_dir, dll)
98 _CopyRuntimeImpl(target, source)
99
100
101def _CopyRuntime2015(target_dir, source_dir, dll_pattern):
102 """Copy both the msvcp and vccorlib runtime DLLs, only if the target doesn't
103 exist, but the target directory does exist."""
104 for file_part in ('msvcp', 'vccorlib'):
105 dll = dll_pattern % file_part
106 target = os.path.join(target_dir, dll)
107 source = os.path.join(source_dir, dll)
108 _CopyRuntimeImpl(target, source)
Benjamin Lerman57998902014-11-18 16:06:02 +0100109
110
James Robinson646469d2014-10-03 15:33:28 -0700111def CopyVsRuntimeDlls(output_dir, runtime_dirs):
112 """Copies the VS runtime DLLs from the given |runtime_dirs| to the output
113 directory so that even if not system-installed, built binaries are likely to
114 be able to run.
115
116 This needs to be run after gyp has been run so that the expected target
117 output directories are already created.
118 """
119 assert sys.platform.startswith(('win32', 'cygwin'))
120
James Robinson646469d2014-10-03 15:33:28 -0700121 x86, x64 = runtime_dirs
122 out_debug = os.path.join(output_dir, 'Debug')
123 out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
124 out_release = os.path.join(output_dir, 'Release')
125 out_release_nacl64 = os.path.join(output_dir, 'Release', 'x64')
126 out_debug_x64 = os.path.join(output_dir, 'Debug_x64')
127 out_release_x64 = os.path.join(output_dir, 'Release_x64')
128
129 if os.path.exists(out_debug) and not os.path.exists(out_debug_nacl64):
130 os.makedirs(out_debug_nacl64)
131 if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
132 os.makedirs(out_release_nacl64)
Viet-Trung Luu235cf3d2015-06-11 10:01:25 -0700133 if os.environ.get('GYP_MSVS_VERSION') == '2015':
134 _CopyRuntime2015(out_debug, x86, '%s140d.dll')
135 _CopyRuntime2015(out_release, x86, '%s140.dll')
136 _CopyRuntime2015(out_debug_x64, x64, '%s140d.dll')
137 _CopyRuntime2015(out_release_x64, x64, '%s140.dll')
138 _CopyRuntime2015(out_debug_nacl64, x64, '%s140d.dll')
139 _CopyRuntime2015(out_release_nacl64, x64, '%s140.dll')
140 else:
141 # VS2013 is the default.
142 _CopyRuntime2013(out_debug, x86, 'msvc%s120d.dll')
143 _CopyRuntime2013(out_release, x86, 'msvc%s120.dll')
144 _CopyRuntime2013(out_debug_x64, x64, 'msvc%s120d.dll')
145 _CopyRuntime2013(out_release_x64, x64, 'msvc%s120.dll')
146 _CopyRuntime2013(out_debug_nacl64, x64, 'msvc%s120d.dll')
147 _CopyRuntime2013(out_release_nacl64, x64, 'msvc%s120.dll')
James Robinson646469d2014-10-03 15:33:28 -0700148
149 # Copy the PGO runtime library to the release directories.
150 if os.environ.get('GYP_MSVS_OVERRIDE_PATH'):
151 pgo_x86_runtime_dir = os.path.join(os.environ.get('GYP_MSVS_OVERRIDE_PATH'),
152 'VC', 'bin')
153 pgo_x64_runtime_dir = os.path.join(pgo_x86_runtime_dir, 'amd64')
Viet-Trung Luu235cf3d2015-06-11 10:01:25 -0700154 pgo_runtime_dll = 'pgort' + _VersionNumber() + '.dll'
James Robinson646469d2014-10-03 15:33:28 -0700155 source_x86 = os.path.join(pgo_x86_runtime_dir, pgo_runtime_dll)
156 if os.path.exists(source_x86):
Benjamin Lerman57998902014-11-18 16:06:02 +0100157 _CopyRuntimeImpl(os.path.join(out_release, pgo_runtime_dll), source_x86)
James Robinson646469d2014-10-03 15:33:28 -0700158 source_x64 = os.path.join(pgo_x64_runtime_dir, pgo_runtime_dll)
159 if os.path.exists(source_x64):
Benjamin Lerman57998902014-11-18 16:06:02 +0100160 _CopyRuntimeImpl(os.path.join(out_release_x64, pgo_runtime_dll),
161 source_x64)
162
163
Benjamin Lermane8ca9b72015-02-24 16:42:13 +0100164def CopyDlls(target_dir, configuration, target_cpu):
Benjamin Lerman57998902014-11-18 16:06:02 +0100165 """Copy the VS runtime DLLs into the requested directory as needed.
166
167 configuration is one of 'Debug' or 'Release'.
Benjamin Lermane8ca9b72015-02-24 16:42:13 +0100168 target_cpu is one of 'x86' or 'x64'.
Benjamin Lerman57998902014-11-18 16:06:02 +0100169
170 The debug configuration gets both the debug and release DLLs; the
171 release config only the latter.
172 """
173 vs2013_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
174 if not vs2013_runtime_dll_dirs:
175 return
176
177 x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
Benjamin Lermane8ca9b72015-02-24 16:42:13 +0100178 runtime_dir = x64_runtime if target_cpu == 'x64' else x86_runtime
Viet-Trung Luu235cf3d2015-06-11 10:01:25 -0700179 _CopyRuntime2013(
180 target_dir, runtime_dir, 'msvc%s' + _VersionNumber() + '.dll')
Benjamin Lerman57998902014-11-18 16:06:02 +0100181 if configuration == 'Debug':
Viet-Trung Luu235cf3d2015-06-11 10:01:25 -0700182 _CopyRuntime2013(
183 target_dir, runtime_dir, 'msvc%s' + _VersionNumber() + 'd.dll')
James Robinson646469d2014-10-03 15:33:28 -0700184
185
186def _GetDesiredVsToolchainHashes():
187 """Load a list of SHA1s corresponding to the toolchains that we want installed
188 to build with."""
Viet-Trung Luu235cf3d2015-06-11 10:01:25 -0700189 # TODO(scottmg): If explicitly set to VS2015 override hashes to the VS2015 RC
190 # toolchain. http://crbug.com/492774.
191 if os.environ.get('GYP_MSVS_VERSION') == '2015':
192 return ['40721575c85171cea5d7afe5ec17bd108a94796e']
193 else:
194 # Default to VS2013.
195 return ['ee7d718ec60c2dc5d255bbe325909c2021a7efef']
James Robinson646469d2014-10-03 15:33:28 -0700196
197
198def Update():
199 """Requests an update of the toolchain to the specific hashes we have at
200 this revision. The update outputs a .json of the various configuration
201 information required to pass to gyp which we use in |GetToolchainDir()|.
202 """
203 depot_tools_win_toolchain = \
204 bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
205 if sys.platform in ('win32', 'cygwin') and depot_tools_win_toolchain:
206 import find_depot_tools
207 depot_tools_path = find_depot_tools.add_depot_tools_to_path()
James Robinson646469d2014-10-03 15:33:28 -0700208 get_toolchain_args = [
209 sys.executable,
210 os.path.join(depot_tools_path,
211 'win_toolchain',
212 'get_toolchain_if_necessary.py'),
213 '--output-json', json_data_file,
214 ] + _GetDesiredVsToolchainHashes()
215 subprocess.check_call(get_toolchain_args)
216
217 return 0
218
219
220def GetToolchainDir():
221 """Gets location information about the current toolchain (must have been
222 previously updated by 'update'). This is used for the GN build."""
James Robinsonc4c1c592014-11-21 18:27:04 -0800223 runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
James Robinson646469d2014-10-03 15:33:28 -0700224
225 # If WINDOWSSDKDIR is not set, search the default SDK path and set it.
226 if not 'WINDOWSSDKDIR' in os.environ:
James Robinsonc4c1c592014-11-21 18:27:04 -0800227 default_sdk_path = 'C:\\Program Files (x86)\\Windows Kits\\8.1'
James Robinson646469d2014-10-03 15:33:28 -0700228 if os.path.isdir(default_sdk_path):
229 os.environ['WINDOWSSDKDIR'] = default_sdk_path
230
231 print '''vs_path = "%s"
232sdk_path = "%s"
233vs_version = "%s"
234wdk_dir = "%s"
James Robinsonc4c1c592014-11-21 18:27:04 -0800235runtime_dirs = "%s"
James Robinson646469d2014-10-03 15:33:28 -0700236''' % (
237 os.environ['GYP_MSVS_OVERRIDE_PATH'],
238 os.environ['WINDOWSSDKDIR'],
239 os.environ['GYP_MSVS_VERSION'],
James Robinsonc4c1c592014-11-21 18:27:04 -0800240 os.environ.get('WDK_DIR', ''),
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100241 ';'.join(runtime_dll_dirs or ['None']))
James Robinson646469d2014-10-03 15:33:28 -0700242
243
244def main():
245 if not sys.platform.startswith(('win32', 'cygwin')):
246 return 0
247 commands = {
248 'update': Update,
249 'get_toolchain_dir': GetToolchainDir,
Benjamin Lerman57998902014-11-18 16:06:02 +0100250 'copy_dlls': CopyDlls,
James Robinson646469d2014-10-03 15:33:28 -0700251 }
252 if len(sys.argv) < 2 or sys.argv[1] not in commands:
253 print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
254 return 1
Benjamin Lerman57998902014-11-18 16:06:02 +0100255 return commands[sys.argv[1]](*sys.argv[2:])
James Robinson646469d2014-10-03 15:33:28 -0700256
257
258if __name__ == '__main__':
259 sys.exit(main())