Chromium Code Reviews| 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 |