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

Side by Side Diff: build/toolchain/win/setup_toolchain.py

Issue 3002853002: [infra] Remove dependence on //third_party/gyp/pylib/gyp/win_tool.py (Closed)
Patch Set: Remove commented code Created 3 years, 4 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/toolchain/win/midl.gni ('k') | build/toolchain/win/tool_wrapper.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 # 4 #
5 # Copies the given "win tool" (which the toolchain uses to wrap compiler 5 # Copies the given "win tool" (which the toolchain uses to wrap compiler
6 # invocations) and the environment blocks for the 32-bit and 64-bit builds on 6 # invocations) and the environment blocks for the 32-bit and 64-bit builds on
7 # Windows to the build directory. 7 # Windows to the build directory.
8 # 8 #
9 # The arguments are the visual studio install location and the location of the 9 # The arguments are the visual studio install location and the location of the
10 # win tool. The script assumes that the root build directory is the current dir 10 # win tool. The script assumes that the root build directory is the current dir
11 # and the files will be written to the current directory. 11 # and the files will be written to the current directory.
12 12
13 import errno 13 import errno
14 import json
14 import os 15 import os
15 import re 16 import re
16 import subprocess 17 import subprocess
17 import sys 18 import sys
18 19
20 sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
21 import gn_helpers
22
23 SCRIPT_DIR = os.path.dirname(__file__)
19 24
20 def _ExtractImportantEnvironment(output_of_set): 25 def _ExtractImportantEnvironment(output_of_set):
21 """Extracts environment variables required for the toolchain to run from 26 """Extracts environment variables required for the toolchain to run from
22 a textual dump output by the cmd.exe 'set' command.""" 27 a textual dump output by the cmd.exe 'set' command."""
23 envvars_to_save = ( 28 envvars_to_save = (
24 'goma_.*', # TODO(scottmg): This is ugly, but needed for goma. 29 'goma_.*', # TODO(scottmg): This is ugly, but needed for goma.
25 'include', 30 'include',
26 'lib', 31 'lib',
27 'libpath', 32 'libpath',
28 'path', 33 'path',
29 'pathext', 34 'pathext',
30 'systemroot', 35 'systemroot',
31 'temp', 36 'temp',
32 'tmp', 37 'tmp',
33 ) 38 )
34 env = {} 39 env = {}
40 # This occasionally happens and leads to misleading SYSTEMROOT error messages
41 # if not caught here.
42 if output_of_set.count('=') == 0:
43 raise Exception('Invalid output_of_set. Value is:\n%s' % output_of_set)
35 for line in output_of_set.splitlines(): 44 for line in output_of_set.splitlines():
36 for envvar in envvars_to_save: 45 for envvar in envvars_to_save:
37 if re.match(envvar + '=', line.lower()): 46 if re.match(envvar + '=', line.lower()):
38 var, setting = line.split('=', 1) 47 var, setting = line.split('=', 1)
39 if envvar == 'path': 48 if envvar == 'path':
40 # Our own rules (for running gyp-win-tool) and other actions in 49 # Our own rules and actions in Chromium rely on python being in the
41 # Chromium rely on python being in the path. Add the path to this 50 # path. Add the path to this python here so that if it's not in the
42 # python here so that if it's not in the path when ninja is run 51 # path when ninja is run later, python will still be found.
43 # later, python will still be found.
44 setting = os.path.dirname(sys.executable) + os.pathsep + setting 52 setting = os.path.dirname(sys.executable) + os.pathsep + setting
45 env[var.upper()] = setting 53 env[var.upper()] = setting.lower()
46 break 54 break
47 for required in ('SYSTEMROOT', 'TEMP', 'TMP'): 55 if sys.platform in ('win32', 'cygwin'):
48 if required not in env: 56 for required in ('SYSTEMROOT', 'TEMP', 'TMP'):
49 raise Exception('Environment variable "%s" ' 57 if required not in env:
50 'required to be set to valid path' % required) 58 raise Exception('Environment variable "%s" '
59 'required to be set to valid path' % required)
51 return env 60 return env
52 61
53 62
54 def _SetupScript(target_cpu, sdk_dir): 63 def _DetectVisualStudioPath():
55 """Returns a command (with arguments) to be used to set up the 64 """Return path to the GYP_MSVS_VERSION of Visual Studio.
56 environment.""" 65 """
66
67 # Use the code in build/vs_toolchain.py to avoid duplicating code.
68 chromium_dir = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..', '..'))
69 sys.path.append(os.path.join(chromium_dir, 'build'))
70 import vs_toolchain
71 return vs_toolchain.DetectVisualStudioPath()
72
73
74 def _LoadEnvFromBat(args):
75 """Given a bat command, runs it and returns env vars set by it."""
76 args = args[:]
77 args.extend(('&&', 'set'))
78 popen = subprocess.Popen(
79 args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
80 variables, _ = popen.communicate()
81 if popen.returncode != 0:
82 raise Exception('"%s" failed with error %d' % (args, popen.returncode))
83 return variables
84
85
86 def _LoadToolchainEnv(cpu, sdk_dir):
87 """Returns a dictionary with environment variables that must be set while
88 running binaries from the toolchain (e.g. INCLUDE and PATH for cl.exe)."""
57 # Check if we are running in the SDK command line environment and use 89 # Check if we are running in the SDK command line environment and use
58 # the setup script from the SDK if so. |target_cpu| should be either 90 # the setup script from the SDK if so. |cpu| should be either
59 # 'x86' or 'x64'. 91 # 'x86' or 'x64'.
60 assert target_cpu in ('x86', 'x64') 92 assert cpu in ('x86', 'x64')
61 if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', 1))) and sdk_dir: 93 if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', 1))) and sdk_dir:
62 return [os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.Cmd')), 94 # Load environment from json file.
63 '/' + target_cpu] 95 env = os.path.normpath(os.path.join(sdk_dir, 'bin/SetEnv.%s.json' % cpu))
96 env = json.load(open(env))['env']
97 for k in env:
98 entries = [os.path.join(*([os.path.join(sdk_dir, 'bin')] + e))
99 for e in env[k]]
100 # clang-cl wants INCLUDE to be ;-separated even on non-Windows,
101 # lld-link wants LIB to be ;-separated even on non-Windows. Path gets :.
102 # The separator for INCLUDE here must match the one used in main() below.
103 sep = os.pathsep if k == 'PATH' else ';'
104 env[k] = sep.join(entries)
105 # PATH is a bit of a special case, it's in addition to the current PATH.
106 env['PATH'] = env['PATH'] + os.pathsep + os.environ['PATH']
107 # Augment with the current env to pick up TEMP and friends.
108 for k in os.environ:
109 if k not in env:
110 env[k] = os.environ[k]
111
112 varlines = []
113 for k in sorted(env.keys()):
114 varlines.append('%s=%s' % (str(k), str(env[k])))
115 variables = '\n'.join(varlines)
116
117 # Check that the json file contained the same environment as the .cmd file.
118 if sys.platform in ('win32', 'cygwin'):
119 script = os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.cmd'))
120 assert _ExtractImportantEnvironment(variables) == \
121 _ExtractImportantEnvironment(_LoadEnvFromBat([script, '/' + cpu]))
64 else: 122 else:
123 if 'GYP_MSVS_OVERRIDE_PATH' not in os.environ:
124 os.environ['GYP_MSVS_OVERRIDE_PATH'] = _DetectVisualStudioPath()
65 # We only support x64-hosted tools. 125 # We only support x64-hosted tools.
66 # TODO(scottmg|dpranke): Non-depot_tools toolchain: need to get Visual 126 script_path = os.path.normpath(os.path.join(
67 # Studio install location from registry. 127 os.environ['GYP_MSVS_OVERRIDE_PATH'],
68 return [os.path.normpath(os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'], 128 'VC/vcvarsall.bat'))
69 'VC/vcvarsall.bat')), 129 if not os.path.exists(script_path):
70 'amd64_x86' if target_cpu == 'x86' else 'amd64'] 130 # vcvarsall.bat for VS 2017 fails if run after running vcvarsall.bat from
131 # VS 2013 or VS 2015. Fix this by clearing the vsinstalldir environment
132 # variable.
133 if 'VSINSTALLDIR' in os.environ:
134 del os.environ['VSINSTALLDIR']
135 other_path = os.path.normpath(os.path.join(
136 os.environ['GYP_MSVS_OVERRIDE_PATH'],
137 'VC/Auxiliary/Build/vcvarsall.bat'))
138 if not os.path.exists(other_path):
139 raise Exception('%s is missing - make sure VC++ tools are installed.' %
140 script_path)
141 script_path = other_path
142 # Chromium requires the 10.0.14393.0 SDK or higher - previous versions don't
143 # have all of the required declarations.
144 args = [script_path, 'amd64_x86' if cpu == 'x86' else 'amd64']
145 variables = _LoadEnvFromBat(args)
146 return _ExtractImportantEnvironment(variables)
71 147
72 148
73 def _FormatAsEnvironmentBlock(envvar_dict): 149 def _FormatAsEnvironmentBlock(envvar_dict):
74 """Format as an 'environment block' directly suitable for CreateProcess. 150 """Format as an 'environment block' directly suitable for CreateProcess.
75 Briefly this is a list of key=value\0, terminated by an additional \0. See 151 Briefly this is a list of key=value\0, terminated by an additional \0. See
76 CreateProcess documentation for more details.""" 152 CreateProcess documentation for more details."""
77 block = '' 153 block = ''
78 nul = '\0' 154 nul = '\0'
79 for key, value in envvar_dict.iteritems(): 155 for key, value in envvar_dict.iteritems():
80 block += key + '=' + value + nul 156 block += key + '=' + value + nul
81 block += nul 157 block += nul
82 return block 158 return block
83 159
84 160
85 def _CopyTool(source_path):
86 """Copies the given tool to the current directory, including a warning not
87 to edit it."""
88 with open(source_path) as source_file:
89 tool_source = source_file.readlines()
90
91 # Add header and write it out to the current directory (which should be the
92 # root build dir).
93 with open("gyp-win-tool", 'w') as tool_file:
94 tool_file.write(''.join([tool_source[0],
95 '# Generated by setup_toolchain.py do not edit.\n']
96 + tool_source[1:]))
97
98
99 def main(): 161 def main():
100 if len(sys.argv) != 6: 162 if len(sys.argv) != 5:
101 print('Usage setup_toolchain.py ' 163 print('Usage setup_toolchain.py '
102 '<visual studio path> <win tool path> <win sdk path> ' 164 '<visual studio path> <win sdk path> '
103 '<runtime dirs> <target_cpu>') 165 '<runtime dirs> <target_cpu> <include prefix>')
104 sys.exit(2) 166 sys.exit(2)
105 tool_source = sys.argv[2] 167 win_sdk_path = sys.argv[2]
106 win_sdk_path = sys.argv[3] 168 runtime_dirs = sys.argv[3]
107 runtime_dirs = sys.argv[4] 169 target_cpu = sys.argv[4]
108 target_cpu = sys.argv[5]
109
110 _CopyTool(tool_source)
111 170
112 cpus = ('x86', 'x64') 171 cpus = ('x86', 'x64')
113 assert target_cpu in cpus 172 assert target_cpu in cpus
114 vc_bin_dir = '' 173 vc_bin_dir = ''
174 include = ''
115 175
116 # TODO(scottmg|goma): Do we need an equivalent of 176 # TODO(scottmg|goma): Do we need an equivalent of
117 # ninja_use_custom_environment_files? 177 # ninja_use_custom_environment_files?
118 178
119 for cpu in cpus: 179 for cpu in cpus:
120 # Extract environment variables for subprocesses. 180 # Extract environment variables for subprocesses.
121 args = _SetupScript(cpu, win_sdk_path) 181 env = _LoadToolchainEnv(cpu, win_sdk_path)
122 args.extend(('&&', 'set')) 182 env['PATH'] = runtime_dirs + os.pathsep + env['PATH']
123 popen = subprocess.Popen(
124 args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
125 variables, _ = popen.communicate()
126 env = _ExtractImportantEnvironment(variables)
127 env['PATH'] = runtime_dirs + ';' + env['PATH']
128 183
129 if cpu == target_cpu: 184 if cpu == target_cpu:
130 for path in env['PATH'].split(os.pathsep): 185 for path in env['PATH'].split(os.pathsep):
131 if os.path.exists(os.path.join(path, 'cl.exe')): 186 if os.path.exists(os.path.join(path, 'cl.exe')):
132 vc_bin_dir = os.path.realpath(path) 187 vc_bin_dir = os.path.realpath(path)
133 break 188 break
189 # The separator for INCLUDE here must match the one used in
190 # _LoadToolchainEnv() above.
191 include = [p.replace('"', r'\"') for p in env['INCLUDE'].split(';') if p]
192 include_I = ' '.join(['"/I' + i + '"' for i in include])
193 include_imsvc = ' '.join(['"-imsvc' + i + '"' for i in include])
134 194
135 # The Windows SDK include directories must be first. They both have a sal.h,
136 # and the SDK one is newer and the SDK uses some newer features from it not
137 # present in the Visual Studio one.
138
139 if win_sdk_path:
140 additional_includes = ('{sdk_dir}\\Include\\shared;' +
141 '{sdk_dir}\\Include\\um;' +
142 '{sdk_dir}\\Include\\winrt;').format(
143 sdk_dir=win_sdk_path)
144 env['INCLUDE'] = additional_includes + env['INCLUDE']
145 env_block = _FormatAsEnvironmentBlock(env) 195 env_block = _FormatAsEnvironmentBlock(env)
146 with open('environment.' + cpu, 'wb') as f: 196 with open('environment.' + cpu, 'wb') as f:
147 f.write(env_block) 197 f.write(env_block)
148 198
199 # Create a store app version of the environment.
200 if 'LIB' in env:
201 env['LIB'] = env['LIB'] .replace(r'\VC\LIB', r'\VC\LIB\STORE')
202 if 'LIBPATH' in env:
203 env['LIBPATH'] = env['LIBPATH'].replace(r'\VC\LIB', r'\VC\LIB\STORE')
204 env_block = _FormatAsEnvironmentBlock(env)
205 with open('environment.winrt_' + cpu, 'wb') as f:
206 f.write(env_block)
207
149 assert vc_bin_dir 208 assert vc_bin_dir
150 print 'vc_bin_dir = "%s"' % vc_bin_dir 209 print 'vc_bin_dir = ' + gn_helpers.ToGNString(vc_bin_dir)
151 210 assert include_I
211 print 'include_flags_I = ' + gn_helpers.ToGNString(include_I)
212 assert include_imsvc
213 print 'include_flags_imsvc = ' + gn_helpers.ToGNString(include_imsvc)
152 214
153 if __name__ == '__main__': 215 if __name__ == '__main__':
154 main() 216 main()
OLDNEW
« no previous file with comments | « build/toolchain/win/midl.gni ('k') | build/toolchain/win/tool_wrapper.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698