"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/node-gyp/gyp/pylib/gyp/__init__.py" (11 Apr 2017, 22178 Bytes) of package /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 #!/usr/bin/env python
    2 
    3 # Copyright (c) 2012 Google Inc. All rights reserved.
    4 # Use of this source code is governed by a BSD-style license that can be
    5 # found in the LICENSE file.
    6 
    7 import copy
    8 import gyp.input
    9 import optparse
   10 import os.path
   11 import re
   12 import shlex
   13 import sys
   14 import traceback
   15 from gyp.common import GypError
   16 
   17 # Default debug modes for GYP
   18 debug = {}
   19 
   20 # List of "official" debug modes, but you can use anything you like.
   21 DEBUG_GENERAL = 'general'
   22 DEBUG_VARIABLES = 'variables'
   23 DEBUG_INCLUDES = 'includes'
   24 
   25 
   26 def DebugOutput(mode, message, *args):
   27   if 'all' in gyp.debug or mode in gyp.debug:
   28     ctx = ('unknown', 0, 'unknown')
   29     try:
   30       f = traceback.extract_stack(limit=2)
   31       if f:
   32         ctx = f[0][:3]
   33     except:
   34       pass
   35     if args:
   36       message %= args
   37     print '%s:%s:%d:%s %s' % (mode.upper(), os.path.basename(ctx[0]),
   38                               ctx[1], ctx[2], message)
   39 
   40 def FindBuildFiles():
   41   extension = '.gyp'
   42   files = os.listdir(os.getcwd())
   43   build_files = []
   44   for file in files:
   45     if file.endswith(extension):
   46       build_files.append(file)
   47   return build_files
   48 
   49 
   50 def Load(build_files, format, default_variables={},
   51          includes=[], depth='.', params=None, check=False,
   52          circular_check=True, duplicate_basename_check=True):
   53   """
   54   Loads one or more specified build files.
   55   default_variables and includes will be copied before use.
   56   Returns the generator for the specified format and the
   57   data returned by loading the specified build files.
   58   """
   59   if params is None:
   60     params = {}
   61 
   62   if '-' in format:
   63     format, params['flavor'] = format.split('-', 1)
   64 
   65   default_variables = copy.copy(default_variables)
   66 
   67   # Default variables provided by this program and its modules should be
   68   # named WITH_CAPITAL_LETTERS to provide a distinct "best practice" namespace,
   69   # avoiding collisions with user and automatic variables.
   70   default_variables['GENERATOR'] = format
   71   default_variables['GENERATOR_FLAVOR'] = params.get('flavor', '')
   72 
   73   # Format can be a custom python file, or by default the name of a module
   74   # within gyp.generator.
   75   if format.endswith('.py'):
   76     generator_name = os.path.splitext(format)[0]
   77     path, generator_name = os.path.split(generator_name)
   78 
   79     # Make sure the path to the custom generator is in sys.path
   80     # Don't worry about removing it once we are done.  Keeping the path
   81     # to each generator that is used in sys.path is likely harmless and
   82     # arguably a good idea.
   83     path = os.path.abspath(path)
   84     if path not in sys.path:
   85       sys.path.insert(0, path)
   86   else:
   87     generator_name = 'gyp.generator.' + format
   88 
   89   # These parameters are passed in order (as opposed to by key)
   90   # because ActivePython cannot handle key parameters to __import__.
   91   generator = __import__(generator_name, globals(), locals(), generator_name)
   92   for (key, val) in generator.generator_default_variables.items():
   93     default_variables.setdefault(key, val)
   94 
   95   # Give the generator the opportunity to set additional variables based on
   96   # the params it will receive in the output phase.
   97   if getattr(generator, 'CalculateVariables', None):
   98     generator.CalculateVariables(default_variables, params)
   99 
  100   # Give the generator the opportunity to set generator_input_info based on
  101   # the params it will receive in the output phase.
  102   if getattr(generator, 'CalculateGeneratorInputInfo', None):
  103     generator.CalculateGeneratorInputInfo(params)
  104 
  105   # Fetch the generator specific info that gets fed to input, we use getattr
  106   # so we can default things and the generators only have to provide what
  107   # they need.
  108   generator_input_info = {
  109     'non_configuration_keys':
  110         getattr(generator, 'generator_additional_non_configuration_keys', []),
  111     'path_sections':
  112         getattr(generator, 'generator_additional_path_sections', []),
  113     'extra_sources_for_rules':
  114         getattr(generator, 'generator_extra_sources_for_rules', []),
  115     'generator_supports_multiple_toolsets':
  116         getattr(generator, 'generator_supports_multiple_toolsets', False),
  117     'generator_wants_static_library_dependencies_adjusted':
  118         getattr(generator,
  119                 'generator_wants_static_library_dependencies_adjusted', True),
  120     'generator_wants_sorted_dependencies':
  121         getattr(generator, 'generator_wants_sorted_dependencies', False),
  122     'generator_filelist_paths':
  123         getattr(generator, 'generator_filelist_paths', None),
  124   }
  125 
  126   # Process the input specific to this generator.
  127   result = gyp.input.Load(build_files, default_variables, includes[:],
  128                           depth, generator_input_info, check, circular_check,
  129                           duplicate_basename_check,
  130                           params['parallel'], params['root_targets'])
  131   return [generator] + result
  132 
  133 def NameValueListToDict(name_value_list):
  134   """
  135   Takes an array of strings of the form 'NAME=VALUE' and creates a dictionary
  136   of the pairs.  If a string is simply NAME, then the value in the dictionary
  137   is set to True.  If VALUE can be converted to an integer, it is.
  138   """
  139   result = { }
  140   for item in name_value_list:
  141     tokens = item.split('=', 1)
  142     if len(tokens) == 2:
  143       # If we can make it an int, use that, otherwise, use the string.
  144       try:
  145         token_value = int(tokens[1])
  146       except ValueError:
  147         token_value = tokens[1]
  148       # Set the variable to the supplied value.
  149       result[tokens[0]] = token_value
  150     else:
  151       # No value supplied, treat it as a boolean and set it.
  152       result[tokens[0]] = True
  153   return result
  154 
  155 def ShlexEnv(env_name):
  156   flags = os.environ.get(env_name, [])
  157   if flags:
  158     flags = shlex.split(flags)
  159   return flags
  160 
  161 def FormatOpt(opt, value):
  162   if opt.startswith('--'):
  163     return '%s=%s' % (opt, value)
  164   return opt + value
  165 
  166 def RegenerateAppendFlag(flag, values, predicate, env_name, options):
  167   """Regenerate a list of command line flags, for an option of action='append'.
  168 
  169   The |env_name|, if given, is checked in the environment and used to generate
  170   an initial list of options, then the options that were specified on the
  171   command line (given in |values|) are appended.  This matches the handling of
  172   environment variables and command line flags where command line flags override
  173   the environment, while not requiring the environment to be set when the flags
  174   are used again.
  175   """
  176   flags = []
  177   if options.use_environment and env_name:
  178     for flag_value in ShlexEnv(env_name):
  179       value = FormatOpt(flag, predicate(flag_value))
  180       if value in flags:
  181         flags.remove(value)
  182       flags.append(value)
  183   if values:
  184     for flag_value in values:
  185       flags.append(FormatOpt(flag, predicate(flag_value)))
  186   return flags
  187 
  188 def RegenerateFlags(options):
  189   """Given a parsed options object, and taking the environment variables into
  190   account, returns a list of flags that should regenerate an equivalent options
  191   object (even in the absence of the environment variables.)
  192 
  193   Any path options will be normalized relative to depth.
  194 
  195   The format flag is not included, as it is assumed the calling generator will
  196   set that as appropriate.
  197   """
  198   def FixPath(path):
  199     path = gyp.common.FixIfRelativePath(path, options.depth)
  200     if not path:
  201       return os.path.curdir
  202     return path
  203 
  204   def Noop(value):
  205     return value
  206 
  207   # We always want to ignore the environment when regenerating, to avoid
  208   # duplicate or changed flags in the environment at the time of regeneration.
  209   flags = ['--ignore-environment']
  210   for name, metadata in options._regeneration_metadata.iteritems():
  211     opt = metadata['opt']
  212     value = getattr(options, name)
  213     value_predicate = metadata['type'] == 'path' and FixPath or Noop
  214     action = metadata['action']
  215     env_name = metadata['env_name']
  216     if action == 'append':
  217       flags.extend(RegenerateAppendFlag(opt, value, value_predicate,
  218                                         env_name, options))
  219     elif action in ('store', None):  # None is a synonym for 'store'.
  220       if value:
  221         flags.append(FormatOpt(opt, value_predicate(value)))
  222       elif options.use_environment and env_name and os.environ.get(env_name):
  223         flags.append(FormatOpt(opt, value_predicate(os.environ.get(env_name))))
  224     elif action in ('store_true', 'store_false'):
  225       if ((action == 'store_true' and value) or
  226           (action == 'store_false' and not value)):
  227         flags.append(opt)
  228       elif options.use_environment and env_name:
  229         print >>sys.stderr, ('Warning: environment regeneration unimplemented '
  230                              'for %s flag %r env_name %r' % (action, opt,
  231                                                              env_name))
  232     else:
  233       print >>sys.stderr, ('Warning: regeneration unimplemented for action %r '
  234                            'flag %r' % (action, opt))
  235 
  236   return flags
  237 
  238 class RegeneratableOptionParser(optparse.OptionParser):
  239   def __init__(self):
  240     self.__regeneratable_options = {}
  241     optparse.OptionParser.__init__(self)
  242 
  243   def add_option(self, *args, **kw):
  244     """Add an option to the parser.
  245 
  246     This accepts the same arguments as OptionParser.add_option, plus the
  247     following:
  248       regenerate: can be set to False to prevent this option from being included
  249                   in regeneration.
  250       env_name: name of environment variable that additional values for this
  251                 option come from.
  252       type: adds type='path', to tell the regenerator that the values of
  253             this option need to be made relative to options.depth
  254     """
  255     env_name = kw.pop('env_name', None)
  256     if 'dest' in kw and kw.pop('regenerate', True):
  257       dest = kw['dest']
  258 
  259       # The path type is needed for regenerating, for optparse we can just treat
  260       # it as a string.
  261       type = kw.get('type')
  262       if type == 'path':
  263         kw['type'] = 'string'
  264 
  265       self.__regeneratable_options[dest] = {
  266           'action': kw.get('action'),
  267           'type': type,
  268           'env_name': env_name,
  269           'opt': args[0],
  270         }
  271 
  272     optparse.OptionParser.add_option(self, *args, **kw)
  273 
  274   def parse_args(self, *args):
  275     values, args = optparse.OptionParser.parse_args(self, *args)
  276     values._regeneration_metadata = self.__regeneratable_options
  277     return values, args
  278 
  279 def gyp_main(args):
  280   my_name = os.path.basename(sys.argv[0])
  281 
  282   parser = RegeneratableOptionParser()
  283   usage = 'usage: %s [options ...] [build_file ...]'
  284   parser.set_usage(usage.replace('%s', '%prog'))
  285   parser.add_option('--build', dest='configs', action='append',
  286                     help='configuration for build after project generation')
  287   parser.add_option('--check', dest='check', action='store_true',
  288                     help='check format of gyp files')
  289   parser.add_option('--config-dir', dest='config_dir', action='store',
  290                     env_name='GYP_CONFIG_DIR', default=None,
  291                     help='The location for configuration files like '
  292                     'include.gypi.')
  293   parser.add_option('-d', '--debug', dest='debug', metavar='DEBUGMODE',
  294                     action='append', default=[], help='turn on a debugging '
  295                     'mode for debugging GYP.  Supported modes are "variables", '
  296                     '"includes" and "general" or "all" for all of them.')
  297   parser.add_option('-D', dest='defines', action='append', metavar='VAR=VAL',
  298                     env_name='GYP_DEFINES',
  299                     help='sets variable VAR to value VAL')
  300   parser.add_option('--depth', dest='depth', metavar='PATH', type='path',
  301                     help='set DEPTH gyp variable to a relative path to PATH')
  302   parser.add_option('-f', '--format', dest='formats', action='append',
  303                     env_name='GYP_GENERATORS', regenerate=False,
  304                     help='output formats to generate')
  305   parser.add_option('-G', dest='generator_flags', action='append', default=[],
  306                     metavar='FLAG=VAL', env_name='GYP_GENERATOR_FLAGS',
  307                     help='sets generator flag FLAG to VAL')
  308   parser.add_option('--generator-output', dest='generator_output',
  309                     action='store', default=None, metavar='DIR', type='path',
  310                     env_name='GYP_GENERATOR_OUTPUT',
  311                     help='puts generated build files under DIR')
  312   parser.add_option('--ignore-environment', dest='use_environment',
  313                     action='store_false', default=True, regenerate=False,
  314                     help='do not read options from environment variables')
  315   parser.add_option('-I', '--include', dest='includes', action='append',
  316                     metavar='INCLUDE', type='path',
  317                     help='files to include in all loaded .gyp files')
  318   # --no-circular-check disables the check for circular relationships between
  319   # .gyp files.  These relationships should not exist, but they've only been
  320   # observed to be harmful with the Xcode generator.  Chromium's .gyp files
  321   # currently have some circular relationships on non-Mac platforms, so this
  322   # option allows the strict behavior to be used on Macs and the lenient
  323   # behavior to be used elsewhere.
  324   # TODO(mark): Remove this option when http://crbug.com/35878 is fixed.
  325   parser.add_option('--no-circular-check', dest='circular_check',
  326                     action='store_false', default=True, regenerate=False,
  327                     help="don't check for circular relationships between files")
  328   # --no-duplicate-basename-check disables the check for duplicate basenames
  329   # in a static_library/shared_library project. Visual C++ 2008 generator
  330   # doesn't support this configuration. Libtool on Mac also generates warnings
  331   # when duplicate basenames are passed into Make generator on Mac.
  332   # TODO(yukawa): Remove this option when these legacy generators are
  333   # deprecated.
  334   parser.add_option('--no-duplicate-basename-check',
  335                     dest='duplicate_basename_check', action='store_false',
  336                     default=True, regenerate=False,
  337                     help="don't check for duplicate basenames")
  338   parser.add_option('--no-parallel', action='store_true', default=False,
  339                     help='Disable multiprocessing')
  340   parser.add_option('-S', '--suffix', dest='suffix', default='',
  341                     help='suffix to add to generated files')
  342   parser.add_option('--toplevel-dir', dest='toplevel_dir', action='store',
  343                     default=None, metavar='DIR', type='path',
  344                     help='directory to use as the root of the source tree')
  345   parser.add_option('-R', '--root-target', dest='root_targets',
  346                     action='append', metavar='TARGET',
  347                     help='include only TARGET and its deep dependencies')
  348 
  349   options, build_files_arg = parser.parse_args(args)
  350   build_files = build_files_arg
  351 
  352   # Set up the configuration directory (defaults to ~/.gyp)
  353   if not options.config_dir:
  354     home = None
  355     home_dot_gyp = None
  356     if options.use_environment:
  357       home_dot_gyp = os.environ.get('GYP_CONFIG_DIR', None)
  358       if home_dot_gyp:
  359         home_dot_gyp = os.path.expanduser(home_dot_gyp)
  360 
  361     if not home_dot_gyp:
  362       home_vars = ['HOME']
  363       if sys.platform in ('cygwin', 'win32'):
  364         home_vars.append('USERPROFILE')
  365       for home_var in home_vars:
  366         home = os.getenv(home_var)
  367         if home != None:
  368           home_dot_gyp = os.path.join(home, '.gyp')
  369           if not os.path.exists(home_dot_gyp):
  370             home_dot_gyp = None
  371           else:
  372             break
  373   else:
  374     home_dot_gyp = os.path.expanduser(options.config_dir)
  375 
  376   if home_dot_gyp and not os.path.exists(home_dot_gyp):
  377     home_dot_gyp = None
  378 
  379   if not options.formats:
  380     # If no format was given on the command line, then check the env variable.
  381     generate_formats = []
  382     if options.use_environment:
  383       generate_formats = os.environ.get('GYP_GENERATORS', [])
  384     if generate_formats:
  385       generate_formats = re.split(r'[\s,]', generate_formats)
  386     if generate_formats:
  387       options.formats = generate_formats
  388     else:
  389       # Nothing in the variable, default based on platform.
  390       if sys.platform == 'darwin':
  391         options.formats = ['xcode']
  392       elif sys.platform in ('win32', 'cygwin'):
  393         options.formats = ['msvs']
  394       else:
  395         options.formats = ['make']
  396 
  397   if not options.generator_output and options.use_environment:
  398     g_o = os.environ.get('GYP_GENERATOR_OUTPUT')
  399     if g_o:
  400       options.generator_output = g_o
  401 
  402   options.parallel = not options.no_parallel
  403 
  404   for mode in options.debug:
  405     gyp.debug[mode] = 1
  406 
  407   # Do an extra check to avoid work when we're not debugging.
  408   if DEBUG_GENERAL in gyp.debug:
  409     DebugOutput(DEBUG_GENERAL, 'running with these options:')
  410     for option, value in sorted(options.__dict__.items()):
  411       if option[0] == '_':
  412         continue
  413       if isinstance(value, basestring):
  414         DebugOutput(DEBUG_GENERAL, "  %s: '%s'", option, value)
  415       else:
  416         DebugOutput(DEBUG_GENERAL, "  %s: %s", option, value)
  417 
  418   if not build_files:
  419     build_files = FindBuildFiles()
  420   if not build_files:
  421     raise GypError((usage + '\n\n%s: error: no build_file') %
  422                    (my_name, my_name))
  423 
  424   # TODO(mark): Chromium-specific hack!
  425   # For Chromium, the gyp "depth" variable should always be a relative path
  426   # to Chromium's top-level "src" directory.  If no depth variable was set
  427   # on the command line, try to find a "src" directory by looking at the
  428   # absolute path to each build file's directory.  The first "src" component
  429   # found will be treated as though it were the path used for --depth.
  430   if not options.depth:
  431     for build_file in build_files:
  432       build_file_dir = os.path.abspath(os.path.dirname(build_file))
  433       build_file_dir_components = build_file_dir.split(os.path.sep)
  434       components_len = len(build_file_dir_components)
  435       for index in xrange(components_len - 1, -1, -1):
  436         if build_file_dir_components[index] == 'src':
  437           options.depth = os.path.sep.join(build_file_dir_components)
  438           break
  439         del build_file_dir_components[index]
  440 
  441       # If the inner loop found something, break without advancing to another
  442       # build file.
  443       if options.depth:
  444         break
  445 
  446     if not options.depth:
  447       raise GypError('Could not automatically locate src directory.  This is'
  448                      'a temporary Chromium feature that will be removed.  Use'
  449                      '--depth as a workaround.')
  450 
  451   # If toplevel-dir is not set, we assume that depth is the root of our source
  452   # tree.
  453   if not options.toplevel_dir:
  454     options.toplevel_dir = options.depth
  455 
  456   # -D on the command line sets variable defaults - D isn't just for define,
  457   # it's for default.  Perhaps there should be a way to force (-F?) a
  458   # variable's value so that it can't be overridden by anything else.
  459   cmdline_default_variables = {}
  460   defines = []
  461   if options.use_environment:
  462     defines += ShlexEnv('GYP_DEFINES')
  463   if options.defines:
  464     defines += options.defines
  465   cmdline_default_variables = NameValueListToDict(defines)
  466   if DEBUG_GENERAL in gyp.debug:
  467     DebugOutput(DEBUG_GENERAL,
  468                 "cmdline_default_variables: %s", cmdline_default_variables)
  469 
  470   # Set up includes.
  471   includes = []
  472 
  473   # If ~/.gyp/include.gypi exists, it'll be forcibly included into every
  474   # .gyp file that's loaded, before anything else is included.
  475   if home_dot_gyp != None:
  476     default_include = os.path.join(home_dot_gyp, 'include.gypi')
  477     if os.path.exists(default_include):
  478       print 'Using overrides found in ' + default_include
  479       includes.append(default_include)
  480 
  481   # Command-line --include files come after the default include.
  482   if options.includes:
  483     includes.extend(options.includes)
  484 
  485   # Generator flags should be prefixed with the target generator since they
  486   # are global across all generator runs.
  487   gen_flags = []
  488   if options.use_environment:
  489     gen_flags += ShlexEnv('GYP_GENERATOR_FLAGS')
  490   if options.generator_flags:
  491     gen_flags += options.generator_flags
  492   generator_flags = NameValueListToDict(gen_flags)
  493   if DEBUG_GENERAL in gyp.debug.keys():
  494     DebugOutput(DEBUG_GENERAL, "generator_flags: %s", generator_flags)
  495 
  496   # Generate all requested formats (use a set in case we got one format request
  497   # twice)
  498   for format in set(options.formats):
  499     params = {'options': options,
  500               'build_files': build_files,
  501               'generator_flags': generator_flags,
  502               'cwd': os.getcwd(),
  503               'build_files_arg': build_files_arg,
  504               'gyp_binary': sys.argv[0],
  505               'home_dot_gyp': home_dot_gyp,
  506               'parallel': options.parallel,
  507               'root_targets': options.root_targets,
  508               'target_arch': cmdline_default_variables.get('target_arch', '')}
  509 
  510     # Start with the default variables from the command line.
  511     [generator, flat_list, targets, data] = Load(
  512         build_files, format, cmdline_default_variables, includes, options.depth,
  513         params, options.check, options.circular_check,
  514         options.duplicate_basename_check)
  515 
  516     # TODO(mark): Pass |data| for now because the generator needs a list of
  517     # build files that came in.  In the future, maybe it should just accept
  518     # a list, and not the whole data dict.
  519     # NOTE: flat_list is the flattened dependency graph specifying the order
  520     # that targets may be built.  Build systems that operate serially or that
  521     # need to have dependencies defined before dependents reference them should
  522     # generate targets in the order specified in flat_list.
  523     generator.GenerateOutput(flat_list, targets, data, params)
  524 
  525     if options.configs:
  526       valid_configs = targets[flat_list[0]]['configurations'].keys()
  527       for conf in options.configs:
  528         if conf not in valid_configs:
  529           raise GypError('Invalid config specified via --build: %s' % conf)
  530       generator.PerformBuild(data, options.configs, params)
  531 
  532   # Done
  533   return 0
  534 
  535 
  536 def main(args):
  537   try:
  538     return gyp_main(args)
  539   except GypError, e:
  540     sys.stderr.write("gyp: %s\n" % e)
  541     return 1
  542 
  543 # NOTE: setuptools generated console_scripts calls function with no arguments
  544 def script_main():
  545   return main(sys.argv[1:])
  546 
  547 if __name__ == '__main__':
  548   sys.exit(script_main())