blob: 735827e94316f4125b42d41ed389719955050612 [file] [log] [blame]
scottmg@chromium.org73ab3a52014-03-20 07:01:39 +09001# 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
scottmg@chromium.org73ab3a52014-03-20 07:01:39 +090011
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'))
scottmg@chromium.orgf867a392014-04-09 10:56:20 +090018json_data_file = os.path.join(script_dir, 'win_toolchain.json')
scottmg@chromium.org73ab3a52014-03-20 07:01:39 +090019
20
21import gyp
22
23
scottmg@chromium.orgf867a392014-04-09 10:56:20 +090024def 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.
scottmg@chromium.org73ab3a52014-03-20 07:01:39 +090028 """
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:
scottmg@chromium.org2f8c83b2014-08-14 23:03:30 +090033 if not os.path.exists(json_data_file):
34 Update()
scottmg@chromium.orgf867a392014-04-09 10:56:20 +090035 with open(json_data_file, 'r') as tempf:
scottmg@chromium.org73ab3a52014-03-20 07:01:39 +090036 toolchain_data = json.load(tempf)
scottmg@chromium.org73ab3a52014-03-20 07:01:39 +090037
38 toolchain = toolchain_data['path']
39 version = toolchain_data['version']
40 version_is_pro = version[-1] != 'e'
41 win8sdk = toolchain_data['win8sdk']
42 wdk = toolchain_data['wdk']
43 # TODO(scottmg): The order unfortunately matters in these. They should be
44 # split into separate keys for x86 and x64. (See CopyVsRuntimeDlls call
45 # below). http://crbug.com/345992
46 vs2013_runtime_dll_dirs = toolchain_data['runtime_dirs']
47
48 os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
49 os.environ['GYP_MSVS_VERSION'] = version
50 # We need to make sure windows_sdk_path is set to the automated
51 # toolchain values in GYP_DEFINES, but don't want to override any
52 # otheroptions.express
53 # values there.
54 gyp_defines_dict = gyp.NameValueListToDict(gyp.ShlexEnv('GYP_DEFINES'))
55 gyp_defines_dict['windows_sdk_path'] = win8sdk
56 os.environ['GYP_DEFINES'] = ' '.join('%s=%s' % (k, pipes.quote(str(v)))
57 for k, v in gyp_defines_dict.iteritems())
58 os.environ['WINDOWSSDKDIR'] = win8sdk
59 os.environ['WDK_DIR'] = wdk
60 # Include the VS runtime in the PATH in case it's not machine-installed.
61 runtime_path = ';'.join(vs2013_runtime_dll_dirs)
62 os.environ['PATH'] = runtime_path + ';' + os.environ['PATH']
scottmg@chromium.org73ab3a52014-03-20 07:01:39 +090063 return vs2013_runtime_dll_dirs
64
65
66def CopyVsRuntimeDlls(output_dir, runtime_dirs):
67 """Copies the VS runtime DLLs from the given |runtime_dirs| to the output
68 directory so that even if not system-installed, built binaries are likely to
69 be able to run.
70
71 This needs to be run after gyp has been run so that the expected target
72 output directories are already created.
73 """
74 assert sys.platform.startswith(('win32', 'cygwin'))
75
sebmarchand@chromium.orgf1d42ff2014-07-22 09:18:32 +090076 def copy_runtime_impl(target, source):
77 """Copy |source| to |target| if it doesn't already exist or if it need to be
78 updated.
79 """
80 if (os.path.isdir(os.path.dirname(target)) and
81 (not os.path.isfile(target) or
82 os.stat(target).st_mtime != os.stat(source).st_mtime)):
83 print 'Copying %s to %s...' % (source, target)
84 if os.path.exists(target):
85 os.unlink(target)
86 shutil.copy2(source, target)
87
scottmg@chromium.org73ab3a52014-03-20 07:01:39 +090088 def copy_runtime(target_dir, source_dir, dll_pattern):
89 """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
90 exist, but the target directory does exist."""
91 for which in ('p', 'r'):
92 dll = dll_pattern % which
93 target = os.path.join(target_dir, dll)
94 source = os.path.join(source_dir, dll)
sebmarchand@chromium.orgf1d42ff2014-07-22 09:18:32 +090095 copy_runtime_impl(target, source)
scottmg@chromium.org73ab3a52014-03-20 07:01:39 +090096
97 x86, x64 = runtime_dirs
98 out_debug = os.path.join(output_dir, 'Debug')
99 out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
100 out_release = os.path.join(output_dir, 'Release')
101 out_release_nacl64 = os.path.join(output_dir, 'Release', 'x64')
102 out_debug_x64 = os.path.join(output_dir, 'Debug_x64')
103 out_release_x64 = os.path.join(output_dir, 'Release_x64')
104
105 if os.path.exists(out_debug) and not os.path.exists(out_debug_nacl64):
106 os.makedirs(out_debug_nacl64)
107 if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
108 os.makedirs(out_release_nacl64)
109 copy_runtime(out_debug, x86, 'msvc%s120d.dll')
110 copy_runtime(out_release, x86, 'msvc%s120.dll')
111 copy_runtime(out_debug_x64, x64, 'msvc%s120d.dll')
112 copy_runtime(out_release_x64, x64, 'msvc%s120.dll')
113 copy_runtime(out_debug_nacl64, x64, 'msvc%s120d.dll')
114 copy_runtime(out_release_nacl64, x64, 'msvc%s120.dll')
115
sebmarchand@chromium.orgf1d42ff2014-07-22 09:18:32 +0900116 # Copy the PGO runtime library to the release directories.
117 if os.environ.get('GYP_MSVS_OVERRIDE_PATH'):
118 pgo_x86_runtime_dir = os.path.join(os.environ.get('GYP_MSVS_OVERRIDE_PATH'),
119 'VC', 'bin')
120 pgo_x64_runtime_dir = os.path.join(pgo_x86_runtime_dir, 'amd64')
121 pgo_runtime_dll = 'pgort120.dll'
122 source_x86 = os.path.join(pgo_x86_runtime_dir, pgo_runtime_dll)
123 if os.path.exists(source_x86):
124 copy_runtime_impl(os.path.join(out_release, pgo_runtime_dll), source_x86)
125 source_x64 = os.path.join(pgo_x64_runtime_dir, pgo_runtime_dll)
126 if os.path.exists(source_x64):
127 copy_runtime_impl(os.path.join(out_release_x64, pgo_runtime_dll),
128 source_x64)
129
scottmg@chromium.org73ab3a52014-03-20 07:01:39 +0900130
scottmg@chromium.orgf867a392014-04-09 10:56:20 +0900131def _GetDesiredVsToolchainHashes():
132 """Load a list of SHA1s corresponding to the toolchains that we want installed
133 to build with."""
scottmg@chromium.org1c172fa2014-08-09 09:27:26 +0900134 sha1path = os.path.join(script_dir,
135 '..', 'buildtools', 'toolchain_vs2013.hash')
scottmg@chromium.orgf867a392014-04-09 10:56:20 +0900136 with open(sha1path, 'rb') as f:
137 return f.read().strip().splitlines()
138
139
140def Update():
141 """Requests an update of the toolchain to the specific hashes we have at
142 this revision. The update outputs a .json of the various configuration
143 information required to pass to gyp which we use in |GetToolchainDir()|.
144 """
145 depot_tools_win_toolchain = \
146 bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
147 if sys.platform in ('win32', 'cygwin') and depot_tools_win_toolchain:
148 import find_depot_tools
149 depot_tools_path = find_depot_tools.add_depot_tools_to_path()
150 json_data_file = os.path.join(script_dir, 'win_toolchain.json')
151 get_toolchain_args = [
152 sys.executable,
153 os.path.join(depot_tools_path,
154 'win_toolchain',
155 'get_toolchain_if_necessary.py'),
156 '--output-json', json_data_file,
157 ] + _GetDesiredVsToolchainHashes()
158 subprocess.check_call(get_toolchain_args)
159
scottmg@chromium.org73ab3a52014-03-20 07:01:39 +0900160 return 0
161
scottmg@chromium.org0efdbb72014-03-21 02:42:25 +0900162
scottmg@chromium.orgf867a392014-04-09 10:56:20 +0900163def GetToolchainDir():
164 """Gets location information about the current toolchain (must have been
brettw@chromium.org4d8b4232014-05-29 05:32:01 +0900165 previously updated by 'update'). This is used for the GN build."""
scottmg@chromium.orgf867a392014-04-09 10:56:20 +0900166 SetEnvironmentAndGetRuntimeDllDirs()
brettw@chromium.org4d8b4232014-05-29 05:32:01 +0900167 print '''vs_path = "%s"
168sdk_path = "%s"
169vs_version = "%s"
170wdk_dir = "%s"
171''' % (
172 os.environ['GYP_MSVS_OVERRIDE_PATH'],
173 os.environ['WINDOWSSDKDIR'],
174 os.environ['GYP_MSVS_VERSION'],
175 os.environ['WDK_DIR'])
scottmg@chromium.orgf867a392014-04-09 10:56:20 +0900176
177
178def main():
179 if not sys.platform.startswith(('win32', 'cygwin')):
180 return 0
181 commands = {
182 'update': Update,
183 'get_toolchain_dir': GetToolchainDir,
184 # TODO(scottmg): Add copy_dlls for GN builds (gyp_chromium calls
185 # CopyVsRuntimeDlls via import, currently).
186 }
187 if len(sys.argv) < 2 or sys.argv[1] not in commands:
188 print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
189 return 1
190 return commands[sys.argv[1]]()
191
192
scottmg@chromium.org73ab3a52014-03-20 07:01:39 +0900193if __name__ == '__main__':
194 sys.exit(main())