| 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 def ExtractSharedMSVSSystemIncludes(configs, generator_flags): |
| 156 """Finds msvs_system_include_dirs that are common to all targets, removes |
| 157 them from all targets, and returns an OrderedSet containing them.""" |
| 158 all_system_includes = OrderedSet( |
| 159 configs[0].get('msvs_system_include_dirs', [])) |
| 160 for config in configs[1:]: |
| 161 system_includes = config.get('msvs_system_include_dirs', []) |
| 162 all_system_includes = all_system_includes & OrderedSet(system_includes) |
| 163 if not all_system_includes: |
| 164 return None |
| 165 # Expand macros in all_system_includes. |
| 166 env = GetGlobalVSMacroEnv(GetVSVersion(generator_flags)) |
| 167 expanded_system_includes = OrderedSet([ExpandMacros(include, env) |
| 168 for include in all_system_includes]) |
| 169 if any(['$' in include for include in expanded_system_includes]): |
| 170 # Some path relies on target-specific variables, bail. |
| 171 return None |
| 172 |
| 173 # Remove system includes shared by all targets from the targets. |
| 174 for config in configs: |
| 175 includes = config.get('msvs_system_include_dirs', []) |
| 176 if includes: # Don't insert a msvs_system_include_dirs key if not needed. |
| 177 # This must check the unexpanded includes list: |
| 178 new_includes = [i for i in includes if i not in all_system_includes] |
| 179 config['msvs_system_include_dirs'] = new_includes |
| 180 return expanded_system_includes |
| 181 |
| 182 |
| 134 class MsvsSettings(object): | 183 class MsvsSettings(object): |
| 135 """A class that understands the gyp 'msvs_...' values (especially the | 184 """A class that understands the gyp 'msvs_...' values (especially the |
| 136 msvs_settings field). They largely correpond to the VS2008 IDE DOM. This | 185 msvs_settings field). They largely correpond to the VS2008 IDE DOM. This |
| 137 class helps map those settings to command line options.""" | 186 class helps map those settings to command line options.""" |
| 138 | 187 |
| 139 def __init__(self, spec, generator_flags): | 188 def __init__(self, spec, generator_flags): |
| 140 self.spec = spec | 189 self.spec = spec |
| 141 self.vs_version = GetVSVersion(generator_flags) | 190 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 | 191 |
| 148 supported_fields = [ | 192 supported_fields = [ |
| 149 ('msvs_configuration_attributes', dict), | 193 ('msvs_configuration_attributes', dict), |
| 150 ('msvs_settings', dict), | 194 ('msvs_settings', dict), |
| 151 ('msvs_system_include_dirs', list), | 195 ('msvs_system_include_dirs', list), |
| 152 ('msvs_disabled_warnings', list), | 196 ('msvs_disabled_warnings', list), |
| 153 ('msvs_precompiled_header', str), | 197 ('msvs_precompiled_header', str), |
| 154 ('msvs_precompiled_source', str), | 198 ('msvs_precompiled_source', str), |
| 155 ('msvs_configuration_platform', str), | 199 ('msvs_configuration_platform', str), |
| 156 ('msvs_target_platform', str), | 200 ('msvs_target_platform', str), |
| (...skipping 30 matching lines...) Expand all Loading... |
| 187 '$(OutDir)\\': target_dir, | 231 '$(OutDir)\\': target_dir, |
| 188 '$(TargetDir)\\': target_dir, | 232 '$(TargetDir)\\': target_dir, |
| 189 '$(IntDir)': '$!INTERMEDIATE_DIR', | 233 '$(IntDir)': '$!INTERMEDIATE_DIR', |
| 190 '$(InputPath)': '${source}', | 234 '$(InputPath)': '${source}', |
| 191 '$(InputName)': '${root}', | 235 '$(InputName)': '${root}', |
| 192 '$(ProjectName)': self.spec['target_name'], | 236 '$(ProjectName)': self.spec['target_name'], |
| 193 '$(TargetName)': target_name, | 237 '$(TargetName)': target_name, |
| 194 '$(PlatformName)': target_platform, | 238 '$(PlatformName)': target_platform, |
| 195 '$(ProjectDir)\\': '', | 239 '$(ProjectDir)\\': '', |
| 196 } | 240 } |
| 197 # '$(VSInstallDir)' and '$(VCInstallDir)' are available when and only when | 241 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 | 242 return replacements |
| 210 | 243 |
| 211 def ConvertVSMacros(self, s, base_to_build=None, config=None): | 244 def ConvertVSMacros(self, s, base_to_build=None, config=None): |
| 212 """Convert from VS macro names to something equivalent.""" | 245 """Convert from VS macro names to something equivalent.""" |
| 213 env = self.GetVSMacroEnv(base_to_build, config=config) | 246 env = self.GetVSMacroEnv(base_to_build, config=config) |
| 214 return ExpandMacros(s, env) | 247 return ExpandMacros(s, env) |
| 215 | 248 |
| 216 def AdjustLibraries(self, libraries): | 249 def AdjustLibraries(self, libraries): |
| 217 """Strip -l from library if it's specified with that.""" | 250 """Strip -l from library if it's specified with that.""" |
| 218 libs = [lib[2:] if lib.startswith('-l') else lib for lib in libraries] | 251 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 | 923 return block |
| 891 | 924 |
| 892 def _ExtractCLPath(output_of_where): | 925 def _ExtractCLPath(output_of_where): |
| 893 """Gets the path to cl.exe based on the output of calling the environment | 926 """Gets the path to cl.exe based on the output of calling the environment |
| 894 setup batch file, followed by the equivalent of `where`.""" | 927 setup batch file, followed by the equivalent of `where`.""" |
| 895 # Take the first line, as that's the first found in the PATH. | 928 # Take the first line, as that's the first found in the PATH. |
| 896 for line in output_of_where.strip().splitlines(): | 929 for line in output_of_where.strip().splitlines(): |
| 897 if line.startswith('LOC:'): | 930 if line.startswith('LOC:'): |
| 898 return line[len('LOC:'):].strip() | 931 return line[len('LOC:'):].strip() |
| 899 | 932 |
| 900 def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags, open_out): | 933 def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags, |
| 934 system_includes, open_out): |
| 901 """It's not sufficient to have the absolute path to the compiler, linker, | 935 """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 | 936 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 | 937 need to support both x86 and x64 compilers within the same build (to support |
| 904 msvs_target_platform hackery). Different architectures require a different | 938 msvs_target_platform hackery). Different architectures require a different |
| 905 compiler binary, and different supporting environment variables (INCLUDE, | 939 compiler binary, and different supporting environment variables (INCLUDE, |
| 906 LIB, LIBPATH). So, we extract the environment here, wrap all invocations | 940 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 | 941 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 | 942 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 | 943 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. | 944 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) | 955 vs = GetVSVersion(generator_flags) |
| 922 cl_paths = {} | 956 cl_paths = {} |
| 923 for arch in archs: | 957 for arch in archs: |
| 924 # Extract environment variables for subprocesses. | 958 # Extract environment variables for subprocesses. |
| 925 args = vs.SetupScript(arch) | 959 args = vs.SetupScript(arch) |
| 926 args.extend(('&&', 'set')) | 960 args.extend(('&&', 'set')) |
| 927 popen = subprocess.Popen( | 961 popen = subprocess.Popen( |
| 928 args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | 962 args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
| 929 variables, _ = popen.communicate() | 963 variables, _ = popen.communicate() |
| 930 env = _ExtractImportantEnvironment(variables) | 964 env = _ExtractImportantEnvironment(variables) |
| 965 |
| 966 # Inject system includes from gyp files into INCLUDE. |
| 967 if system_includes: |
| 968 system_includes = system_includes | OrderedSet( |
| 969 env.get('INCLUDE', '').split(';')) |
| 970 env['INCLUDE'] = ';'.join(system_includes) |
| 971 |
| 931 env_block = _FormatAsEnvironmentBlock(env) | 972 env_block = _FormatAsEnvironmentBlock(env) |
| 932 f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb') | 973 f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb') |
| 933 f.write(env_block) | 974 f.write(env_block) |
| 934 f.close() | 975 f.close() |
| 935 | 976 |
| 936 # Find cl.exe location for this architecture. | 977 # Find cl.exe location for this architecture. |
| 937 args = vs.SetupScript(arch) | 978 args = vs.SetupScript(arch) |
| 938 args.extend(('&&', | 979 args.extend(('&&', |
| 939 'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i')) | 980 'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i')) |
| 940 popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE) | 981 popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE) |
| (...skipping 28 matching lines...) Expand all Loading... |
| 969 | 1010 |
| 970 # To determine processor word size on Windows, in addition to checking | 1011 # To determine processor word size on Windows, in addition to checking |
| 971 # PROCESSOR_ARCHITECTURE (which reflects the word size of the current | 1012 # PROCESSOR_ARCHITECTURE (which reflects the word size of the current |
| 972 # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which | 1013 # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which |
| 973 # contains the actual word size of the system when running thru WOW64). | 1014 # contains the actual word size of the system when running thru WOW64). |
| 974 if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or | 1015 if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or |
| 975 '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')): | 1016 '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')): |
| 976 default_variables['MSVS_OS_BITS'] = 64 | 1017 default_variables['MSVS_OS_BITS'] = 64 |
| 977 else: | 1018 else: |
| 978 default_variables['MSVS_OS_BITS'] = 32 | 1019 default_variables['MSVS_OS_BITS'] = 32 |
| OLD | NEW |