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

Side by Side Diff: pylib/gyp/msvs_emulation.py

Issue 1454433002: Python 3 compatibility Base URL: https://chromium.googlesource.com/external/gyp.git@master
Patch Set: Rebase with master (4ec6c4e3a94bd04a6da2858163d40b2429b8aad1) Created 4 years, 8 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
OLDNEW
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 collections
10 import os 11 import os
11 import re 12 import re
12 import subprocess 13 import subprocess
13 import sys 14 import sys
14 15
15 from gyp.common import OrderedSet 16 from gyp.common import OrderedSet
16 import gyp.MSVSUtil 17 import gyp.MSVSUtil
17 import gyp.MSVSVersion 18 import gyp.MSVSVersion
18 19
20 try:
21 basestring = basestring
22 except NameError:
23 basestring = str
19 24
20 windows_quoter_regex = re.compile(r'(\\*)"') 25 windows_quoter_regex = re.compile(r'(\\*)"')
21 26
22 27
23 def QuoteForRspFile(arg): 28 def QuoteForRspFile(arg):
24 """Quote a command line argument so that it appears as one argument when 29 """Quote a command line argument so that it appears as one argument when
25 processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for 30 processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for
26 Windows programs).""" 31 Windows programs)."""
27 # See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment 32 # See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment
28 # threads. This is actually the quoting rules for CommandLineToArgvW, not 33 # threads. This is actually the quoting rules for CommandLineToArgvW, not
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 return default 78 return default
74 if not path: 79 if not path:
75 return root 80 return root
76 return _GenericRetrieve(root.get(path[0]), default, path[1:]) 81 return _GenericRetrieve(root.get(path[0]), default, path[1:])
77 82
78 83
79 def _AddPrefix(element, prefix): 84 def _AddPrefix(element, prefix):
80 """Add |prefix| to |element| or each subelement if element is iterable.""" 85 """Add |prefix| to |element| or each subelement if element is iterable."""
81 if element is None: 86 if element is None:
82 return element 87 return element
83 # Note, not Iterable because we don't want to handle strings like that. 88 if (isinstance(element, collections.Iterable) and
84 if isinstance(element, list) or isinstance(element, tuple): 89 not isinstance(element, basestring)):
85 return [prefix + e for e in element] 90 return [prefix + e for e in element]
86 else: 91 else:
87 return prefix + element 92 return prefix + element
88 93
89 94
90 def _DoRemapping(element, map): 95 def _DoRemapping(element, map):
91 """If |element| then remap it through |map|. If |element| is iterable then 96 """If |element| then remap it through |map|. If |element| is iterable then
92 each item will be remapped. Any elements not found will be removed.""" 97 each item will be remapped. Any elements not found will be removed."""
93 if map is not None and element is not None: 98 if map is not None and element is not None:
94 if not callable(map): 99 if not callable(map):
95 map = map.get # Assume it's a dict, otherwise a callable to do the remap. 100 map = map.get # Assume it's a dict, otherwise a callable to do the remap.
96 if isinstance(element, list) or isinstance(element, tuple): 101 if (isinstance(element, collections.Iterable) and
102 not isinstance(element, basestring)):
97 element = filter(None, [map(elem) for elem in element]) 103 element = filter(None, [map(elem) for elem in element])
98 else: 104 else:
99 element = map(element) 105 element = map(element)
100 return element 106 return element
101 107
102 108
103 def _AppendOrReturn(append, element): 109 def _AppendOrReturn(append, element):
104 """If |append| is None, simply return |element|. If |append| is not None, 110 """If |append| is None, simply return |element|. If |append| is not None,
105 then add |element| to it, adding each item in |element| if it's a list or 111 then add |element| to it, adding each item in |element| if it's a list or
106 tuple.""" 112 tuple."""
107 if append is not None and element is not None: 113 if append is not None and element is not None:
108 if isinstance(element, list) or isinstance(element, tuple): 114 if (isinstance(element, collections.Iterable) and
115 not isinstance(element, basestring)):
109 append.extend(element) 116 append.extend(element)
110 else: 117 else:
111 append.append(element) 118 append.append(element)
112 else: 119 else:
113 return element 120 return element
114 121
115 122
116 def _FindDirectXInstallation(): 123 def _FindDirectXInstallation():
117 """Try to find an installation location for the DirectX SDK. Check for the 124 """Try to find an installation location for the DirectX SDK. Check for the
118 standard environment variable, and if that doesn't exist, try to find 125 standard environment variable, and if that doesn't exist, try to find
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 ('msvs_system_include_dirs', list), 205 ('msvs_system_include_dirs', list),
199 ('msvs_disabled_warnings', list), 206 ('msvs_disabled_warnings', list),
200 ('msvs_precompiled_header', str), 207 ('msvs_precompiled_header', str),
201 ('msvs_precompiled_source', str), 208 ('msvs_precompiled_source', str),
202 ('msvs_configuration_platform', str), 209 ('msvs_configuration_platform', str),
203 ('msvs_target_platform', str), 210 ('msvs_target_platform', str),
204 ] 211 ]
205 configs = spec['configurations'] 212 configs = spec['configurations']
206 for field, default in supported_fields: 213 for field, default in supported_fields:
207 setattr(self, field, {}) 214 setattr(self, field, {})
208 for configname, config in configs.iteritems(): 215 for configname, config in configs.items():
209 getattr(self, field)[configname] = config.get(field, default()) 216 getattr(self, field)[configname] = config.get(field, default())
210 217
211 self.msvs_cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.']) 218 self.msvs_cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.'])
212 219
213 unsupported_fields = [ 220 unsupported_fields = [
214 'msvs_prebuild', 221 'msvs_prebuild',
215 'msvs_postbuild', 222 'msvs_postbuild',
216 ] 223 ]
217 unsupported = [] 224 unsupported = []
218 for field in unsupported_fields: 225 for field in unsupported_fields:
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 cl('AdditionalOptions', prefix='') 472 cl('AdditionalOptions', prefix='')
466 cl('EnableEnhancedInstructionSet', 473 cl('EnableEnhancedInstructionSet',
467 map={'1': 'SSE', '2': 'SSE2', '3': 'AVX', '4': 'IA32', '5': 'AVX2'}, 474 map={'1': 'SSE', '2': 'SSE2', '3': 'AVX', '4': 'IA32', '5': 'AVX2'},
468 prefix='/arch:') 475 prefix='/arch:')
469 cflags.extend(['/FI' + f for f in self._Setting( 476 cflags.extend(['/FI' + f for f in self._Setting(
470 ('VCCLCompilerTool', 'ForcedIncludeFiles'), config, default=[])]) 477 ('VCCLCompilerTool', 'ForcedIncludeFiles'), config, default=[])])
471 if self.vs_version.short_name in ('2013', '2013e', '2015'): 478 if self.vs_version.short_name in ('2013', '2013e', '2015'):
472 # New flag required in 2013 to maintain previous PDB behavior. 479 # New flag required in 2013 to maintain previous PDB behavior.
473 cflags.append('/FS') 480 cflags.append('/FS')
474 # ninja handles parallelism by itself, don't have the compiler do it too. 481 # ninja handles parallelism by itself, don't have the compiler do it too.
475 cflags = filter(lambda x: not x.startswith('/MP'), cflags) 482 cflags = [x for x in cflags if not x.startswith('/MP')]
476 return cflags 483 return cflags
477 484
478 def _GetPchFlags(self, config, extension): 485 def _GetPchFlags(self, config, extension):
479 """Get the flags to be added to the cflags for precompiled header support. 486 """Get the flags to be added to the cflags for precompiled header support.
480 """ 487 """
481 config = self._TargetConfig(config) 488 config = self._TargetConfig(config)
482 # The PCH is only built once by a particular source file. Usage of PCH must 489 # The PCH is only built once by a particular source file. Usage of PCH must
483 # only be for the same language (i.e. C vs. C++), so only include the pch 490 # only be for the same language (i.e. C vs. C++), so only include the pch
484 # flags when the language matches. 491 # flags when the language matches.
485 if self.msvs_precompiled_header[config]: 492 if self.msvs_precompiled_header[config]:
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 if self.GetArch(config) == 'x86': 638 if self.GetArch(config) == 'x86':
632 safeseh_default = 'true' 639 safeseh_default = 'true'
633 else: 640 else:
634 safeseh_default = None 641 safeseh_default = None
635 ld('ImageHasSafeExceptionHandlers', 642 ld('ImageHasSafeExceptionHandlers',
636 map={'false': ':NO', 'true': ''}, prefix='/SAFESEH', 643 map={'false': ':NO', 'true': ''}, prefix='/SAFESEH',
637 default=safeseh_default) 644 default=safeseh_default)
638 645
639 # If the base address is not specifically controlled, DYNAMICBASE should 646 # If the base address is not specifically controlled, DYNAMICBASE should
640 # be on by default. 647 # be on by default.
641 base_flags = filter(lambda x: 'DYNAMICBASE' in x or x == '/FIXED', 648 if not any('DYNAMICBASE' in flag or flag == '/FIXED' for flag in ldflags):
642 ldflags)
643 if not base_flags:
644 ldflags.append('/DYNAMICBASE') 649 ldflags.append('/DYNAMICBASE')
645 650
646 # If the NXCOMPAT flag has not been specified, default to on. Despite the 651 # If the NXCOMPAT flag has not been specified, default to on. Despite the
647 # documentation that says this only defaults to on when the subsystem is 652 # documentation that says this only defaults to on when the subsystem is
648 # Vista or greater (which applies to the linker), the IDE defaults it on 653 # Vista or greater (which applies to the linker), the IDE defaults it on
649 # unless it's explicitly off. 654 # unless it's explicitly off.
650 if not filter(lambda x: 'NXCOMPAT' in x, ldflags): 655 if not any('NXCOMPAT' in flag for flag in ldflags):
651 ldflags.append('/NXCOMPAT') 656 ldflags.append('/NXCOMPAT')
652 657
653 have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags) 658 have_def_file = any(flag.startswith('/DEF:') for flag in ldflags)
654 manifest_flags, intermediate_manifest, manifest_files = \ 659 manifest_flags, intermediate_manifest, manifest_files = \
655 self._GetLdManifestFlags(config, manifest_base_name, gyp_to_build_path, 660 self._GetLdManifestFlags(config, manifest_base_name, gyp_to_build_path,
656 is_executable and not have_def_file, build_dir) 661 is_executable and not have_def_file, build_dir)
657 ldflags.extend(manifest_flags) 662 ldflags.extend(manifest_flags)
658 return ldflags, intermediate_manifest, manifest_files 663 return ldflags, intermediate_manifest, manifest_files
659 664
660 def _GetLdManifestFlags(self, config, name, gyp_to_build_path, 665 def _GetLdManifestFlags(self, config, name, gyp_to_build_path,
661 allow_isolation, build_dir): 666 allow_isolation, build_dir):
662 """Returns a 3-tuple: 667 """Returns a 3-tuple:
663 - the set of flags that need to be added to the link to generate 668 - the set of flags that need to be added to the link to generate
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after
935 return vs_version 940 return vs_version
936 941
937 def _GetVsvarsSetupArgs(generator_flags, arch): 942 def _GetVsvarsSetupArgs(generator_flags, arch):
938 vs = GetVSVersion(generator_flags) 943 vs = GetVSVersion(generator_flags)
939 return vs.SetupScript() 944 return vs.SetupScript()
940 945
941 def ExpandMacros(string, expansions): 946 def ExpandMacros(string, expansions):
942 """Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv 947 """Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv
943 for the canonical way to retrieve a suitable dict.""" 948 for the canonical way to retrieve a suitable dict."""
944 if '$' in string: 949 if '$' in string:
945 for old, new in expansions.iteritems(): 950 for old, new in expansions.items():
946 assert '$(' not in new, new 951 assert '$(' not in new, new
947 string = string.replace(old, new) 952 string = string.replace(old, new)
948 return string 953 return string
949 954
950 def _ExtractImportantEnvironment(output_of_set): 955 def _ExtractImportantEnvironment(output_of_set):
951 """Extracts environment variables required for the toolchain to run from 956 """Extracts environment variables required for the toolchain to run from
952 a textual dump output by the cmd.exe 'set' command.""" 957 a textual dump output by the cmd.exe 'set' command."""
953 envvars_to_save = ( 958 envvars_to_save = (
954 'goma_.*', # TODO(scottmg): This is ugly, but needed for goma. 959 'goma_.*', # TODO(scottmg): This is ugly, but needed for goma.
955 'include', 960 'include',
(...skipping 27 matching lines...) Expand all
983 raise Exception('Environment variable "%s" ' 988 raise Exception('Environment variable "%s" '
984 'required to be set to valid path' % required) 989 'required to be set to valid path' % required)
985 return env 990 return env
986 991
987 def _FormatAsEnvironmentBlock(envvar_dict): 992 def _FormatAsEnvironmentBlock(envvar_dict):
988 """Format as an 'environment block' directly suitable for CreateProcess. 993 """Format as an 'environment block' directly suitable for CreateProcess.
989 Briefly this is a list of key=value\0, terminated by an additional \0. See 994 Briefly this is a list of key=value\0, terminated by an additional \0. See
990 CreateProcess documentation for more details.""" 995 CreateProcess documentation for more details."""
991 block = '' 996 block = ''
992 nul = '\0' 997 nul = '\0'
993 for key, value in envvar_dict.iteritems(): 998 for key, value in envvar_dict.items():
994 block += key + '=' + value + nul 999 block += key + '=' + value + nul
995 block += nul 1000 block += nul
996 return block 1001 return block
997 1002
998 def _ExtractCLPath(output_of_where): 1003 def _ExtractCLPath(output_of_where):
999 """Gets the path to cl.exe based on the output of calling the environment 1004 """Gets the path to cl.exe based on the output of calling the environment
1000 setup batch file, followed by the equivalent of `where`.""" 1005 setup batch file, followed by the equivalent of `where`."""
1001 # Take the first line, as that's the first found in the PATH. 1006 # Take the first line, as that's the first found in the PATH.
1002 for line in output_of_where.strip().splitlines(): 1007 for line in output_of_where.strip().splitlines():
1003 if line.startswith('LOC:'): 1008 if line.startswith('LOC:'):
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1038 raise Exception('"%s" failed with error %d' % (args, popen.returncode)) 1043 raise Exception('"%s" failed with error %d' % (args, popen.returncode))
1039 env = _ExtractImportantEnvironment(variables) 1044 env = _ExtractImportantEnvironment(variables)
1040 1045
1041 # Inject system includes from gyp files into INCLUDE. 1046 # Inject system includes from gyp files into INCLUDE.
1042 if system_includes: 1047 if system_includes:
1043 system_includes = system_includes | OrderedSet( 1048 system_includes = system_includes | OrderedSet(
1044 env.get('INCLUDE', '').split(';')) 1049 env.get('INCLUDE', '').split(';'))
1045 env['INCLUDE'] = ';'.join(system_includes) 1050 env['INCLUDE'] = ';'.join(system_includes)
1046 1051
1047 env_block = _FormatAsEnvironmentBlock(env) 1052 env_block = _FormatAsEnvironmentBlock(env)
1048 f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb') 1053 f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'w')
1049 f.write(env_block) 1054 f.write(env_block)
1050 f.close() 1055 f.close()
1051 1056
1052 # Find cl.exe location for this architecture. 1057 # Find cl.exe location for this architecture.
1053 args = vs.SetupScript(arch) 1058 args = vs.SetupScript(arch)
1054 args.extend(('&&', 1059 args.extend(('&&',
1055 'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i')) 1060 'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i'))
1056 popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE) 1061 popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE)
1057 output, _ = popen.communicate() 1062 output, _ = popen.communicate()
1058 cl_paths[arch] = _ExtractCLPath(output) 1063 cl_paths[arch] = _ExtractCLPath(output)
1059 return cl_paths 1064 return cl_paths
1060 1065
1061 def VerifyMissingSources(sources, build_dir, generator_flags, gyp_to_ninja): 1066 def VerifyMissingSources(sources, build_dir, generator_flags, gyp_to_ninja):
1062 """Emulate behavior of msvs_error_on_missing_sources present in the msvs 1067 """Emulate behavior of msvs_error_on_missing_sources present in the msvs
1063 generator: Check that all regular source files, i.e. not created at run time, 1068 generator: Check that all regular source files, i.e. not created at run time,
1064 exist on disk. Missing files cause needless recompilation when building via 1069 exist on disk. Missing files cause needless recompilation when building via
1065 VS, and we want this check to match for people/bots that build using ninja, 1070 VS, and we want this check to match for people/bots that build using ninja,
1066 so they're not surprised when the VS build fails.""" 1071 so they're not surprised when the VS build fails."""
1067 if int(generator_flags.get('msvs_error_on_missing_sources', 0)): 1072 if int(generator_flags.get('msvs_error_on_missing_sources', 0)):
1068 no_specials = filter(lambda x: '$' not in x, sources) 1073 no_specials = filter(lambda x: '$' not in x, sources)
1069 relative = [os.path.join(build_dir, gyp_to_ninja(s)) for s in no_specials] 1074 relative = [os.path.join(build_dir, gyp_to_ninja(s)) for s in no_specials]
1070 missing = filter(lambda x: not os.path.exists(x), relative) 1075 missing = [x for x in relative if not os.path.exists(x)]
1071 if missing: 1076 if missing:
1072 # They'll look like out\Release\..\..\stuff\things.cc, so normalize the 1077 # They'll look like out\Release\..\..\stuff\things.cc, so normalize the
1073 # path for a slightly less crazy looking output. 1078 # path for a slightly less crazy looking output.
1074 cleaned_up = [os.path.normpath(x) for x in missing] 1079 cleaned_up = [os.path.normpath(x) for x in missing]
1075 raise Exception('Missing input files:\n%s' % '\n'.join(cleaned_up)) 1080 raise Exception('Missing input files:\n%s' % '\n'.join(cleaned_up))
1076 1081
1077 # Sets some values in default_variables, which are required for many 1082 # Sets some values in default_variables, which are required for many
1078 # generators, run on Windows. 1083 # generators, run on Windows.
1079 def CalculateCommonVariables(default_variables, params): 1084 def CalculateCommonVariables(default_variables, params):
1080 generator_flags = params.get('generator_flags', {}) 1085 generator_flags = params.get('generator_flags', {})
1081 1086
1082 # Set a variable so conditions can be based on msvs_version. 1087 # Set a variable so conditions can be based on msvs_version.
1083 msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags) 1088 msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags)
1084 default_variables['MSVS_VERSION'] = msvs_version.ShortName() 1089 default_variables['MSVS_VERSION'] = msvs_version.ShortName()
1085 1090
1086 # To determine processor word size on Windows, in addition to checking 1091 # To determine processor word size on Windows, in addition to checking
1087 # PROCESSOR_ARCHITECTURE (which reflects the word size of the current 1092 # PROCESSOR_ARCHITECTURE (which reflects the word size of the current
1088 # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which 1093 # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which
1089 # contains the actual word size of the system when running thru WOW64). 1094 # contains the actual word size of the system when running thru WOW64).
1090 if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or 1095 if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or
1091 '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')): 1096 '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')):
1092 default_variables['MSVS_OS_BITS'] = 64 1097 default_variables['MSVS_OS_BITS'] = 64
1093 else: 1098 else:
1094 default_variables['MSVS_OS_BITS'] = 32 1099 default_variables['MSVS_OS_BITS'] = 32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698