Using pre-existing constants instead of hard-coding
[chromium-blink-merge.git] / build / vs_toolchain.py
blob558ad3abeabe7bf3c1a7235c56a90cb27709a766
1 # 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.
5 import json
6 import os
7 import pipes
8 import shutil
9 import subprocess
10 import sys
13 script_dir = os.path.dirname(os.path.realpath(__file__))
14 chrome_src = os.path.abspath(os.path.join(script_dir, os.pardir))
15 SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
16 sys.path.insert(1, os.path.join(chrome_src, 'tools'))
17 sys.path.insert(0, os.path.join(chrome_src, 'tools', 'gyp', 'pylib'))
18 json_data_file = os.path.join(script_dir, 'win_toolchain.json')
21 import gyp
24 def 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 with open(json_data_file, 'r') as tempf:
34 toolchain_data = json.load(tempf)
36 toolchain = toolchain_data['path']
37 version = toolchain_data['version']
38 version_is_pro = version[-1] != 'e'
39 win8sdk = toolchain_data['win8sdk']
40 wdk = toolchain_data['wdk']
41 # TODO(scottmg): The order unfortunately matters in these. They should be
42 # split into separate keys for x86 and x64. (See CopyVsRuntimeDlls call
43 # below). http://crbug.com/345992
44 vs2013_runtime_dll_dirs = toolchain_data['runtime_dirs']
46 os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
47 os.environ['GYP_MSVS_VERSION'] = version
48 # We need to make sure windows_sdk_path is set to the automated
49 # toolchain values in GYP_DEFINES, but don't want to override any
50 # otheroptions.express
51 # values there.
52 gyp_defines_dict = gyp.NameValueListToDict(gyp.ShlexEnv('GYP_DEFINES'))
53 gyp_defines_dict['windows_sdk_path'] = win8sdk
54 os.environ['GYP_DEFINES'] = ' '.join('%s=%s' % (k, pipes.quote(str(v)))
55 for k, v in gyp_defines_dict.iteritems())
56 os.environ['WINDOWSSDKDIR'] = win8sdk
57 os.environ['WDK_DIR'] = wdk
58 # Include the VS runtime in the PATH in case it's not machine-installed.
59 runtime_path = ';'.join(vs2013_runtime_dll_dirs)
60 os.environ['PATH'] = runtime_path + ';' + os.environ['PATH']
61 return vs2013_runtime_dll_dirs
64 def CopyVsRuntimeDlls(output_dir, runtime_dirs):
65 """Copies the VS runtime DLLs from the given |runtime_dirs| to the output
66 directory so that even if not system-installed, built binaries are likely to
67 be able to run.
69 This needs to be run after gyp has been run so that the expected target
70 output directories are already created.
71 """
72 assert sys.platform.startswith(('win32', 'cygwin'))
74 def copy_runtime(target_dir, source_dir, dll_pattern):
75 """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
76 exist, but the target directory does exist."""
77 for which in ('p', 'r'):
78 dll = dll_pattern % which
79 target = os.path.join(target_dir, dll)
80 source = os.path.join(source_dir, dll)
81 # If gyp generated to that output dir, and the runtime isn't already
82 # there, then copy it over.
83 if (os.path.isdir(target_dir) and
84 (not os.path.isfile(target) or
85 os.stat(target).st_mtime != os.stat(source).st_mtime)):
86 print 'Copying %s to %s...' % (source, target)
87 if os.path.exists(target):
88 os.unlink(target)
89 shutil.copy2(source, target)
91 x86, x64 = runtime_dirs
92 out_debug = os.path.join(output_dir, 'Debug')
93 out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
94 out_release = os.path.join(output_dir, 'Release')
95 out_release_nacl64 = os.path.join(output_dir, 'Release', 'x64')
96 out_debug_x64 = os.path.join(output_dir, 'Debug_x64')
97 out_release_x64 = os.path.join(output_dir, 'Release_x64')
99 if os.path.exists(out_debug) and not os.path.exists(out_debug_nacl64):
100 os.makedirs(out_debug_nacl64)
101 if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
102 os.makedirs(out_release_nacl64)
103 copy_runtime(out_debug, x86, 'msvc%s120d.dll')
104 copy_runtime(out_release, x86, 'msvc%s120.dll')
105 copy_runtime(out_debug_x64, x64, 'msvc%s120d.dll')
106 copy_runtime(out_release_x64, x64, 'msvc%s120.dll')
107 copy_runtime(out_debug_nacl64, x64, 'msvc%s120d.dll')
108 copy_runtime(out_release_nacl64, x64, 'msvc%s120.dll')
111 def _GetDesiredVsToolchainHashes():
112 """Load a list of SHA1s corresponding to the toolchains that we want installed
113 to build with."""
114 sha1path = os.path.join(script_dir, 'toolchain_vs2013.hash')
115 with open(sha1path, 'rb') as f:
116 return f.read().strip().splitlines()
119 def Update():
120 """Requests an update of the toolchain to the specific hashes we have at
121 this revision. The update outputs a .json of the various configuration
122 information required to pass to gyp which we use in |GetToolchainDir()|.
124 depot_tools_win_toolchain = \
125 bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
126 if sys.platform in ('win32', 'cygwin') and depot_tools_win_toolchain:
127 import find_depot_tools
128 depot_tools_path = find_depot_tools.add_depot_tools_to_path()
129 json_data_file = os.path.join(script_dir, 'win_toolchain.json')
130 get_toolchain_args = [
131 sys.executable,
132 os.path.join(depot_tools_path,
133 'win_toolchain',
134 'get_toolchain_if_necessary.py'),
135 '--output-json', json_data_file,
136 ] + _GetDesiredVsToolchainHashes()
137 subprocess.check_call(get_toolchain_args)
139 return 0
142 def GetToolchainDir():
143 """Gets location information about the current toolchain (must have been
144 previously updated by 'update'). This is used for the GN build."""
145 SetEnvironmentAndGetRuntimeDllDirs()
146 print '''vs_path = "%s"
147 sdk_path = "%s"
148 vs_version = "%s"
149 wdk_dir = "%s"
150 ''' % (
151 os.environ['GYP_MSVS_OVERRIDE_PATH'],
152 os.environ['WINDOWSSDKDIR'],
153 os.environ['GYP_MSVS_VERSION'],
154 os.environ['WDK_DIR'])
157 def main():
158 if not sys.platform.startswith(('win32', 'cygwin')):
159 return 0
160 commands = {
161 'update': Update,
162 'get_toolchain_dir': GetToolchainDir,
163 # TODO(scottmg): Add copy_dlls for GN builds (gyp_chromium calls
164 # CopyVsRuntimeDlls via import, currently).
166 if len(sys.argv) < 2 or sys.argv[1] not in commands:
167 print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
168 return 1
169 return commands[sys.argv[1]]()
172 if __name__ == '__main__':
173 sys.exit(main())