"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/node-gyp/gyp/pylib/gyp/msvs_emulation.py" (8 Mar 2017, 47697 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    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
    3 # found in the LICENSE file.
    4 
    5 """
    6 This module helps emulate Visual Studio 2008 behavior on top of other
    7 build systems, primarily ninja.
    8 """
    9 
   10 import os
   11 import re
   12 import subprocess
   13 import sys
   14 
   15 from gyp.common import OrderedSet
   16 import gyp.MSVSUtil
   17 import gyp.MSVSVersion
   18 
   19 
   20 windows_quoter_regex = re.compile(r'(\\*)"')
   21 
   22 
   23 def QuoteForRspFile(arg):
   24   """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
   26   Windows programs)."""
   27   # See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment
   28   # threads. This is actually the quoting rules for CommandLineToArgvW, not
   29   # for the shell, because the shell doesn't do anything in Windows. This
   30   # works more or less because most programs (including the compiler, etc.)
   31   # use that function to handle command line arguments.
   32 
   33   # For a literal quote, CommandLineToArgvW requires 2n+1 backslashes
   34   # preceding it, and results in n backslashes + the quote. So we substitute
   35   # in 2* what we match, +1 more, plus the quote.
   36   arg = windows_quoter_regex.sub(lambda mo: 2 * mo.group(1) + '\\"', arg)
   37 
   38   # %'s also need to be doubled otherwise they're interpreted as batch
   39   # positional arguments. Also make sure to escape the % so that they're
   40   # passed literally through escaping so they can be singled to just the
   41   # original %. Otherwise, trying to pass the literal representation that
   42   # looks like an environment variable to the shell (e.g. %PATH%) would fail.
   43   arg = arg.replace('%', '%%')
   44 
   45   # These commands are used in rsp files, so no escaping for the shell (via ^)
   46   # is necessary.
   47 
   48   # Finally, wrap the whole thing in quotes so that the above quote rule
   49   # applies and whitespace isn't a word break.
   50   return '"' + arg + '"'
   51 
   52 
   53 def EncodeRspFileList(args):
   54   """Process a list of arguments using QuoteCmdExeArgument."""
   55   # Note that the first argument is assumed to be the command. Don't add
   56   # quotes around it because then built-ins like 'echo', etc. won't work.
   57   # Take care to normpath only the path in the case of 'call ../x.bat' because
   58   # otherwise the whole thing is incorrectly interpreted as a path and not
   59   # normalized correctly.
   60   if not args: return ''
   61   if args[0].startswith('call '):
   62     call, program = args[0].split(' ', 1)
   63     program = call + ' ' + os.path.normpath(program)
   64   else:
   65     program = os.path.normpath(args[0])
   66   return program + ' ' + ' '.join(QuoteForRspFile(arg) for arg in args[1:])
   67 
   68 
   69 def _GenericRetrieve(root, default, path):
   70   """Given a list of dictionary keys |path| and a tree of dicts |root|, find
   71   value at path, or return |default| if any of the path doesn't exist."""
   72   if not root:
   73     return default
   74   if not path:
   75     return root
   76   return _GenericRetrieve(root.get(path[0]), default, path[1:])
   77 
   78 
   79 def _AddPrefix(element, prefix):
   80   """Add |prefix| to |element| or each subelement if element is iterable."""
   81   if element is None:
   82     return element
   83   # Note, not Iterable because we don't want to handle strings like that.
   84   if isinstance(element, list) or isinstance(element, tuple):
   85     return [prefix + e for e in element]
   86   else:
   87     return prefix + element
   88 
   89 
   90 def _DoRemapping(element, map):
   91   """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."""
   93   if map is not None and element is not None:
   94     if not callable(map):
   95       map = map.get # Assume it's a dict, otherwise a callable to do the remap.
   96     if isinstance(element, list) or isinstance(element, tuple):
   97       element = filter(None, [map(elem) for elem in element])
   98     else:
   99       element = map(element)
  100   return element
  101 
  102 
  103 def _AppendOrReturn(append, element):
  104   """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
  106   tuple."""
  107   if append is not None and element is not None:
  108     if isinstance(element, list) or isinstance(element, tuple):
  109       append.extend(element)
  110     else:
  111       append.append(element)
  112   else:
  113     return element
  114 
  115 
  116 def _FindDirectXInstallation():
  117   """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
  119   via the registry. May return None if not found in either location."""
  120   # Return previously calculated value, if there is one
  121   if hasattr(_FindDirectXInstallation, 'dxsdk_dir'):
  122     return _FindDirectXInstallation.dxsdk_dir
  123 
  124   dxsdk_dir = os.environ.get('DXSDK_DIR')
  125   if not dxsdk_dir:
  126     # Setup params to pass to and attempt to launch reg.exe.
  127     cmd = ['reg.exe', 'query', r'HKLM\Software\Microsoft\DirectX', '/s']
  128     p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  129     for line in p.communicate()[0].splitlines():
  130       if 'InstallPath' in line:
  131         dxsdk_dir = line.split('    ')[3] + "\\"
  132 
  133   # Cache return value
  134   _FindDirectXInstallation.dxsdk_dir = dxsdk_dir
  135   return dxsdk_dir
  136 
  137 
  138 def GetGlobalVSMacroEnv(vs_version):
  139   """Get a dict of variables mapping internal VS macro names to their gyp
  140   equivalents. Returns all variables that are independent of the target."""
  141   env = {}
  142   # '$(VSInstallDir)' and '$(VCInstallDir)' are available when and only when
  143   # Visual Studio is actually installed.
  144   if vs_version.Path():
  145     env['$(VSInstallDir)'] = vs_version.Path()
  146     env['$(VCInstallDir)'] = os.path.join(vs_version.Path(), 'VC') + '\\'
  147   # Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be
  148   # set. This happens when the SDK is sync'd via src-internal, rather than
  149   # by typical end-user installation of the SDK. If it's not set, we don't
  150   # want to leave the unexpanded variable in the path, so simply strip it.
  151   dxsdk_dir = _FindDirectXInstallation()
  152   env['$(DXSDK_DIR)'] = dxsdk_dir if dxsdk_dir else ''
  153   # Try to find an installation location for the Windows DDK by checking
  154   # the WDK_DIR environment variable, may be None.
  155   env['$(WDK_DIR)'] = os.environ.get('WDK_DIR', '')
  156   return env
  157 
  158 def ExtractSharedMSVSSystemIncludes(configs, generator_flags):
  159   """Finds msvs_system_include_dirs that are common to all targets, removes
  160   them from all targets, and returns an OrderedSet containing them."""
  161   all_system_includes = OrderedSet(
  162       configs[0].get('msvs_system_include_dirs', []))
  163   for config in configs[1:]:
  164     system_includes = config.get('msvs_system_include_dirs', [])
  165     all_system_includes = all_system_includes & OrderedSet(system_includes)
  166   if not all_system_includes:
  167     return None
  168   # Expand macros in all_system_includes.
  169   env = GetGlobalVSMacroEnv(GetVSVersion(generator_flags))
  170   expanded_system_includes = OrderedSet([ExpandMacros(include, env)
  171                                          for include in all_system_includes])
  172   if any(['$' in include for include in expanded_system_includes]):
  173     # Some path relies on target-specific variables, bail.
  174     return None
  175 
  176   # Remove system includes shared by all targets from the targets.
  177   for config in configs:
  178     includes = config.get('msvs_system_include_dirs', [])
  179     if includes:  # Don't insert a msvs_system_include_dirs key if not needed.
  180       # This must check the unexpanded includes list:
  181       new_includes = [i for i in includes if i not in all_system_includes]
  182       config['msvs_system_include_dirs'] = new_includes
  183   return expanded_system_includes
  184 
  185 
  186 class MsvsSettings(object):
  187   """A class that understands the gyp 'msvs_...' values (especially the
  188   msvs_settings field). They largely correpond to the VS2008 IDE DOM. This
  189   class helps map those settings to command line options."""
  190 
  191   def __init__(self, spec, generator_flags):
  192     self.spec = spec
  193     self.vs_version = GetVSVersion(generator_flags)
  194 
  195     supported_fields = [
  196         ('msvs_configuration_attributes', dict),
  197         ('msvs_settings', dict),
  198         ('msvs_system_include_dirs', list),
  199         ('msvs_disabled_warnings', list),
  200         ('msvs_precompiled_header', str),
  201         ('msvs_precompiled_source', str),
  202         ('msvs_configuration_platform', str),
  203         ('msvs_target_platform', str),
  204         ]
  205     configs = spec['configurations']
  206     for field, default in supported_fields:
  207       setattr(self, field, {})
  208       for configname, config in configs.iteritems():
  209         getattr(self, field)[configname] = config.get(field, default())
  210 
  211     self.msvs_cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.'])
  212 
  213     unsupported_fields = [
  214         'msvs_prebuild',
  215         'msvs_postbuild',
  216     ]
  217     unsupported = []
  218     for field in unsupported_fields:
  219       for config in configs.values():
  220         if field in config:
  221           unsupported += ["%s not supported (target %s)." %
  222                           (field, spec['target_name'])]
  223     if unsupported:
  224       raise Exception('\n'.join(unsupported))
  225 
  226   def GetExtension(self):
  227     """Returns the extension for the target, with no leading dot.
  228 
  229     Uses 'product_extension' if specified, otherwise uses MSVS defaults based on
  230     the target type.
  231     """
  232     ext = self.spec.get('product_extension', None)
  233     if ext:
  234       return ext
  235     return gyp.MSVSUtil.TARGET_TYPE_EXT.get(self.spec['type'], '')
  236 
  237   def GetVSMacroEnv(self, base_to_build=None, config=None):
  238     """Get a dict of variables mapping internal VS macro names to their gyp
  239     equivalents."""
  240     target_platform = 'Win32' if self.GetArch(config) == 'x86' else 'x64'
  241     target_name = self.spec.get('product_prefix', '') + \
  242         self.spec.get('product_name', self.spec['target_name'])
  243     target_dir = base_to_build + '\\' if base_to_build else ''
  244     target_ext = '.' + self.GetExtension()
  245     target_file_name = target_name + target_ext
  246 
  247     replacements = {
  248         '$(InputName)': '${root}',
  249         '$(InputPath)': '${source}',
  250         '$(IntDir)': '$!INTERMEDIATE_DIR',
  251         '$(OutDir)\\': target_dir,
  252         '$(PlatformName)': target_platform,
  253         '$(ProjectDir)\\': '',
  254         '$(ProjectName)': self.spec['target_name'],
  255         '$(TargetDir)\\': target_dir,
  256         '$(TargetExt)': target_ext,
  257         '$(TargetFileName)': target_file_name,
  258         '$(TargetName)': target_name,
  259         '$(TargetPath)': os.path.join(target_dir, target_file_name),
  260     }
  261     replacements.update(GetGlobalVSMacroEnv(self.vs_version))
  262     return replacements
  263 
  264   def ConvertVSMacros(self, s, base_to_build=None, config=None):
  265     """Convert from VS macro names to something equivalent."""
  266     env = self.GetVSMacroEnv(base_to_build, config=config)
  267     return ExpandMacros(s, env)
  268 
  269   def AdjustLibraries(self, libraries):
  270     """Strip -l from library if it's specified with that."""
  271     libs = [lib[2:] if lib.startswith('-l') else lib for lib in libraries]
  272     return [lib + '.lib' if not lib.endswith('.lib') else lib for lib in libs]
  273 
  274   def _GetAndMunge(self, field, path, default, prefix, append, map):
  275     """Retrieve a value from |field| at |path| or return |default|. If
  276     |append| is specified, and the item is found, it will be appended to that
  277     object instead of returned. If |map| is specified, results will be
  278     remapped through |map| before being returned or appended."""
  279     result = _GenericRetrieve(field, default, path)
  280     result = _DoRemapping(result, map)
  281     result = _AddPrefix(result, prefix)
  282     return _AppendOrReturn(append, result)
  283 
  284   class _GetWrapper(object):
  285     def __init__(self, parent, field, base_path, append=None):
  286       self.parent = parent
  287       self.field = field
  288       self.base_path = [base_path]
  289       self.append = append
  290     def __call__(self, name, map=None, prefix='', default=None):
  291       return self.parent._GetAndMunge(self.field, self.base_path + [name],
  292           default=default, prefix=prefix, append=self.append, map=map)
  293 
  294   def GetArch(self, config):
  295     """Get architecture based on msvs_configuration_platform and
  296     msvs_target_platform. Returns either 'x86' or 'x64'."""
  297     configuration_platform = self.msvs_configuration_platform.get(config, '')
  298     platform = self.msvs_target_platform.get(config, '')
  299     if not platform: # If no specific override, use the configuration's.
  300       platform = configuration_platform
  301     # Map from platform to architecture.
  302     return {'Win32': 'x86', 'x64': 'x64'}.get(platform, 'x86')
  303 
  304   def _TargetConfig(self, config):
  305     """Returns the target-specific configuration."""
  306     # There's two levels of architecture/platform specification in VS. The
  307     # first level is globally for the configuration (this is what we consider
  308     # "the" config at the gyp level, which will be something like 'Debug' or
  309     # 'Release_x64'), and a second target-specific configuration, which is an
  310     # override for the global one. |config| is remapped here to take into
  311     # account the local target-specific overrides to the global configuration.
  312     arch = self.GetArch(config)
  313     if arch == 'x64' and not config.endswith('_x64'):
  314       config += '_x64'
  315     if arch == 'x86' and config.endswith('_x64'):
  316       config = config.rsplit('_', 1)[0]
  317     return config
  318 
  319   def _Setting(self, path, config,
  320               default=None, prefix='', append=None, map=None):
  321     """_GetAndMunge for msvs_settings."""
  322     return self._GetAndMunge(
  323         self.msvs_settings[config], path, default, prefix, append, map)
  324 
  325   def _ConfigAttrib(self, path, config,
  326                    default=None, prefix='', append=None, map=None):
  327     """_GetAndMunge for msvs_configuration_attributes."""
  328     return self._GetAndMunge(
  329         self.msvs_configuration_attributes[config],
  330         path, default, prefix, append, map)
  331 
  332   def AdjustIncludeDirs(self, include_dirs, config):
  333     """Updates include_dirs to expand VS specific paths, and adds the system
  334     include dirs used for platform SDK and similar."""
  335     config = self._TargetConfig(config)
  336     includes = include_dirs + self.msvs_system_include_dirs[config]
  337     includes.extend(self._Setting(
  338       ('VCCLCompilerTool', 'AdditionalIncludeDirectories'), config, default=[]))
  339     return [self.ConvertVSMacros(p, config=config) for p in includes]
  340 
  341   def AdjustMidlIncludeDirs(self, midl_include_dirs, config):
  342     """Updates midl_include_dirs to expand VS specific paths, and adds the
  343     system include dirs used for platform SDK and similar."""
  344     config = self._TargetConfig(config)
  345     includes = midl_include_dirs + self.msvs_system_include_dirs[config]
  346     includes.extend(self._Setting(
  347       ('VCMIDLTool', 'AdditionalIncludeDirectories'), config, default=[]))
  348     return [self.ConvertVSMacros(p, config=config) for p in includes]
  349 
  350   def GetComputedDefines(self, config):
  351     """Returns the set of defines that are injected to the defines list based
  352     on other VS settings."""
  353     config = self._TargetConfig(config)
  354     defines = []
  355     if self._ConfigAttrib(['CharacterSet'], config) == '1':
  356       defines.extend(('_UNICODE', 'UNICODE'))
  357     if self._ConfigAttrib(['CharacterSet'], config) == '2':
  358       defines.append('_MBCS')
  359     defines.extend(self._Setting(
  360         ('VCCLCompilerTool', 'PreprocessorDefinitions'), config, default=[]))
  361     return defines
  362 
  363   def GetCompilerPdbName(self, config, expand_special):
  364     """Get the pdb file name that should be used for compiler invocations, or
  365     None if there's no explicit name specified."""
  366     config = self._TargetConfig(config)
  367     pdbname = self._Setting(
  368         ('VCCLCompilerTool', 'ProgramDataBaseFileName'), config)
  369     if pdbname:
  370       pdbname = expand_special(self.ConvertVSMacros(pdbname))
  371     return pdbname
  372 
  373   def GetMapFileName(self, config, expand_special):
  374     """Gets the explicitly overriden map file name for a target or returns None
  375     if it's not set."""
  376     config = self._TargetConfig(config)
  377     map_file = self._Setting(('VCLinkerTool', 'MapFileName'), config)
  378     if map_file:
  379       map_file = expand_special(self.ConvertVSMacros(map_file, config=config))
  380     return map_file
  381 
  382   def GetOutputName(self, config, expand_special):
  383     """Gets the explicitly overridden output name for a target or returns None
  384     if it's not overridden."""
  385     config = self._TargetConfig(config)
  386     type = self.spec['type']
  387     root = 'VCLibrarianTool' if type == 'static_library' else 'VCLinkerTool'
  388     # TODO(scottmg): Handle OutputDirectory without OutputFile.
  389     output_file = self._Setting((root, 'OutputFile'), config)
  390     if output_file:
  391       output_file = expand_special(self.ConvertVSMacros(
  392           output_file, config=config))
  393     return output_file
  394 
  395   def GetPDBName(self, config, expand_special, default):
  396     """Gets the explicitly overridden pdb name for a target or returns
  397     default if it's not overridden, or if no pdb will be generated."""
  398     config = self._TargetConfig(config)
  399     output_file = self._Setting(('VCLinkerTool', 'ProgramDatabaseFile'), config)
  400     generate_debug_info = self._Setting(
  401         ('VCLinkerTool', 'GenerateDebugInformation'), config)
  402     if generate_debug_info == 'true':
  403       if output_file:
  404         return expand_special(self.ConvertVSMacros(output_file, config=config))
  405       else:
  406         return default
  407     else:
  408       return None
  409 
  410   def GetNoImportLibrary(self, config):
  411     """If NoImportLibrary: true, ninja will not expect the output to include
  412     an import library."""
  413     config = self._TargetConfig(config)
  414     noimplib = self._Setting(('NoImportLibrary',), config)
  415     return noimplib == 'true'
  416 
  417   def GetAsmflags(self, config):
  418     """Returns the flags that need to be added to ml invocations."""
  419     config = self._TargetConfig(config)
  420     asmflags = []
  421     safeseh = self._Setting(('MASM', 'UseSafeExceptionHandlers'), config)
  422     if safeseh == 'true':
  423       asmflags.append('/safeseh')
  424     return asmflags
  425 
  426   def GetCflags(self, config):
  427     """Returns the flags that need to be added to .c and .cc compilations."""
  428     config = self._TargetConfig(config)
  429     cflags = []
  430     cflags.extend(['/wd' + w for w in self.msvs_disabled_warnings[config]])
  431     cl = self._GetWrapper(self, self.msvs_settings[config],
  432                           'VCCLCompilerTool', append=cflags)
  433     cl('Optimization',
  434        map={'0': 'd', '1': '1', '2': '2', '3': 'x'}, prefix='/O', default='2')
  435     cl('InlineFunctionExpansion', prefix='/Ob')
  436     cl('DisableSpecificWarnings', prefix='/wd')
  437     cl('StringPooling', map={'true': '/GF'})
  438     cl('EnableFiberSafeOptimizations', map={'true': '/GT'})
  439     cl('OmitFramePointers', map={'false': '-', 'true': ''}, prefix='/Oy')
  440     cl('EnableIntrinsicFunctions', map={'false': '-', 'true': ''}, prefix='/Oi')
  441     cl('FavorSizeOrSpeed', map={'1': 't', '2': 's'}, prefix='/O')
  442     cl('FloatingPointModel',
  443         map={'0': 'precise', '1': 'strict', '2': 'fast'}, prefix='/fp:',
  444         default='0')
  445     cl('CompileAsManaged', map={'false': '', 'true': '/clr'})
  446     cl('WholeProgramOptimization', map={'true': '/GL'})
  447     cl('WarningLevel', prefix='/W')
  448     cl('WarnAsError', map={'true': '/WX'})
  449     cl('CallingConvention',
  450         map={'0': 'd', '1': 'r', '2': 'z', '3': 'v'}, prefix='/G')
  451     cl('DebugInformationFormat',
  452         map={'1': '7', '3': 'i', '4': 'I'}, prefix='/Z')
  453     cl('RuntimeTypeInfo', map={'true': '/GR', 'false': '/GR-'})
  454     cl('EnableFunctionLevelLinking', map={'true': '/Gy', 'false': '/Gy-'})
  455     cl('MinimalRebuild', map={'true': '/Gm'})
  456     cl('BufferSecurityCheck', map={'true': '/GS', 'false': '/GS-'})
  457     cl('BasicRuntimeChecks', map={'1': 's', '2': 'u', '3': '1'}, prefix='/RTC')
  458     cl('RuntimeLibrary',
  459         map={'0': 'T', '1': 'Td', '2': 'D', '3': 'Dd'}, prefix='/M')
  460     cl('ExceptionHandling', map={'1': 'sc','2': 'a'}, prefix='/EH')
  461     cl('DefaultCharIsUnsigned', map={'true': '/J'})
  462     cl('TreatWChar_tAsBuiltInType',
  463         map={'false': '-', 'true': ''}, prefix='/Zc:wchar_t')
  464     cl('EnablePREfast', map={'true': '/analyze'})
  465     cl('AdditionalOptions', prefix='')
  466     cl('EnableEnhancedInstructionSet',
  467         map={'1': 'SSE', '2': 'SSE2', '3': 'AVX', '4': 'IA32', '5': 'AVX2'},
  468         prefix='/arch:')
  469     cflags.extend(['/FI' + f for f in self._Setting(
  470         ('VCCLCompilerTool', 'ForcedIncludeFiles'), config, default=[])])
  471     if self.vs_version.short_name in ('2013', '2013e', '2015'):
  472       # New flag required in 2013 to maintain previous PDB behavior.
  473       cflags.append('/FS')
  474     # ninja handles parallelism by itself, don't have the compiler do it too.
  475     cflags = filter(lambda x: not x.startswith('/MP'), cflags)
  476     return cflags
  477 
  478   def _GetPchFlags(self, config, extension):
  479     """Get the flags to be added to the cflags for precompiled header support.
  480     """
  481     config = self._TargetConfig(config)
  482     # 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
  484     # flags when the language matches.
  485     if self.msvs_precompiled_header[config]:
  486       source_ext = os.path.splitext(self.msvs_precompiled_source[config])[1]
  487       if _LanguageMatchesForPch(source_ext, extension):
  488         pch = os.path.split(self.msvs_precompiled_header[config])[1]
  489         return ['/Yu' + pch, '/FI' + pch, '/Fp${pchprefix}.' + pch + '.pch']
  490     return  []
  491 
  492   def GetCflagsC(self, config):
  493     """Returns the flags that need to be added to .c compilations."""
  494     config = self._TargetConfig(config)
  495     return self._GetPchFlags(config, '.c')
  496 
  497   def GetCflagsCC(self, config):
  498     """Returns the flags that need to be added to .cc compilations."""
  499     config = self._TargetConfig(config)
  500     return ['/TP'] + self._GetPchFlags(config, '.cc')
  501 
  502   def _GetAdditionalLibraryDirectories(self, root, config, gyp_to_build_path):
  503     """Get and normalize the list of paths in AdditionalLibraryDirectories
  504     setting."""
  505     config = self._TargetConfig(config)
  506     libpaths = self._Setting((root, 'AdditionalLibraryDirectories'),
  507                              config, default=[])
  508     libpaths = [os.path.normpath(
  509                     gyp_to_build_path(self.ConvertVSMacros(p, config=config)))
  510                 for p in libpaths]
  511     return ['/LIBPATH:"' + p + '"' for p in libpaths]
  512 
  513   def GetLibFlags(self, config, gyp_to_build_path):
  514     """Returns the flags that need to be added to lib commands."""
  515     config = self._TargetConfig(config)
  516     libflags = []
  517     lib = self._GetWrapper(self, self.msvs_settings[config],
  518                           'VCLibrarianTool', append=libflags)
  519     libflags.extend(self._GetAdditionalLibraryDirectories(
  520         'VCLibrarianTool', config, gyp_to_build_path))
  521     lib('LinkTimeCodeGeneration', map={'true': '/LTCG'})
  522     lib('TargetMachine', map={'1': 'X86', '17': 'X64', '3': 'ARM'},
  523         prefix='/MACHINE:')
  524     lib('AdditionalOptions')
  525     return libflags
  526 
  527   def GetDefFile(self, gyp_to_build_path):
  528     """Returns the .def file from sources, if any.  Otherwise returns None."""
  529     spec = self.spec
  530     if spec['type'] in ('shared_library', 'loadable_module', 'executable'):
  531       def_files = [s for s in spec.get('sources', []) if s.endswith('.def')]
  532       if len(def_files) == 1:
  533         return gyp_to_build_path(def_files[0])
  534       elif len(def_files) > 1:
  535         raise Exception("Multiple .def files")
  536     return None
  537 
  538   def _GetDefFileAsLdflags(self, ldflags, gyp_to_build_path):
  539     """.def files get implicitly converted to a ModuleDefinitionFile for the
  540     linker in the VS generator. Emulate that behaviour here."""
  541     def_file = self.GetDefFile(gyp_to_build_path)
  542     if def_file:
  543       ldflags.append('/DEF:"%s"' % def_file)
  544 
  545   def GetPGDName(self, config, expand_special):
  546     """Gets the explicitly overridden pgd name for a target or returns None
  547     if it's not overridden."""
  548     config = self._TargetConfig(config)
  549     output_file = self._Setting(
  550         ('VCLinkerTool', 'ProfileGuidedDatabase'), config)
  551     if output_file:
  552       output_file = expand_special(self.ConvertVSMacros(
  553           output_file, config=config))
  554     return output_file
  555 
  556   def GetLdflags(self, config, gyp_to_build_path, expand_special,
  557                  manifest_base_name, output_name, is_executable, build_dir):
  558     """Returns the flags that need to be added to link commands, and the
  559     manifest files."""
  560     config = self._TargetConfig(config)
  561     ldflags = []
  562     ld = self._GetWrapper(self, self.msvs_settings[config],
  563                           'VCLinkerTool', append=ldflags)
  564     self._GetDefFileAsLdflags(ldflags, gyp_to_build_path)
  565     ld('GenerateDebugInformation', map={'true': '/DEBUG'})
  566     ld('TargetMachine', map={'1': 'X86', '17': 'X64', '3': 'ARM'},
  567        prefix='/MACHINE:')
  568     ldflags.extend(self._GetAdditionalLibraryDirectories(
  569         'VCLinkerTool', config, gyp_to_build_path))
  570     ld('DelayLoadDLLs', prefix='/DELAYLOAD:')
  571     ld('TreatLinkerWarningAsErrors', prefix='/WX',
  572        map={'true': '', 'false': ':NO'})
  573     out = self.GetOutputName(config, expand_special)
  574     if out:
  575       ldflags.append('/OUT:' + out)
  576     pdb = self.GetPDBName(config, expand_special, output_name + '.pdb')
  577     if pdb:
  578       ldflags.append('/PDB:' + pdb)
  579     pgd = self.GetPGDName(config, expand_special)
  580     if pgd:
  581       ldflags.append('/PGD:' + pgd)
  582     map_file = self.GetMapFileName(config, expand_special)
  583     ld('GenerateMapFile', map={'true': '/MAP:' + map_file if map_file
  584         else '/MAP'})
  585     ld('MapExports', map={'true': '/MAPINFO:EXPORTS'})
  586     ld('AdditionalOptions', prefix='')
  587 
  588     minimum_required_version = self._Setting(
  589         ('VCLinkerTool', 'MinimumRequiredVersion'), config, default='')
  590     if minimum_required_version:
  591       minimum_required_version = ',' + minimum_required_version
  592     ld('SubSystem',
  593        map={'1': 'CONSOLE%s' % minimum_required_version,
  594             '2': 'WINDOWS%s' % minimum_required_version},
  595        prefix='/SUBSYSTEM:')
  596 
  597     stack_reserve_size = self._Setting(
  598         ('VCLinkerTool', 'StackReserveSize'), config, default='')
  599     if stack_reserve_size:
  600       stack_commit_size = self._Setting(
  601           ('VCLinkerTool', 'StackCommitSize'), config, default='')
  602       if stack_commit_size:
  603         stack_commit_size = ',' + stack_commit_size
  604       ldflags.append('/STACK:%s%s' % (stack_reserve_size, stack_commit_size))
  605 
  606     ld('TerminalServerAware', map={'1': ':NO', '2': ''}, prefix='/TSAWARE')
  607     ld('LinkIncremental', map={'1': ':NO', '2': ''}, prefix='/INCREMENTAL')
  608     ld('BaseAddress', prefix='/BASE:')
  609     ld('FixedBaseAddress', map={'1': ':NO', '2': ''}, prefix='/FIXED')
  610     ld('RandomizedBaseAddress',
  611         map={'1': ':NO', '2': ''}, prefix='/DYNAMICBASE')
  612     ld('DataExecutionPrevention',
  613         map={'1': ':NO', '2': ''}, prefix='/NXCOMPAT')
  614     ld('OptimizeReferences', map={'1': 'NOREF', '2': 'REF'}, prefix='/OPT:')
  615     ld('ForceSymbolReferences', prefix='/INCLUDE:')
  616     ld('EnableCOMDATFolding', map={'1': 'NOICF', '2': 'ICF'}, prefix='/OPT:')
  617     ld('LinkTimeCodeGeneration',
  618         map={'1': '', '2': ':PGINSTRUMENT', '3': ':PGOPTIMIZE',
  619              '4': ':PGUPDATE'},
  620         prefix='/LTCG')
  621     ld('IgnoreDefaultLibraryNames', prefix='/NODEFAULTLIB:')
  622     ld('ResourceOnlyDLL', map={'true': '/NOENTRY'})
  623     ld('EntryPointSymbol', prefix='/ENTRY:')
  624     ld('Profile', map={'true': '/PROFILE'})
  625     ld('LargeAddressAware',
  626         map={'1': ':NO', '2': ''}, prefix='/LARGEADDRESSAWARE')
  627     # TODO(scottmg): This should sort of be somewhere else (not really a flag).
  628     ld('AdditionalDependencies', prefix='')
  629 
  630     if self.GetArch(config) == 'x86':
  631       safeseh_default = 'true'
  632     else:
  633       safeseh_default = None
  634     ld('ImageHasSafeExceptionHandlers',
  635         map={'false': ':NO', 'true': ''}, prefix='/SAFESEH',
  636         default=safeseh_default)
  637 
  638     # If the base address is not specifically controlled, DYNAMICBASE should
  639     # be on by default.
  640     base_flags = filter(lambda x: 'DYNAMICBASE' in x or x == '/FIXED',
  641                         ldflags)
  642     if not base_flags:
  643       ldflags.append('/DYNAMICBASE')
  644 
  645     # If the NXCOMPAT flag has not been specified, default to on. Despite the
  646     # documentation that says this only defaults to on when the subsystem is
  647     # Vista or greater (which applies to the linker), the IDE defaults it on
  648     # unless it's explicitly off.
  649     if not filter(lambda x: 'NXCOMPAT' in x, ldflags):
  650       ldflags.append('/NXCOMPAT')
  651 
  652     have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags)
  653     manifest_flags, intermediate_manifest, manifest_files = \
  654         self._GetLdManifestFlags(config, manifest_base_name, gyp_to_build_path,
  655                                  is_executable and not have_def_file, build_dir)
  656     ldflags.extend(manifest_flags)
  657     return ldflags, intermediate_manifest, manifest_files
  658 
  659   def _GetLdManifestFlags(self, config, name, gyp_to_build_path,
  660                           allow_isolation, build_dir):
  661     """Returns a 3-tuple:
  662     - the set of flags that need to be added to the link to generate
  663       a default manifest
  664     - the intermediate manifest that the linker will generate that should be
  665       used to assert it doesn't add anything to the merged one.
  666     - the list of all the manifest files to be merged by the manifest tool and
  667       included into the link."""
  668     generate_manifest = self._Setting(('VCLinkerTool', 'GenerateManifest'),
  669                                       config,
  670                                       default='true')
  671     if generate_manifest != 'true':
  672       # This means not only that the linker should not generate the intermediate
  673       # manifest but also that the manifest tool should do nothing even when
  674       # additional manifests are specified.
  675       return ['/MANIFEST:NO'], [], []
  676 
  677     output_name = name + '.intermediate.manifest'
  678     flags = [
  679       '/MANIFEST',
  680       '/ManifestFile:' + output_name,
  681     ]
  682 
  683     # Instead of using the MANIFESTUAC flags, we generate a .manifest to
  684     # include into the list of manifests. This allows us to avoid the need to
  685     # do two passes during linking. The /MANIFEST flag and /ManifestFile are
  686     # still used, and the intermediate manifest is used to assert that the
  687     # final manifest we get from merging all the additional manifest files
  688     # (plus the one we generate here) isn't modified by merging the
  689     # intermediate into it.
  690 
  691     # Always NO, because we generate a manifest file that has what we want.
  692     flags.append('/MANIFESTUAC:NO')
  693 
  694     config = self._TargetConfig(config)
  695     enable_uac = self._Setting(('VCLinkerTool', 'EnableUAC'), config,
  696                                default='true')
  697     manifest_files = []
  698     generated_manifest_outer = \
  699 "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" \
  700 "<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>%s" \
  701 "</assembly>"
  702     if enable_uac == 'true':
  703       execution_level = self._Setting(('VCLinkerTool', 'UACExecutionLevel'),
  704                                       config, default='0')
  705       execution_level_map = {
  706         '0': 'asInvoker',
  707         '1': 'highestAvailable',
  708         '2': 'requireAdministrator'
  709       }
  710 
  711       ui_access = self._Setting(('VCLinkerTool', 'UACUIAccess'), config,
  712                                 default='false')
  713 
  714       inner = '''
  715 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
  716   <security>
  717     <requestedPrivileges>
  718       <requestedExecutionLevel level='%s' uiAccess='%s' />
  719     </requestedPrivileges>
  720   </security>
  721 </trustInfo>''' % (execution_level_map[execution_level], ui_access)
  722     else:
  723       inner = ''
  724 
  725     generated_manifest_contents = generated_manifest_outer % inner
  726     generated_name = name + '.generated.manifest'
  727     # Need to join with the build_dir here as we're writing it during
  728     # generation time, but we return the un-joined version because the build
  729     # will occur in that directory. We only write the file if the contents
  730     # have changed so that simply regenerating the project files doesn't
  731     # cause a relink.
  732     build_dir_generated_name = os.path.join(build_dir, generated_name)
  733     gyp.common.EnsureDirExists(build_dir_generated_name)
  734     f = gyp.common.WriteOnDiff(build_dir_generated_name)
  735     f.write(generated_manifest_contents)
  736     f.close()
  737     manifest_files = [generated_name]
  738 
  739     if allow_isolation:
  740       flags.append('/ALLOWISOLATION')
  741 
  742     manifest_files += self._GetAdditionalManifestFiles(config,
  743                                                        gyp_to_build_path)
  744     return flags, output_name, manifest_files
  745 
  746   def _GetAdditionalManifestFiles(self, config, gyp_to_build_path):
  747     """Gets additional manifest files that are added to the default one
  748     generated by the linker."""
  749     files = self._Setting(('VCManifestTool', 'AdditionalManifestFiles'), config,
  750                           default=[])
  751     if isinstance(files, str):
  752       files = files.split(';')
  753     return [os.path.normpath(
  754                 gyp_to_build_path(self.ConvertVSMacros(f, config=config)))
  755             for f in files]
  756 
  757   def IsUseLibraryDependencyInputs(self, config):
  758     """Returns whether the target should be linked via Use Library Dependency
  759     Inputs (using component .objs of a given .lib)."""
  760     config = self._TargetConfig(config)
  761     uldi = self._Setting(('VCLinkerTool', 'UseLibraryDependencyInputs'), config)
  762     return uldi == 'true'
  763 
  764   def IsEmbedManifest(self, config):
  765     """Returns whether manifest should be linked into binary."""
  766     config = self._TargetConfig(config)
  767     embed = self._Setting(('VCManifestTool', 'EmbedManifest'), config,
  768                           default='true')
  769     return embed == 'true'
  770 
  771   def IsLinkIncremental(self, config):
  772     """Returns whether the target should be linked incrementally."""
  773     config = self._TargetConfig(config)
  774     link_inc = self._Setting(('VCLinkerTool', 'LinkIncremental'), config)
  775     return link_inc != '1'
  776 
  777   def GetRcflags(self, config, gyp_to_ninja_path):
  778     """Returns the flags that need to be added to invocations of the resource
  779     compiler."""
  780     config = self._TargetConfig(config)
  781     rcflags = []
  782     rc = self._GetWrapper(self, self.msvs_settings[config],
  783         'VCResourceCompilerTool', append=rcflags)
  784     rc('AdditionalIncludeDirectories', map=gyp_to_ninja_path, prefix='/I')
  785     rcflags.append('/I' + gyp_to_ninja_path('.'))
  786     rc('PreprocessorDefinitions', prefix='/d')
  787     # /l arg must be in hex without leading '0x'
  788     rc('Culture', prefix='/l', map=lambda x: hex(int(x))[2:])
  789     return rcflags
  790 
  791   def BuildCygwinBashCommandLine(self, args, path_to_base):
  792     """Build a command line that runs args via cygwin bash. We assume that all
  793     incoming paths are in Windows normpath'd form, so they need to be
  794     converted to posix style for the part of the command line that's passed to
  795     bash. We also have to do some Visual Studio macro emulation here because
  796     various rules use magic VS names for things. Also note that rules that
  797     contain ninja variables cannot be fixed here (for example ${source}), so
  798     the outer generator needs to make sure that the paths that are written out
  799     are in posix style, if the command line will be used here."""
  800     cygwin_dir = os.path.normpath(
  801         os.path.join(path_to_base, self.msvs_cygwin_dirs[0]))
  802     cd = ('cd %s' % path_to_base).replace('\\', '/')
  803     args = [a.replace('\\', '/').replace('"', '\\"') for a in args]
  804     args = ["'%s'" % a.replace("'", "'\\''") for a in args]
  805     bash_cmd = ' '.join(args)
  806     cmd = (
  807         'call "%s\\setup_env.bat" && set CYGWIN=nontsec && ' % cygwin_dir +
  808         'bash -c "%s ; %s"' % (cd, bash_cmd))
  809     return cmd
  810 
  811   def IsRuleRunUnderCygwin(self, rule):
  812     """Determine if an action should be run under cygwin. If the variable is
  813     unset, or set to 1 we use cygwin."""
  814     return int(rule.get('msvs_cygwin_shell',
  815                         self.spec.get('msvs_cygwin_shell', 1))) != 0
  816 
  817   def _HasExplicitRuleForExtension(self, spec, extension):
  818     """Determine if there's an explicit rule for a particular extension."""
  819     for rule in spec.get('rules', []):
  820       if rule['extension'] == extension:
  821         return True
  822     return False
  823 
  824   def _HasExplicitIdlActions(self, spec):
  825     """Determine if an action should not run midl for .idl files."""
  826     return any([action.get('explicit_idl_action', 0)
  827                 for action in spec.get('actions', [])])
  828 
  829   def HasExplicitIdlRulesOrActions(self, spec):
  830     """Determine if there's an explicit rule or action for idl files. When
  831     there isn't we need to generate implicit rules to build MIDL .idl files."""
  832     return (self._HasExplicitRuleForExtension(spec, 'idl') or
  833             self._HasExplicitIdlActions(spec))
  834 
  835   def HasExplicitAsmRules(self, spec):
  836     """Determine if there's an explicit rule for asm files. When there isn't we
  837     need to generate implicit rules to assemble .asm files."""
  838     return self._HasExplicitRuleForExtension(spec, 'asm')
  839 
  840   def GetIdlBuildData(self, source, config):
  841     """Determine the implicit outputs for an idl file. Returns output
  842     directory, outputs, and variables and flags that are required."""
  843     config = self._TargetConfig(config)
  844     midl_get = self._GetWrapper(self, self.msvs_settings[config], 'VCMIDLTool')
  845     def midl(name, default=None):
  846       return self.ConvertVSMacros(midl_get(name, default=default),
  847                                   config=config)
  848     tlb = midl('TypeLibraryName', default='${root}.tlb')
  849     header = midl('HeaderFileName', default='${root}.h')
  850     dlldata = midl('DLLDataFileName', default='dlldata.c')
  851     iid = midl('InterfaceIdentifierFileName', default='${root}_i.c')
  852     proxy = midl('ProxyFileName', default='${root}_p.c')
  853     # Note that .tlb is not included in the outputs as it is not always
  854     # generated depending on the content of the input idl file.
  855     outdir = midl('OutputDirectory', default='')
  856     output = [header, dlldata, iid, proxy]
  857     variables = [('tlb', tlb),
  858                  ('h', header),
  859                  ('dlldata', dlldata),
  860                  ('iid', iid),
  861                  ('proxy', proxy)]
  862     # TODO(scottmg): Are there configuration settings to set these flags?
  863     target_platform = 'win32' if self.GetArch(config) == 'x86' else 'x64'
  864     flags = ['/char', 'signed', '/env', target_platform, '/Oicf']
  865     return outdir, output, variables, flags
  866 
  867 
  868 def _LanguageMatchesForPch(source_ext, pch_source_ext):
  869   c_exts = ('.c',)
  870   cc_exts = ('.cc', '.cxx', '.cpp')
  871   return ((source_ext in c_exts and pch_source_ext in c_exts) or
  872           (source_ext in cc_exts and pch_source_ext in cc_exts))
  873 
  874 
  875 class PrecompiledHeader(object):
  876   """Helper to generate dependencies and build rules to handle generation of
  877   precompiled headers. Interface matches the GCH handler in xcode_emulation.py.
  878   """
  879   def __init__(
  880       self, settings, config, gyp_to_build_path, gyp_to_unique_output, obj_ext):
  881     self.settings = settings
  882     self.config = config
  883     pch_source = self.settings.msvs_precompiled_source[self.config]
  884     self.pch_source = gyp_to_build_path(pch_source)
  885     filename, _ = os.path.splitext(pch_source)
  886     self.output_obj = gyp_to_unique_output(filename + obj_ext).lower()
  887 
  888   def _PchHeader(self):
  889     """Get the header that will appear in an #include line for all source
  890     files."""
  891     return os.path.split(self.settings.msvs_precompiled_header[self.config])[1]
  892 
  893   def GetObjDependencies(self, sources, objs, arch):
  894     """Given a list of sources files and the corresponding object files,
  895     returns a list of the pch files that should be depended upon. The
  896     additional wrapping in the return value is for interface compatibility
  897     with make.py on Mac, and xcode_emulation.py."""
  898     assert arch is None
  899     if not self._PchHeader():
  900       return []
  901     pch_ext = os.path.splitext(self.pch_source)[1]
  902     for source in sources:
  903       if _LanguageMatchesForPch(os.path.splitext(source)[1], pch_ext):
  904         return [(None, None, self.output_obj)]
  905     return []
  906 
  907   def GetPchBuildCommands(self, arch):
  908     """Not used on Windows as there are no additional build steps required
  909     (instead, existing steps are modified in GetFlagsModifications below)."""
  910     return []
  911 
  912   def GetFlagsModifications(self, input, output, implicit, command,
  913                             cflags_c, cflags_cc, expand_special):
  914     """Get the modified cflags and implicit dependencies that should be used
  915     for the pch compilation step."""
  916     if input == self.pch_source:
  917       pch_output = ['/Yc' + self._PchHeader()]
  918       if command == 'cxx':
  919         return ([('cflags_cc', map(expand_special, cflags_cc + pch_output))],
  920                 self.output_obj, [])
  921       elif command == 'cc':
  922         return ([('cflags_c', map(expand_special, cflags_c + pch_output))],
  923                 self.output_obj, [])
  924     return [], output, implicit
  925 
  926 
  927 vs_version = None
  928 def GetVSVersion(generator_flags):
  929   global vs_version
  930   if not vs_version:
  931     vs_version = gyp.MSVSVersion.SelectVisualStudioVersion(
  932         generator_flags.get('msvs_version', 'auto'),
  933         allow_fallback=False)
  934   return vs_version
  935 
  936 def _GetVsvarsSetupArgs(generator_flags, arch):
  937   vs = GetVSVersion(generator_flags)
  938   return vs.SetupScript()
  939 
  940 def ExpandMacros(string, expansions):
  941   """Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv
  942   for the canonical way to retrieve a suitable dict."""
  943   if '$' in string:
  944     for old, new in expansions.iteritems():
  945       assert '$(' not in new, new
  946       string = string.replace(old, new)
  947   return string
  948 
  949 def _ExtractImportantEnvironment(output_of_set):
  950   """Extracts environment variables required for the toolchain to run from
  951   a textual dump output by the cmd.exe 'set' command."""
  952   envvars_to_save = (
  953       'goma_.*', # TODO(scottmg): This is ugly, but needed for goma.
  954       'include',
  955       'lib',
  956       'libpath',
  957       'path',
  958       'pathext',
  959       'systemroot',
  960       'temp',
  961       'tmp',
  962       )
  963   env = {}
  964   for line in output_of_set.splitlines():
  965     for envvar in envvars_to_save:
  966       if re.match(envvar + '=', line.lower()):
  967         var, setting = line.split('=', 1)
  968         if envvar == 'path':
  969           # Our own rules (for running gyp-win-tool) and other actions in
  970           # Chromium rely on python being in the path. Add the path to this
  971           # python here so that if it's not in the path when ninja is run
  972           # later, python will still be found.
  973           setting = os.path.dirname(sys.executable) + os.pathsep + setting
  974         env[var.upper()] = setting
  975         break
  976   for required in ('SYSTEMROOT', 'TEMP', 'TMP'):
  977     if required not in env:
  978       raise Exception('Environment variable "%s" '
  979                       'required to be set to valid path' % required)
  980   return env
  981 
  982 def _FormatAsEnvironmentBlock(envvar_dict):
  983   """Format as an 'environment block' directly suitable for CreateProcess.
  984   Briefly this is a list of key=value\0, terminated by an additional \0. See
  985   CreateProcess documentation for more details."""
  986   block = ''
  987   nul = '\0'
  988   for key, value in envvar_dict.iteritems():
  989     block += key + '=' + value + nul
  990   block += nul
  991   return block
  992 
  993 def _ExtractCLPath(output_of_where):
  994   """Gets the path to cl.exe based on the output of calling the environment
  995   setup batch file, followed by the equivalent of `where`."""
  996   # Take the first line, as that's the first found in the PATH.
  997   for line in output_of_where.strip().splitlines():
  998     if line.startswith('LOC:'):
  999       return line[len('LOC:'):].strip()
 1000 
 1001 def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags,
 1002                              system_includes, open_out):
 1003   """It's not sufficient to have the absolute path to the compiler, linker,
 1004   etc. on Windows, as those tools rely on .dlls being in the PATH. We also
 1005   need to support both x86 and x64 compilers within the same build (to support
 1006   msvs_target_platform hackery). Different architectures require a different
 1007   compiler binary, and different supporting environment variables (INCLUDE,
 1008   LIB, LIBPATH). So, we extract the environment here, wrap all invocations
 1009   of compiler tools (cl, link, lib, rc, midl, etc.) via win_tool.py which
 1010   sets up the environment, and then we do not prefix the compiler with
 1011   an absolute path, instead preferring something like "cl.exe" in the rule
 1012   which will then run whichever the environment setup has put in the path.
 1013   When the following procedure to generate environment files does not
 1014   meet your requirement (e.g. for custom toolchains), you can pass
 1015   "-G ninja_use_custom_environment_files" to the gyp to suppress file
 1016   generation and use custom environment files prepared by yourself."""
 1017   archs = ('x86', 'x64')
 1018   if generator_flags.get('ninja_use_custom_environment_files', 0):
 1019     cl_paths = {}
 1020     for arch in archs:
 1021       cl_paths[arch] = 'cl.exe'
 1022     return cl_paths
 1023   vs = GetVSVersion(generator_flags)
 1024   cl_paths = {}
 1025   for arch in archs:
 1026     # Extract environment variables for subprocesses.
 1027     args = vs.SetupScript(arch)
 1028     args.extend(('&&', 'set'))
 1029     popen = subprocess.Popen(
 1030         args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
 1031     variables, _ = popen.communicate()
 1032     env = _ExtractImportantEnvironment(variables)
 1033 
 1034     # Inject system includes from gyp files into INCLUDE.
 1035     if system_includes:
 1036       system_includes = system_includes | OrderedSet(
 1037                                               env.get('INCLUDE', '').split(';'))
 1038       env['INCLUDE'] = ';'.join(system_includes)
 1039 
 1040     env_block = _FormatAsEnvironmentBlock(env)
 1041     f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb')
 1042     f.write(env_block)
 1043     f.close()
 1044 
 1045     # Find cl.exe location for this architecture.
 1046     args = vs.SetupScript(arch)
 1047     args.extend(('&&',
 1048       'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i'))
 1049     popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE)
 1050     output, _ = popen.communicate()
 1051     cl_paths[arch] = _ExtractCLPath(output)
 1052   return cl_paths
 1053 
 1054 def VerifyMissingSources(sources, build_dir, generator_flags, gyp_to_ninja):
 1055   """Emulate behavior of msvs_error_on_missing_sources present in the msvs
 1056   generator: Check that all regular source files, i.e. not created at run time,
 1057   exist on disk. Missing files cause needless recompilation when building via
 1058   VS, and we want this check to match for people/bots that build using ninja,
 1059   so they're not surprised when the VS build fails."""
 1060   if int(generator_flags.get('msvs_error_on_missing_sources', 0)):
 1061     no_specials = filter(lambda x: '$' not in x, sources)
 1062     relative = [os.path.join(build_dir, gyp_to_ninja(s)) for s in no_specials]
 1063     missing = filter(lambda x: not os.path.exists(x), relative)
 1064     if missing:
 1065       # They'll look like out\Release\..\..\stuff\things.cc, so normalize the
 1066       # path for a slightly less crazy looking output.
 1067       cleaned_up = [os.path.normpath(x) for x in missing]
 1068       raise Exception('Missing input files:\n%s' % '\n'.join(cleaned_up))
 1069 
 1070 # Sets some values in default_variables, which are required for many
 1071 # generators, run on Windows.
 1072 def CalculateCommonVariables(default_variables, params):
 1073   generator_flags = params.get('generator_flags', {})
 1074 
 1075   # Set a variable so conditions can be based on msvs_version.
 1076   msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags)
 1077   default_variables['MSVS_VERSION'] = msvs_version.ShortName()
 1078 
 1079   # To determine processor word size on Windows, in addition to checking
 1080   # PROCESSOR_ARCHITECTURE (which reflects the word size of the current
 1081   # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which
 1082   # contains the actual word size of the system when running thru WOW64).
 1083   if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or
 1084       '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')):
 1085     default_variables['MSVS_OS_BITS'] = 64
 1086   else:
 1087     default_variables['MSVS_OS_BITS'] = 32