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

Side by Side Diff: build_gyp/vs_toolchain.py

Issue 1933843002: Use utilities from build directory instead of own copies (Closed) Base URL: https://pdfium.googlesource.com/pdfium.git@master
Patch Set: fix Created 4 years, 7 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
« no previous file with comments | « build_gyp/standalone.gypi ('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 #!/usr/bin/env python
2 # Copyright 2016 PDFium 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.
5
6 import glob
7 import json
8 import os
9 import pipes
10 import shutil
11 import subprocess
12 import sys
13
14
15 script_dir = os.path.dirname(os.path.realpath(__file__))
16 src_root = os.path.abspath(os.path.join(script_dir, os.pardir))
17 SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
18 # Add gyp path which is needed to import gyp.
19 sys.path.insert(0, os.path.join(src_root, 'tools', 'gyp', 'pylib'))
20 json_data_file = os.path.join(script_dir, 'win_toolchain.json')
21
22
23 import gyp
24
25
26 # Use MSVS2015 as the default toolchain.
27 CURRENT_DEFAULT_TOOLCHAIN_VERSION = '2015'
28
29
30 def SetEnvironmentAndGetRuntimeDllDirs():
31 """Sets up os.environ to use the depot_tools VS toolchain with gyp, and
32 returns the location of the VS runtime DLLs so they can be copied into
33 the output directory after gyp generation.
34 """
35 vs_runtime_dll_dirs = None
36 depot_tools_win_toolchain = \
37 bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
38 # When running on a non-Windows host, only do this if the SDK has explicitly
39 # been downloaded before (in which case json_data_file will exist).
40 if ((sys.platform in ('win32', 'cygwin') or os.path.exists(json_data_file))
41 and depot_tools_win_toolchain):
42 if ShouldUpdateToolchain():
43 Update()
44 with open(json_data_file, 'r') as tempf:
45 toolchain_data = json.load(tempf)
46
47 toolchain = toolchain_data['path']
48 version = toolchain_data['version']
49 win_sdk = toolchain_data.get('win_sdk')
50 if not win_sdk:
51 win_sdk = toolchain_data['win8sdk']
52 wdk = toolchain_data['wdk']
53 # TODO(scottmg): The order unfortunately matters in these. They should be
54 # split into separate keys for x86 and x64. (See CopyVsRuntimeDlls call
55 # below). http://crbug.com/345992
56 vs_runtime_dll_dirs = toolchain_data['runtime_dirs']
57
58 os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
59 os.environ['GYP_MSVS_VERSION'] = version
60 # We need to make sure windows_sdk_path is set to the automated
61 # toolchain values in GYP_DEFINES, but don't want to override any
62 # otheroptions.express
63 # values there.
64 gyp_defines_dict = gyp.NameValueListToDict(gyp.ShlexEnv('GYP_DEFINES'))
65 gyp_defines_dict['windows_sdk_path'] = win_sdk
66 os.environ['GYP_DEFINES'] = ' '.join('%s=%s' % (k, pipes.quote(str(v)))
67 for k, v in gyp_defines_dict.iteritems())
68 os.environ['WINDOWSSDKDIR'] = win_sdk
69 os.environ['WDK_DIR'] = wdk
70 # Include the VS runtime in the PATH in case it's not machine-installed.
71 runtime_path = os.path.pathsep.join(vs_runtime_dll_dirs)
72 os.environ['PATH'] = runtime_path + os.path.pathsep + os.environ['PATH']
73 elif sys.platform == 'win32' and not depot_tools_win_toolchain:
74 if not 'GYP_MSVS_OVERRIDE_PATH' in os.environ:
75 os.environ['GYP_MSVS_OVERRIDE_PATH'] = DetectVisualStudioPath()
76 if not 'GYP_MSVS_VERSION' in os.environ:
77 os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion()
78
79 return vs_runtime_dll_dirs
80
81
82 def _RegistryGetValueUsingWinReg(key, value):
83 """Use the _winreg module to obtain the value of a registry key.
84
85 Args:
86 key: The registry key.
87 value: The particular registry value to read.
88 Return:
89 contents of the registry key's value, or None on failure. Throws
90 ImportError if _winreg is unavailable.
91 """
92 import _winreg
93 try:
94 root, subkey = key.split('\\', 1)
95 assert root == 'HKLM' # Only need HKLM for now.
96 with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, subkey) as hkey:
97 return _winreg.QueryValueEx(hkey, value)[0]
98 except WindowsError:
99 return None
100
101
102 def _RegistryGetValue(key, value):
103 try:
104 return _RegistryGetValueUsingWinReg(key, value)
105 except ImportError:
106 raise Exception('The python library _winreg not found.')
107
108
109 def GetVisualStudioVersion():
110 """Return GYP_MSVS_VERSION of Visual Studio.
111 """
112 return os.environ.get('GYP_MSVS_VERSION', CURRENT_DEFAULT_TOOLCHAIN_VERSION)
113
114
115 def DetectVisualStudioPath():
116 """Return path to the GYP_MSVS_VERSION of Visual Studio.
117 """
118
119 # Note that this code is used from
120 # build/toolchain/win/setup_toolchain.py as well.
121 version_as_year = GetVisualStudioVersion()
122 year_to_version = {
123 '2013': '12.0',
124 '2015': '14.0',
125 }
126 if version_as_year not in year_to_version:
127 raise Exception(('Visual Studio version %s (from GYP_MSVS_VERSION)'
128 ' not supported. Supported versions are: %s') % (
129 version_as_year, ', '.join(year_to_version.keys())))
130 version = year_to_version[version_as_year]
131 keys = [r'HKLM\Software\Microsoft\VisualStudio\%s' % version,
132 r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\%s' % version]
133 for key in keys:
134 path = _RegistryGetValue(key, 'InstallDir')
135 if not path:
136 continue
137 path = os.path.normpath(os.path.join(path, '..', '..'))
138 return path
139
140 raise Exception(('Visual Studio Version %s (from GYP_MSVS_VERSION)'
141 ' not found.') % (version_as_year))
142
143
144 def _VersionNumber():
145 """Gets the standard version number ('120', '140', etc.) based on
146 GYP_MSVS_VERSION."""
147 vs_version = GetVisualStudioVersion()
148 if vs_version == '2013':
149 return '120'
150 elif vs_version == '2015':
151 return '140'
152 else:
153 raise ValueError('Unexpected GYP_MSVS_VERSION')
154
155
156 def _CopyRuntimeImpl(target, source, verbose=True):
157 """Copy |source| to |target| if it doesn't already exist or if it
158 needs to be updated.
159 """
160 if (os.path.isdir(os.path.dirname(target)) and
161 (not os.path.isfile(target) or
162 os.stat(target).st_mtime != os.stat(source).st_mtime)):
163 if verbose:
164 print 'Copying %s to %s...' % (source, target)
165 if os.path.exists(target):
166 os.unlink(target)
167 shutil.copy2(source, target)
168
169
170 def _CopyRuntime2013(target_dir, source_dir, dll_pattern):
171 """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
172 exist, but the target directory does exist."""
173 for file_part in ('p', 'r'):
174 dll = dll_pattern % file_part
175 target = os.path.join(target_dir, dll)
176 source = os.path.join(source_dir, dll)
177 _CopyRuntimeImpl(target, source)
178
179
180 def _CopyRuntime2015(target_dir, source_dir, dll_pattern, suffix):
181 """Copy both the msvcp and vccorlib runtime DLLs, only if the target doesn't
182 exist, but the target directory does exist."""
183 for file_part in ('msvcp', 'vccorlib', 'vcruntime'):
184 dll = dll_pattern % file_part
185 target = os.path.join(target_dir, dll)
186 source = os.path.join(source_dir, dll)
187 _CopyRuntimeImpl(target, source)
188 ucrt_src_dir = os.path.join(source_dir, 'api-ms-win-*.dll')
189 print 'Copying %s to %s...' % (ucrt_src_dir, target_dir)
190 for ucrt_src_file in glob.glob(ucrt_src_dir):
191 file_part = os.path.basename(ucrt_src_file)
192 ucrt_dst_file = os.path.join(target_dir, file_part)
193 _CopyRuntimeImpl(ucrt_dst_file, ucrt_src_file, False)
194 _CopyRuntimeImpl(os.path.join(target_dir, 'ucrtbase' + suffix),
195 os.path.join(source_dir, 'ucrtbase' + suffix))
196
197
198 def _CopyRuntime(target_dir, source_dir, target_cpu, debug):
199 """Copy the VS runtime DLLs, only if the target doesn't exist, but the target
200 directory does exist. Handles VS 2013 and VS 2015."""
201 suffix = "d.dll" if debug else ".dll"
202 if GetVisualStudioVersion() == '2015':
203 _CopyRuntime2015(target_dir, source_dir, '%s140' + suffix, suffix)
204 else:
205 _CopyRuntime2013(target_dir, source_dir, 'msvc%s120' + suffix)
206
207 # Copy the PGO runtime library to the release directories.
208 if not debug and os.environ.get('GYP_MSVS_OVERRIDE_PATH'):
209 pgo_x86_runtime_dir = os.path.join(os.environ.get('GYP_MSVS_OVERRIDE_PATH'),
210 'VC', 'bin')
211 pgo_x64_runtime_dir = os.path.join(pgo_x86_runtime_dir, 'amd64')
212 pgo_runtime_dll = 'pgort' + _VersionNumber() + '.dll'
213 if target_cpu == "x86":
214 source_x86 = os.path.join(pgo_x86_runtime_dir, pgo_runtime_dll)
215 if os.path.exists(source_x86):
216 _CopyRuntimeImpl(os.path.join(target_dir, pgo_runtime_dll), source_x86)
217 elif target_cpu == "x64":
218 source_x64 = os.path.join(pgo_x64_runtime_dir, pgo_runtime_dll)
219 if os.path.exists(source_x64):
220 _CopyRuntimeImpl(os.path.join(target_dir, pgo_runtime_dll),
221 source_x64)
222 else:
223 raise NotImplementedError("Unexpected target_cpu value:" + target_cpu)
224
225
226 def CopyVsRuntimeDlls(output_dir, runtime_dirs):
227 """Copies the VS runtime DLLs from the given |runtime_dirs| to the output
228 directory so that even if not system-installed, built binaries are likely to
229 be able to run.
230
231 This needs to be run after gyp has been run so that the expected target
232 output directories are already created.
233
234 This is used for the GYP build and gclient runhooks.
235 """
236 x86, x64 = runtime_dirs
237 out_debug = os.path.join(output_dir, 'Debug')
238 out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
239 out_release = os.path.join(output_dir, 'Release')
240 out_release_nacl64 = os.path.join(output_dir, 'Release', 'x64')
241 out_debug_x64 = os.path.join(output_dir, 'Debug_x64')
242 out_release_x64 = os.path.join(output_dir, 'Release_x64')
243
244 if os.path.exists(out_debug) and not os.path.exists(out_debug_nacl64):
245 os.makedirs(out_debug_nacl64)
246 if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
247 os.makedirs(out_release_nacl64)
248 _CopyRuntime(out_debug, x86, "x86", debug=True)
249 _CopyRuntime(out_release, x86, "x86", debug=False)
250 _CopyRuntime(out_debug_x64, x64, "x64", debug=True)
251 _CopyRuntime(out_release_x64, x64, "x64", debug=False)
252 _CopyRuntime(out_debug_nacl64, x64, "x64", debug=True)
253 _CopyRuntime(out_release_nacl64, x64, "x64", debug=False)
254
255
256 def CopyDlls(target_dir, configuration, target_cpu):
257 """Copy the VS runtime DLLs into the requested directory as needed.
258
259 configuration is one of 'Debug' or 'Release'.
260 target_cpu is one of 'x86' or 'x64'.
261
262 The debug configuration gets both the debug and release DLLs; the
263 release config only the latter.
264
265 This is used for the GN build.
266 """
267 vs_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
268 if not vs_runtime_dll_dirs:
269 return
270
271 x64_runtime, x86_runtime = vs_runtime_dll_dirs
272 runtime_dir = x64_runtime if target_cpu == 'x64' else x86_runtime
273 _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=False)
274 if configuration == 'Debug':
275 _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=True)
276
277
278 def _GetDesiredVsToolchainHashes():
279 """Load a list of SHA1s corresponding to the toolchains that we want installed
280 to build with."""
281 if GetVisualStudioVersion() == '2015':
282 # Update 2.
283 return ['95ddda401ec5678f15eeed01d2bee08fcbc5ee97']
284 else:
285 return ['4087e065abebdca6dbd0caca2910c6718d2ec67f']
286
287
288 def ShouldUpdateToolchain():
289 """Check if the toolchain should be upgraded."""
290 if not os.path.exists(json_data_file):
291 return True
292 with open(json_data_file, 'r') as tempf:
293 toolchain_data = json.load(tempf)
294 version = toolchain_data['version']
295 env_version = GetVisualStudioVersion()
296 # If there's a mismatch between the version set in the environment and the one
297 # in the json file then the toolchain should be updated.
298 return version != env_version
299
300
301 def Update(force=False):
302 """Requests an update of the toolchain to the specific hashes we have at
303 this revision. The update outputs a .json of the various configuration
304 information required to pass to gyp which we use in |GetToolchainDir()|.
305 """
306 if force != False and force != '--force':
307 print >>sys.stderr, 'Unknown parameter "%s"' % force
308 return 1
309 if force == '--force' or os.path.exists(json_data_file):
310 force = True
311
312 depot_tools_win_toolchain = \
313 bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
314 if ((sys.platform in ('win32', 'cygwin') or force) and
315 depot_tools_win_toolchain):
316 import find_depot_tools
317 depot_tools_path = find_depot_tools.add_depot_tools_to_path()
318 # Necessary so that get_toolchain_if_necessary.py will put the VS toolkit
319 # in the correct directory.
320 os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion()
321 get_toolchain_args = [
322 sys.executable,
323 os.path.join(depot_tools_path,
324 'win_toolchain',
325 'get_toolchain_if_necessary.py'),
326 '--output-json', json_data_file,
327 ] + _GetDesiredVsToolchainHashes()
328 if force:
329 get_toolchain_args.append('--force')
330 subprocess.check_call(get_toolchain_args)
331
332 return 0
333
334
335 def NormalizePath(path):
336 while path.endswith("\\"):
337 path = path[:-1]
338 return path
339
340
341 def GetToolchainDir():
342 """Gets location information about the current toolchain (must have been
343 previously updated by 'update'). This is used for the GN build."""
344 runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
345
346 # If WINDOWSSDKDIR is not set, search the default SDK path and set it.
347 if not 'WINDOWSSDKDIR' in os.environ:
348 default_sdk_path = 'C:\\Program Files (x86)\\Windows Kits\\10'
349 if os.path.isdir(default_sdk_path):
350 os.environ['WINDOWSSDKDIR'] = default_sdk_path
351
352 print '''vs_path = "%s"
353 sdk_path = "%s"
354 vs_version = "%s"
355 wdk_dir = "%s"
356 runtime_dirs = "%s"
357 ''' % (
358 NormalizePath(os.environ['GYP_MSVS_OVERRIDE_PATH']),
359 NormalizePath(os.environ['WINDOWSSDKDIR']),
360 GetVisualStudioVersion(),
361 NormalizePath(os.environ.get('WDK_DIR', '')),
362 os.path.pathsep.join(runtime_dll_dirs or ['None']))
363
364
365 def main():
366 commands = {
367 'update': Update,
368 'get_toolchain_dir': GetToolchainDir,
369 'copy_dlls': CopyDlls,
370 }
371 if len(sys.argv) < 2 or sys.argv[1] not in commands:
372 print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
373 return 1
374 return commands[sys.argv[1]](*sys.argv[2:])
375
376
377 if __name__ == '__main__':
378 sys.exit(main())
OLDNEW
« no previous file with comments | « build_gyp/standalone.gypi ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698