"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/node-gyp/gyp/pylib/gyp/MSVSUtil.py" (8 Mar 2017, 9537 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) 2013 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 """Utility functions shared amongst the Windows generators."""
    6 
    7 import copy
    8 import os
    9 
   10 
   11 # A dictionary mapping supported target types to extensions.
   12 TARGET_TYPE_EXT = {
   13   'executable': 'exe',
   14   'loadable_module': 'dll',
   15   'shared_library': 'dll',
   16   'static_library': 'lib',
   17 }
   18 
   19 
   20 def _GetLargePdbShimCcPath():
   21   """Returns the path of the large_pdb_shim.cc file."""
   22   this_dir = os.path.abspath(os.path.dirname(__file__))
   23   src_dir = os.path.abspath(os.path.join(this_dir, '..', '..'))
   24   win_data_dir = os.path.join(src_dir, 'data', 'win')
   25   large_pdb_shim_cc = os.path.join(win_data_dir, 'large-pdb-shim.cc')
   26   return large_pdb_shim_cc
   27 
   28 
   29 def _DeepCopySomeKeys(in_dict, keys):
   30   """Performs a partial deep-copy on |in_dict|, only copying the keys in |keys|.
   31 
   32   Arguments:
   33     in_dict: The dictionary to copy.
   34     keys: The keys to be copied. If a key is in this list and doesn't exist in
   35         |in_dict| this is not an error.
   36   Returns:
   37     The partially deep-copied dictionary.
   38   """
   39   d = {}
   40   for key in keys:
   41     if key not in in_dict:
   42       continue
   43     d[key] = copy.deepcopy(in_dict[key])
   44   return d
   45 
   46 
   47 def _SuffixName(name, suffix):
   48   """Add a suffix to the end of a target.
   49 
   50   Arguments:
   51     name: name of the target (foo#target)
   52     suffix: the suffix to be added
   53   Returns:
   54     Target name with suffix added (foo_suffix#target)
   55   """
   56   parts = name.rsplit('#', 1)
   57   parts[0] = '%s_%s' % (parts[0], suffix)
   58   return '#'.join(parts)
   59 
   60 
   61 def _ShardName(name, number):
   62   """Add a shard number to the end of a target.
   63 
   64   Arguments:
   65     name: name of the target (foo#target)
   66     number: shard number
   67   Returns:
   68     Target name with shard added (foo_1#target)
   69   """
   70   return _SuffixName(name, str(number))
   71 
   72 
   73 def ShardTargets(target_list, target_dicts):
   74   """Shard some targets apart to work around the linkers limits.
   75 
   76   Arguments:
   77     target_list: List of target pairs: 'base/base.gyp:base'.
   78     target_dicts: Dict of target properties keyed on target pair.
   79   Returns:
   80     Tuple of the new sharded versions of the inputs.
   81   """
   82   # Gather the targets to shard, and how many pieces.
   83   targets_to_shard = {}
   84   for t in target_dicts:
   85     shards = int(target_dicts[t].get('msvs_shard', 0))
   86     if shards:
   87       targets_to_shard[t] = shards
   88   # Shard target_list.
   89   new_target_list = []
   90   for t in target_list:
   91     if t in targets_to_shard:
   92       for i in range(targets_to_shard[t]):
   93         new_target_list.append(_ShardName(t, i))
   94     else:
   95       new_target_list.append(t)
   96   # Shard target_dict.
   97   new_target_dicts = {}
   98   for t in target_dicts:
   99     if t in targets_to_shard:
  100       for i in range(targets_to_shard[t]):
  101         name = _ShardName(t, i)
  102         new_target_dicts[name] = copy.copy(target_dicts[t])
  103         new_target_dicts[name]['target_name'] = _ShardName(
  104              new_target_dicts[name]['target_name'], i)
  105         sources = new_target_dicts[name].get('sources', [])
  106         new_sources = []
  107         for pos in range(i, len(sources), targets_to_shard[t]):
  108           new_sources.append(sources[pos])
  109         new_target_dicts[name]['sources'] = new_sources
  110     else:
  111       new_target_dicts[t] = target_dicts[t]
  112   # Shard dependencies.
  113   for t in new_target_dicts:
  114     for deptype in ('dependencies', 'dependencies_original'):
  115       dependencies = copy.copy(new_target_dicts[t].get(deptype, []))
  116       new_dependencies = []
  117       for d in dependencies:
  118         if d in targets_to_shard:
  119           for i in range(targets_to_shard[d]):
  120             new_dependencies.append(_ShardName(d, i))
  121         else:
  122           new_dependencies.append(d)
  123       new_target_dicts[t][deptype] = new_dependencies
  124 
  125   return (new_target_list, new_target_dicts)
  126 
  127 
  128 def _GetPdbPath(target_dict, config_name, vars):
  129   """Returns the path to the PDB file that will be generated by a given
  130   configuration.
  131 
  132   The lookup proceeds as follows:
  133     - Look for an explicit path in the VCLinkerTool configuration block.
  134     - Look for an 'msvs_large_pdb_path' variable.
  135     - Use '<(PRODUCT_DIR)/<(product_name).(exe|dll).pdb' if 'product_name' is
  136       specified.
  137     - Use '<(PRODUCT_DIR)/<(target_name).(exe|dll).pdb'.
  138 
  139   Arguments:
  140     target_dict: The target dictionary to be searched.
  141     config_name: The name of the configuration of interest.
  142     vars: A dictionary of common GYP variables with generator-specific values.
  143   Returns:
  144     The path of the corresponding PDB file.
  145   """
  146   config = target_dict['configurations'][config_name]
  147   msvs = config.setdefault('msvs_settings', {})
  148 
  149   linker = msvs.get('VCLinkerTool', {})
  150 
  151   pdb_path = linker.get('ProgramDatabaseFile')
  152   if pdb_path:
  153     return pdb_path
  154 
  155   variables = target_dict.get('variables', {})
  156   pdb_path = variables.get('msvs_large_pdb_path', None)
  157   if pdb_path:
  158     return pdb_path
  159 
  160 
  161   pdb_base = target_dict.get('product_name', target_dict['target_name'])
  162   pdb_base = '%s.%s.pdb' % (pdb_base, TARGET_TYPE_EXT[target_dict['type']])
  163   pdb_path = vars['PRODUCT_DIR'] + '/' + pdb_base
  164 
  165   return pdb_path
  166 
  167 
  168 def InsertLargePdbShims(target_list, target_dicts, vars):
  169   """Insert a shim target that forces the linker to use 4KB pagesize PDBs.
  170 
  171   This is a workaround for targets with PDBs greater than 1GB in size, the
  172   limit for the 1KB pagesize PDBs created by the linker by default.
  173 
  174   Arguments:
  175     target_list: List of target pairs: 'base/base.gyp:base'.
  176     target_dicts: Dict of target properties keyed on target pair.
  177     vars: A dictionary of common GYP variables with generator-specific values.
  178   Returns:
  179     Tuple of the shimmed version of the inputs.
  180   """
  181   # Determine which targets need shimming.
  182   targets_to_shim = []
  183   for t in target_dicts:
  184     target_dict = target_dicts[t]
  185 
  186     # We only want to shim targets that have msvs_large_pdb enabled.
  187     if not int(target_dict.get('msvs_large_pdb', 0)):
  188       continue
  189     # This is intended for executable, shared_library and loadable_module
  190     # targets where every configuration is set up to produce a PDB output.
  191     # If any of these conditions is not true then the shim logic will fail
  192     # below.
  193     targets_to_shim.append(t)
  194 
  195   large_pdb_shim_cc = _GetLargePdbShimCcPath()
  196 
  197   for t in targets_to_shim:
  198     target_dict = target_dicts[t]
  199     target_name = target_dict.get('target_name')
  200 
  201     base_dict = _DeepCopySomeKeys(target_dict,
  202           ['configurations', 'default_configuration', 'toolset'])
  203 
  204     # This is the dict for copying the source file (part of the GYP tree)
  205     # to the intermediate directory of the project. This is necessary because
  206     # we can't always build a relative path to the shim source file (on Windows
  207     # GYP and the project may be on different drives), and Ninja hates absolute
  208     # paths (it ends up generating the .obj and .obj.d alongside the source
  209     # file, polluting GYPs tree).
  210     copy_suffix = 'large_pdb_copy'
  211     copy_target_name = target_name + '_' + copy_suffix
  212     full_copy_target_name = _SuffixName(t, copy_suffix)
  213     shim_cc_basename = os.path.basename(large_pdb_shim_cc)
  214     shim_cc_dir = vars['SHARED_INTERMEDIATE_DIR'] + '/' + copy_target_name
  215     shim_cc_path = shim_cc_dir + '/' + shim_cc_basename
  216     copy_dict = copy.deepcopy(base_dict)
  217     copy_dict['target_name'] = copy_target_name
  218     copy_dict['type'] = 'none'
  219     copy_dict['sources'] = [ large_pdb_shim_cc ]
  220     copy_dict['copies'] = [{
  221       'destination': shim_cc_dir,
  222       'files': [ large_pdb_shim_cc ]
  223     }]
  224 
  225     # This is the dict for the PDB generating shim target. It depends on the
  226     # copy target.
  227     shim_suffix = 'large_pdb_shim'
  228     shim_target_name = target_name + '_' + shim_suffix
  229     full_shim_target_name = _SuffixName(t, shim_suffix)
  230     shim_dict = copy.deepcopy(base_dict)
  231     shim_dict['target_name'] = shim_target_name
  232     shim_dict['type'] = 'static_library'
  233     shim_dict['sources'] = [ shim_cc_path ]
  234     shim_dict['dependencies'] = [ full_copy_target_name ]
  235 
  236     # Set up the shim to output its PDB to the same location as the final linker
  237     # target.
  238     for config_name, config in shim_dict.get('configurations').iteritems():
  239       pdb_path = _GetPdbPath(target_dict, config_name, vars)
  240 
  241       # A few keys that we don't want to propagate.
  242       for key in ['msvs_precompiled_header', 'msvs_precompiled_source', 'test']:
  243         config.pop(key, None)
  244 
  245       msvs = config.setdefault('msvs_settings', {})
  246 
  247       # Update the compiler directives in the shim target.
  248       compiler = msvs.setdefault('VCCLCompilerTool', {})
  249       compiler['DebugInformationFormat'] = '3'
  250       compiler['ProgramDataBaseFileName'] = pdb_path
  251 
  252       # Set the explicit PDB path in the appropriate configuration of the
  253       # original target.
  254       config = target_dict['configurations'][config_name]
  255       msvs = config.setdefault('msvs_settings', {})
  256       linker = msvs.setdefault('VCLinkerTool', {})
  257       linker['GenerateDebugInformation'] = 'true'
  258       linker['ProgramDatabaseFile'] = pdb_path
  259 
  260     # Add the new targets. They must go to the beginning of the list so that
  261     # the dependency generation works as expected in ninja.
  262     target_list.insert(0, full_copy_target_name)
  263     target_list.insert(0, full_shim_target_name)
  264     target_dicts[full_copy_target_name] = copy_dict
  265     target_dicts[full_shim_target_name] = shim_dict
  266 
  267     # Update the original target to depend on the shim target.
  268     target_dict.setdefault('dependencies', []).append(full_shim_target_name)
  269 
  270   return (target_list, target_dicts)