2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
14 script_dir
= os
.path
.dirname(os
.path
.realpath(__file__
))
15 chrome_src
= os
.path
.abspath(os
.path
.join(script_dir
, os
.pardir
))
16 SRC_DIR
= os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
)))
17 sys
.path
.insert(1, os
.path
.join(chrome_src
, 'tools'))
18 sys
.path
.insert(0, os
.path
.join(chrome_src
, 'tools', 'gyp', 'pylib'))
19 json_data_file
= os
.path
.join(script_dir
, 'win_toolchain.json')
25 def SetEnvironmentAndGetRuntimeDllDirs():
26 """Sets up os.environ to use the depot_tools VS toolchain with gyp, and
27 returns the location of the VS runtime DLLs so they can be copied into
28 the output directory after gyp generation.
30 vs2013_runtime_dll_dirs
= None
31 depot_tools_win_toolchain
= \
32 bool(int(os
.environ
.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
33 # When running on a non-Windows host, only do this if the SDK has explicitly
34 # been downloaded before (in which case json_data_file will exist).
35 if ((sys
.platform
in ('win32', 'cygwin') or os
.path
.exists(json_data_file
))
36 and depot_tools_win_toolchain
):
37 if not os
.path
.exists(json_data_file
):
39 with
open(json_data_file
, 'r') as tempf
:
40 toolchain_data
= json
.load(tempf
)
42 toolchain
= toolchain_data
['path']
43 version
= toolchain_data
['version']
44 win_sdk
= toolchain_data
.get('win_sdk')
46 win_sdk
= toolchain_data
['win8sdk']
47 wdk
= toolchain_data
['wdk']
48 # TODO(scottmg): The order unfortunately matters in these. They should be
49 # split into separate keys for x86 and x64. (See CopyVsRuntimeDlls call
50 # below). http://crbug.com/345992
51 vs2013_runtime_dll_dirs
= toolchain_data
['runtime_dirs']
53 os
.environ
['GYP_MSVS_OVERRIDE_PATH'] = toolchain
54 os
.environ
['GYP_MSVS_VERSION'] = version
55 # We need to make sure windows_sdk_path is set to the automated
56 # toolchain values in GYP_DEFINES, but don't want to override any
57 # otheroptions.express
59 gyp_defines_dict
= gyp
.NameValueListToDict(gyp
.ShlexEnv('GYP_DEFINES'))
60 gyp_defines_dict
['windows_sdk_path'] = win_sdk
61 os
.environ
['GYP_DEFINES'] = ' '.join('%s=%s' % (k
, pipes
.quote(str(v
)))
62 for k
, v
in gyp_defines_dict
.iteritems())
63 os
.environ
['WINDOWSSDKDIR'] = win_sdk
64 os
.environ
['WDK_DIR'] = wdk
65 # Include the VS runtime in the PATH in case it's not machine-installed.
66 runtime_path
= ';'.join(vs2013_runtime_dll_dirs
)
67 os
.environ
['PATH'] = runtime_path
+ ';' + os
.environ
['PATH']
68 return vs2013_runtime_dll_dirs
72 """Gets the standard version number ('120', '140', etc.) based on
74 if os
.environ
['GYP_MSVS_VERSION'] == '2013':
76 elif os
.environ
['GYP_MSVS_VERSION'] == '2015':
79 raise ValueError('Unexpected GYP_MSVS_VERSION')
82 def _CopyRuntimeImpl(target
, source
):
83 """Copy |source| to |target| if it doesn't already exist or if it
86 if (os
.path
.isdir(os
.path
.dirname(target
)) and
87 (not os
.path
.isfile(target
) or
88 os
.stat(target
).st_mtime
!= os
.stat(source
).st_mtime
)):
89 print 'Copying %s to %s...' % (source
, target
)
90 if os
.path
.exists(target
):
92 shutil
.copy2(source
, target
)
95 def _CopyRuntime2013(target_dir
, source_dir
, dll_pattern
):
96 """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
97 exist, but the target directory does exist."""
98 for file_part
in ('p', 'r'):
99 dll
= dll_pattern
% file_part
100 target
= os
.path
.join(target_dir
, dll
)
101 source
= os
.path
.join(source_dir
, dll
)
102 _CopyRuntimeImpl(target
, source
)
105 def _CopyRuntime2015(target_dir
, source_dir
, dll_pattern
):
106 """Copy both the msvcp and vccorlib runtime DLLs, only if the target doesn't
107 exist, but the target directory does exist."""
108 for file_part
in ('msvcp', 'vccorlib'):
109 dll
= dll_pattern
% file_part
110 target
= os
.path
.join(target_dir
, dll
)
111 source
= os
.path
.join(source_dir
, dll
)
112 _CopyRuntimeImpl(target
, source
)
115 def CopyVsRuntimeDlls(output_dir
, runtime_dirs
):
116 """Copies the VS runtime DLLs from the given |runtime_dirs| to the output
117 directory so that even if not system-installed, built binaries are likely to
120 This needs to be run after gyp has been run so that the expected target
121 output directories are already created.
123 x86
, x64
= runtime_dirs
124 out_debug
= os
.path
.join(output_dir
, 'Debug')
125 out_debug_nacl64
= os
.path
.join(output_dir
, 'Debug', 'x64')
126 out_release
= os
.path
.join(output_dir
, 'Release')
127 out_release_nacl64
= os
.path
.join(output_dir
, 'Release', 'x64')
128 out_debug_x64
= os
.path
.join(output_dir
, 'Debug_x64')
129 out_release_x64
= os
.path
.join(output_dir
, 'Release_x64')
131 if os
.path
.exists(out_debug
) and not os
.path
.exists(out_debug_nacl64
):
132 os
.makedirs(out_debug_nacl64
)
133 if os
.path
.exists(out_release
) and not os
.path
.exists(out_release_nacl64
):
134 os
.makedirs(out_release_nacl64
)
135 if os
.environ
.get('GYP_MSVS_VERSION') == '2015':
136 _CopyRuntime2015(out_debug
, x86
, '%s140d.dll')
137 _CopyRuntime2015(out_release
, x86
, '%s140.dll')
138 _CopyRuntime2015(out_debug_x64
, x64
, '%s140d.dll')
139 _CopyRuntime2015(out_release_x64
, x64
, '%s140.dll')
140 _CopyRuntime2015(out_debug_nacl64
, x64
, '%s140d.dll')
141 _CopyRuntime2015(out_release_nacl64
, x64
, '%s140.dll')
143 # VS2013 is the default.
144 _CopyRuntime2013(out_debug
, x86
, 'msvc%s120d.dll')
145 _CopyRuntime2013(out_release
, x86
, 'msvc%s120.dll')
146 _CopyRuntime2013(out_debug_x64
, x64
, 'msvc%s120d.dll')
147 _CopyRuntime2013(out_release_x64
, x64
, 'msvc%s120.dll')
148 _CopyRuntime2013(out_debug_nacl64
, x64
, 'msvc%s120d.dll')
149 _CopyRuntime2013(out_release_nacl64
, x64
, 'msvc%s120.dll')
151 # Copy the PGO runtime library to the release directories.
152 if os
.environ
.get('GYP_MSVS_OVERRIDE_PATH'):
153 pgo_x86_runtime_dir
= os
.path
.join(os
.environ
.get('GYP_MSVS_OVERRIDE_PATH'),
155 pgo_x64_runtime_dir
= os
.path
.join(pgo_x86_runtime_dir
, 'amd64')
156 pgo_runtime_dll
= 'pgort' + _VersionNumber() + '.dll'
157 source_x86
= os
.path
.join(pgo_x86_runtime_dir
, pgo_runtime_dll
)
158 if os
.path
.exists(source_x86
):
159 _CopyRuntimeImpl(os
.path
.join(out_release
, pgo_runtime_dll
), source_x86
)
160 source_x64
= os
.path
.join(pgo_x64_runtime_dir
, pgo_runtime_dll
)
161 if os
.path
.exists(source_x64
):
162 _CopyRuntimeImpl(os
.path
.join(out_release_x64
, pgo_runtime_dll
),
166 def CopyDlls(target_dir
, configuration
, target_cpu
):
167 """Copy the VS runtime DLLs into the requested directory as needed.
169 configuration is one of 'Debug' or 'Release'.
170 target_cpu is one of 'x86' or 'x64'.
172 The debug configuration gets both the debug and release DLLs; the
173 release config only the latter.
175 vs2013_runtime_dll_dirs
= SetEnvironmentAndGetRuntimeDllDirs()
176 if not vs2013_runtime_dll_dirs
:
179 x64_runtime
, x86_runtime
= vs2013_runtime_dll_dirs
180 runtime_dir
= x64_runtime
if target_cpu
== 'x64' else x86_runtime
182 target_dir
, runtime_dir
, 'msvc%s' + _VersionNumber() + '.dll')
183 if configuration
== 'Debug':
185 target_dir
, runtime_dir
, 'msvc%s' + _VersionNumber() + 'd.dll')
188 def _GetDesiredVsToolchainHashes():
189 """Load a list of SHA1s corresponding to the toolchains that we want installed
191 if os
.environ
.get('GYP_MSVS_VERSION') == '2015':
192 return ['49ae4b60d898182fc3f521c2fcda82c453915011']
195 return ['ee7d718ec60c2dc5d255bbe325909c2021a7efef']
198 def Update(force
=False):
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()|.
203 if force
!= False and force
!= '--force':
204 print >>sys
.stderr
, 'Unknown parameter "%s"' % force
206 if force
== '--force' or os
.path
.exists(json_data_file
):
209 depot_tools_win_toolchain
= \
210 bool(int(os
.environ
.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
211 if ((sys
.platform
in ('win32', 'cygwin') or force
) and
212 depot_tools_win_toolchain
):
213 import find_depot_tools
214 depot_tools_path
= find_depot_tools
.add_depot_tools_to_path()
215 get_toolchain_args
= [
217 os
.path
.join(depot_tools_path
,
219 'get_toolchain_if_necessary.py'),
220 '--output-json', json_data_file
,
221 ] + _GetDesiredVsToolchainHashes()
223 get_toolchain_args
.append('--force')
224 subprocess
.check_call(get_toolchain_args
)
229 def GetToolchainDir():
230 """Gets location information about the current toolchain (must have been
231 previously updated by 'update'). This is used for the GN build."""
232 runtime_dll_dirs
= SetEnvironmentAndGetRuntimeDllDirs()
234 # If WINDOWSSDKDIR is not set, search the default SDK path and set it.
235 if not 'WINDOWSSDKDIR' in os
.environ
:
236 default_sdk_path
= 'C:\\Program Files (x86)\\Windows Kits\\8.1'
237 if os
.path
.isdir(default_sdk_path
):
238 os
.environ
['WINDOWSSDKDIR'] = default_sdk_path
240 print '''vs_path = "%s"
246 os
.environ
['GYP_MSVS_OVERRIDE_PATH'],
247 os
.environ
['WINDOWSSDKDIR'],
248 os
.environ
['GYP_MSVS_VERSION'],
249 os
.environ
.get('WDK_DIR', ''),
250 ';'.join(runtime_dll_dirs
or ['None']))
256 'get_toolchain_dir': GetToolchainDir
,
257 'copy_dlls': CopyDlls
,
259 if len(sys
.argv
) < 2 or sys
.argv
[1] not in commands
:
260 print >>sys
.stderr
, 'Expected one of: %s' % ', '.join(commands
)
262 return commands
[sys
.argv
[1]](*sys
.argv
[2:])
265 if __name__
== '__main__':