OLD | NEW |
---|---|
1 # Copyright (c) 2012 Google Inc. All rights reserved. | 1 # Copyright (c) 2012 Google Inc. 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 """ | 5 """ |
6 This module helps emulate Visual Studio 2008 behavior on top of other | 6 This module helps emulate Visual Studio 2008 behavior on top of other |
7 build systems, primarily ninja. | 7 build systems, primarily ninja. |
8 """ | 8 """ |
9 | 9 |
10 import os | 10 import os |
11 import re | 11 import re |
12 import subprocess | 12 import subprocess |
13 import sys | 13 import sys |
14 | 14 |
15 from gyp.common import OrderedSet | |
15 import gyp.MSVSVersion | 16 import gyp.MSVSVersion |
16 | 17 |
17 windows_quoter_regex = re.compile(r'(\\*)"') | 18 windows_quoter_regex = re.compile(r'(\\*)"') |
18 | 19 |
19 def QuoteForRspFile(arg): | 20 def QuoteForRspFile(arg): |
20 """Quote a command line argument so that it appears as one argument when | 21 """Quote a command line argument so that it appears as one argument when |
21 processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for | 22 processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for |
22 Windows programs).""" | 23 Windows programs).""" |
23 # See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment | 24 # See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment |
24 # threads. This is actually the quoting rules for CommandLineToArgvW, not | 25 # threads. This is actually the quoting rules for CommandLineToArgvW, not |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
124 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 125 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
125 for line in p.communicate()[0].splitlines(): | 126 for line in p.communicate()[0].splitlines(): |
126 if 'InstallPath' in line: | 127 if 'InstallPath' in line: |
127 dxsdk_dir = line.split(' ')[3] + "\\" | 128 dxsdk_dir = line.split(' ')[3] + "\\" |
128 | 129 |
129 # Cache return value | 130 # Cache return value |
130 _FindDirectXInstallation.dxsdk_dir = dxsdk_dir | 131 _FindDirectXInstallation.dxsdk_dir = dxsdk_dir |
131 return dxsdk_dir | 132 return dxsdk_dir |
132 | 133 |
133 | 134 |
135 def GetGlobalVSMacroEnv(vs_version): | |
136 """Get a dict of variables mapping internal VS macro names to their gyp | |
137 equivalents. Returns all variables that are independent of the target.""" | |
138 env = {} | |
139 # '$(VSInstallDir)' and '$(VCInstallDir)' are available when and only when | |
140 # Visual Studio is actually installed. | |
141 if vs_version.Path(): | |
142 env['$(VSInstallDir)'] = vs_version.Path() | |
143 env['$(VCInstallDir)'] = os.path.join(vs_version.Path(), 'VC') + '\\' | |
144 # Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be | |
145 # set. This happens when the SDK is sync'd via src-internal, rather than | |
146 # by typical end-user installation of the SDK. If it's not set, we don't | |
147 # want to leave the unexpanded variable in the path, so simply strip it. | |
148 dxsdk_dir = _FindDirectXInstallation() | |
149 env['$(DXSDK_DIR)'] = dxsdk_dir if dxsdk_dir else '' | |
150 # Try to find an installation location for the Windows DDK by checking | |
151 # the WDK_DIR environment variable, may be None. | |
152 env['$(WDK_DIR)'] = os.environ.get('WDK_DIR', '') | |
153 return env | |
154 | |
155 | |
156 def ExtractSharedMSVSSystemIncludes(configs, generator_flags): | |
157 """Finds msvs_system_include_dirs that are common to all targets, removes | |
158 them from all targets, and returns an OrderedSet containing them.""" | |
159 all_system_includes = OrderedSet( | |
scottmg
2014/07/20 05:18:10
I'm vaguely uneasy about differing / \ here, but I
| |
160 configs[0].get('msvs_system_include_dirs', [])) | |
161 for config in configs: | |
scottmg
2014/07/20 05:18:10
configs[1:] maybe would be clearer
Nico
2014/07/20 05:51:02
Done.
| |
162 system_includes = config.get('msvs_system_include_dirs', []) | |
163 all_system_includes = all_system_includes & OrderedSet(system_includes) | |
164 if not all_system_includes: | |
165 return None | |
166 # Expand macros in all_system_includes. | |
167 env = GetGlobalVSMacroEnv(GetVSVersion(generator_flags)) | |
168 expanded_system_includes = OrderedSet([ExpandMacros(include, env) | |
169 for include in all_system_includes]) | |
170 if any(['$' in include for include in expanded_system_includes]): | |
171 # Some path relies on target-specific variables, bail. | |
172 return None | |
173 | |
174 # Remove system includes shared by all targets from the targets. | |
175 for config in configs: | |
176 includes = config.get('msvs_system_include_dirs', []) | |
177 if includes: # Don't insert a msvs_system_include_dirs key if not needed. | |
178 # This must check the unexpanded includes list: | |
179 new_includes = [i for i in includes if i not in all_system_includes] | |
180 config['msvs_system_include_dirs'] = new_includes | |
181 return expanded_system_includes | |
182 | |
183 | |
134 class MsvsSettings(object): | 184 class MsvsSettings(object): |
135 """A class that understands the gyp 'msvs_...' values (especially the | 185 """A class that understands the gyp 'msvs_...' values (especially the |
136 msvs_settings field). They largely correpond to the VS2008 IDE DOM. This | 186 msvs_settings field). They largely correpond to the VS2008 IDE DOM. This |
137 class helps map those settings to command line options.""" | 187 class helps map those settings to command line options.""" |
138 | 188 |
139 def __init__(self, spec, generator_flags): | 189 def __init__(self, spec, generator_flags): |
140 self.spec = spec | 190 self.spec = spec |
141 self.vs_version = GetVSVersion(generator_flags) | 191 self.vs_version = GetVSVersion(generator_flags) |
142 self.dxsdk_dir = _FindDirectXInstallation() | |
143 | |
144 # Try to find an installation location for the Windows DDK by checking | |
145 # the WDK_DIR environment variable, may be None. | |
146 self.wdk_dir = os.environ.get('WDK_DIR') | |
147 | 192 |
148 supported_fields = [ | 193 supported_fields = [ |
149 ('msvs_configuration_attributes', dict), | 194 ('msvs_configuration_attributes', dict), |
150 ('msvs_settings', dict), | 195 ('msvs_settings', dict), |
151 ('msvs_system_include_dirs', list), | 196 ('msvs_system_include_dirs', list), |
152 ('msvs_disabled_warnings', list), | 197 ('msvs_disabled_warnings', list), |
153 ('msvs_precompiled_header', str), | 198 ('msvs_precompiled_header', str), |
154 ('msvs_precompiled_source', str), | 199 ('msvs_precompiled_source', str), |
155 ('msvs_configuration_platform', str), | 200 ('msvs_configuration_platform', str), |
156 ('msvs_target_platform', str), | 201 ('msvs_target_platform', str), |
(...skipping 30 matching lines...) Expand all Loading... | |
187 '$(OutDir)\\': target_dir, | 232 '$(OutDir)\\': target_dir, |
188 '$(TargetDir)\\': target_dir, | 233 '$(TargetDir)\\': target_dir, |
189 '$(IntDir)': '$!INTERMEDIATE_DIR', | 234 '$(IntDir)': '$!INTERMEDIATE_DIR', |
190 '$(InputPath)': '${source}', | 235 '$(InputPath)': '${source}', |
191 '$(InputName)': '${root}', | 236 '$(InputName)': '${root}', |
192 '$(ProjectName)': self.spec['target_name'], | 237 '$(ProjectName)': self.spec['target_name'], |
193 '$(TargetName)': target_name, | 238 '$(TargetName)': target_name, |
194 '$(PlatformName)': target_platform, | 239 '$(PlatformName)': target_platform, |
195 '$(ProjectDir)\\': '', | 240 '$(ProjectDir)\\': '', |
196 } | 241 } |
197 # '$(VSInstallDir)' and '$(VCInstallDir)' are available when and only when | 242 replacements.update(GetGlobalVSMacroEnv(self.vs_version)) |
198 # Visual Studio is actually installed. | |
199 if self.vs_version.Path(): | |
200 replacements['$(VSInstallDir)'] = self.vs_version.Path() | |
201 replacements['$(VCInstallDir)'] = os.path.join(self.vs_version.Path(), | |
202 'VC') + '\\' | |
203 # Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be | |
204 # set. This happens when the SDK is sync'd via src-internal, rather than | |
205 # by typical end-user installation of the SDK. If it's not set, we don't | |
206 # want to leave the unexpanded variable in the path, so simply strip it. | |
207 replacements['$(DXSDK_DIR)'] = self.dxsdk_dir if self.dxsdk_dir else '' | |
208 replacements['$(WDK_DIR)'] = self.wdk_dir if self.wdk_dir else '' | |
209 return replacements | 243 return replacements |
210 | 244 |
211 def ConvertVSMacros(self, s, base_to_build=None, config=None): | 245 def ConvertVSMacros(self, s, base_to_build=None, config=None): |
212 """Convert from VS macro names to something equivalent.""" | 246 """Convert from VS macro names to something equivalent.""" |
213 env = self.GetVSMacroEnv(base_to_build, config=config) | 247 env = self.GetVSMacroEnv(base_to_build, config=config) |
214 return ExpandMacros(s, env) | 248 return ExpandMacros(s, env) |
215 | 249 |
216 def AdjustLibraries(self, libraries): | 250 def AdjustLibraries(self, libraries): |
217 """Strip -l from library if it's specified with that.""" | 251 """Strip -l from library if it's specified with that.""" |
218 libs = [lib[2:] if lib.startswith('-l') else lib for lib in libraries] | 252 libs = [lib[2:] if lib.startswith('-l') else lib for lib in libraries] |
(...skipping 671 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
890 return block | 924 return block |
891 | 925 |
892 def _ExtractCLPath(output_of_where): | 926 def _ExtractCLPath(output_of_where): |
893 """Gets the path to cl.exe based on the output of calling the environment | 927 """Gets the path to cl.exe based on the output of calling the environment |
894 setup batch file, followed by the equivalent of `where`.""" | 928 setup batch file, followed by the equivalent of `where`.""" |
895 # Take the first line, as that's the first found in the PATH. | 929 # Take the first line, as that's the first found in the PATH. |
896 for line in output_of_where.strip().splitlines(): | 930 for line in output_of_where.strip().splitlines(): |
897 if line.startswith('LOC:'): | 931 if line.startswith('LOC:'): |
898 return line[len('LOC:'):].strip() | 932 return line[len('LOC:'):].strip() |
899 | 933 |
900 def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags, open_out): | 934 def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags, |
935 system_includes, open_out): | |
901 """It's not sufficient to have the absolute path to the compiler, linker, | 936 """It's not sufficient to have the absolute path to the compiler, linker, |
902 etc. on Windows, as those tools rely on .dlls being in the PATH. We also | 937 etc. on Windows, as those tools rely on .dlls being in the PATH. We also |
903 need to support both x86 and x64 compilers within the same build (to support | 938 need to support both x86 and x64 compilers within the same build (to support |
904 msvs_target_platform hackery). Different architectures require a different | 939 msvs_target_platform hackery). Different architectures require a different |
905 compiler binary, and different supporting environment variables (INCLUDE, | 940 compiler binary, and different supporting environment variables (INCLUDE, |
906 LIB, LIBPATH). So, we extract the environment here, wrap all invocations | 941 LIB, LIBPATH). So, we extract the environment here, wrap all invocations |
907 of compiler tools (cl, link, lib, rc, midl, etc.) via win_tool.py which | 942 of compiler tools (cl, link, lib, rc, midl, etc.) via win_tool.py which |
908 sets up the environment, and then we do not prefix the compiler with | 943 sets up the environment, and then we do not prefix the compiler with |
909 an absolute path, instead preferring something like "cl.exe" in the rule | 944 an absolute path, instead preferring something like "cl.exe" in the rule |
910 which will then run whichever the environment setup has put in the path. | 945 which will then run whichever the environment setup has put in the path. |
(...skipping 10 matching lines...) Expand all Loading... | |
921 vs = GetVSVersion(generator_flags) | 956 vs = GetVSVersion(generator_flags) |
922 cl_paths = {} | 957 cl_paths = {} |
923 for arch in archs: | 958 for arch in archs: |
924 # Extract environment variables for subprocesses. | 959 # Extract environment variables for subprocesses. |
925 args = vs.SetupScript(arch) | 960 args = vs.SetupScript(arch) |
926 args.extend(('&&', 'set')) | 961 args.extend(('&&', 'set')) |
927 popen = subprocess.Popen( | 962 popen = subprocess.Popen( |
928 args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | 963 args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
929 variables, _ = popen.communicate() | 964 variables, _ = popen.communicate() |
930 env = _ExtractImportantEnvironment(variables) | 965 env = _ExtractImportantEnvironment(variables) |
966 | |
967 # Inject system includes from gyp files into INCLUDE. | |
968 if system_includes: | |
969 system_includes = system_includes | OrderedSet( | |
970 env.get('INCLUDE', '').split(';')) | |
971 env['INCLUDE'] = ';'.join(system_includes) | |
972 | |
931 env_block = _FormatAsEnvironmentBlock(env) | 973 env_block = _FormatAsEnvironmentBlock(env) |
932 f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb') | 974 f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb') |
933 f.write(env_block) | 975 f.write(env_block) |
934 f.close() | 976 f.close() |
935 | 977 |
936 # Find cl.exe location for this architecture. | 978 # Find cl.exe location for this architecture. |
937 args = vs.SetupScript(arch) | 979 args = vs.SetupScript(arch) |
938 args.extend(('&&', | 980 args.extend(('&&', |
939 'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i')) | 981 'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i')) |
940 popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE) | 982 popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE) |
(...skipping 28 matching lines...) Expand all Loading... | |
969 | 1011 |
970 # To determine processor word size on Windows, in addition to checking | 1012 # To determine processor word size on Windows, in addition to checking |
971 # PROCESSOR_ARCHITECTURE (which reflects the word size of the current | 1013 # PROCESSOR_ARCHITECTURE (which reflects the word size of the current |
972 # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which | 1014 # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which |
973 # contains the actual word size of the system when running thru WOW64). | 1015 # contains the actual word size of the system when running thru WOW64). |
974 if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or | 1016 if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or |
975 '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')): | 1017 '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')): |
976 default_variables['MSVS_OS_BITS'] = 64 | 1018 default_variables['MSVS_OS_BITS'] = 64 |
977 else: | 1019 else: |
978 default_variables['MSVS_OS_BITS'] = 32 | 1020 default_variables['MSVS_OS_BITS'] = 32 |
OLD | NEW |