예제 #1
0
def _TopologicallySortedEnvVarKeys(env):
    """Takes a dict |env| whose values are strings that can refer to other keys,
  for example env['foo'] = '$(bar) and $(baz)'. Returns a list L of all keys of
  env such that key2 is after key1 in L if env[key2] refers to env[key1].

  Throws an Exception in case of dependency cycles.
  """
    # Since environment variables can refer to other variables, the evaluation
    # order is important. Below is the logic to compute the dependency graph
    # and sort it.
    regex = re.compile(r'\$\{([a-zA-Z0-9\-_]+)\}')

    def GetEdges(node):
        # Use a definition of edges such that user_of_variable -> used_varible.
        # This happens to be easier in this case, since a variable's
        # definition contains all variables it references in a single string.
        # We can then reverse the result of the topological sort at the end.
        # Since: reverse(topsort(DAG)) = topsort(reverse_edges(DAG))
        matches = set([v for v in regex.findall(env[node]) if v in env])
        for dependee in matches:
            assert '${' not in dependee, 'Nested variables not supported: ' + dependee
        return matches

    try:
        # Topologically sort, and then reverse, because we used an edge definition
        # that's inverted from the expected result of this function (see comment
        # above).
        order = gyp.common.TopologicallySorted(env.keys(), GetEdges)
        order.reverse()
        return order
    except gyp.common.CycleError, e:
        raise GypError(
            'Xcode environment variables are cyclically dependent: ' +
            str(e.nodes))
예제 #2
0
 def _GetStdout(self, cmdlist):
   job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE)
   out = job.communicate()[0]
   if job.returncode != 0:
     sys.stderr.write(out + '\n')
     raise GypError('Error %d running %s' % (job.returncode, cmdlist[0]))
   return out.rstrip('\n')
예제 #3
0
 def _GetSdkVersionInfoItem(self, sdk, infoitem):
   job = subprocess.Popen(['xcodebuild', '-version', '-sdk', sdk, infoitem],
                          stdout=subprocess.PIPE)
   out = job.communicate()[0]
   if job.returncode != 0:
     sys.stderr.write(out + '\n')
     raise GypError('Error %d running xcodebuild' % job.returncode)
   return out.rstrip('\n')
예제 #4
0
파일: __init__.py 프로젝트: imdone/node
def gyp_main(args):
  my_name = os.path.basename(sys.argv[0])

  parser = RegeneratableOptionParser()
  usage = 'usage: %s [options ...] [build_file ...]'
  parser.set_usage(usage.replace('%s', '%prog'))
  parser.add_option('--build', dest='configs', action='append',
                    help='configuration for build after project generation')
  parser.add_option('--check', dest='check', action='store_true',
                    help='check format of gyp files')
  parser.add_option('--config-dir', dest='config_dir', action='store',
                    env_name='GYP_CONFIG_DIR', default=None,
                    help='The location for configuration files like '
                    'include.gypi.')
  parser.add_option('-d', '--debug', dest='debug', metavar='DEBUGMODE',
                    action='append', default=[], help='turn on a debugging '
                    'mode for debugging GYP.  Supported modes are "variables", '
                    '"includes" and "general" or "all" for all of them.')
  parser.add_option('-D', dest='defines', action='append', metavar='VAR=VAL',
                    env_name='GYP_DEFINES',
                    help='sets variable VAR to value VAL')
  parser.add_option('--depth', dest='depth', metavar='PATH', type='path',
                    help='set DEPTH gyp variable to a relative path to PATH')
  parser.add_option('-f', '--format', dest='formats', action='append',
                    env_name='GYP_GENERATORS', regenerate=False,
                    help='output formats to generate')
  parser.add_option('-G', dest='generator_flags', action='append', default=[],
                    metavar='FLAG=VAL', env_name='GYP_GENERATOR_FLAGS',
                    help='sets generator flag FLAG to VAL')
  parser.add_option('--generator-output', dest='generator_output',
                    action='store', default=None, metavar='DIR', type='path',
                    env_name='GYP_GENERATOR_OUTPUT',
                    help='puts generated build files under DIR')
  parser.add_option('--ignore-environment', dest='use_environment',
                    action='store_false', default=True, regenerate=False,
                    help='do not read options from environment variables')
  parser.add_option('-I', '--include', dest='includes', action='append',
                    metavar='INCLUDE', type='path',
                    help='files to include in all loaded .gyp files')
  # --no-circular-check disables the check for circular relationships between
  # .gyp files.  These relationships should not exist, but they've only been
  # observed to be harmful with the Xcode generator.  Chromium's .gyp files
  # currently have some circular relationships on non-Mac platforms, so this
  # option allows the strict behavior to be used on Macs and the lenient
  # behavior to be used elsewhere.
  # TODO (mark): Remove this option when http://crbug.com/35878 is fixed. id:3704
  parser.add_option('--no-circular-check', dest='circular_check',
                    action='store_false', default=True, regenerate=False,
                    help="don't check for circular relationships between files")
  # --no-duplicate-basename-check disables the check for duplicate basenames
  # in a static_library/shared_library project. Visual C++ 2008 generator
  # doesn't support this configuration. Libtool on Mac also generates warnings
  # when duplicate basenames are passed into Make generator on Mac.
  # TODO (yukawa): Remove this option when these legacy generators are id:4097
  # deprecated.
  parser.add_option('--no-duplicate-basename-check',
                    dest='duplicate_basename_check', action='store_false',
                    default=True, regenerate=False,
                    help="don't check for duplicate basenames")
  parser.add_option('--no-parallel', action='store_true', default=False,
                    help='Disable multiprocessing')
  parser.add_option('-S', '--suffix', dest='suffix', default='',
                    help='suffix to add to generated files')
  parser.add_option('--toplevel-dir', dest='toplevel_dir', action='store',
                    default=None, metavar='DIR', type='path',
                    help='directory to use as the root of the source tree')
  parser.add_option('-R', '--root-target', dest='root_targets',
                    action='append', metavar='TARGET',
                    help='include only TARGET and its deep dependencies')

  options, build_files_arg = parser.parse_args(args)
  build_files = build_files_arg

  # Set up the configuration directory (defaults to ~/.gyp)
  if not options.config_dir:
    home = None
    home_dot_gyp = None
    if options.use_environment:
      home_dot_gyp = os.environ.get('GYP_CONFIG_DIR', None)
      if home_dot_gyp:
        home_dot_gyp = os.path.expanduser(home_dot_gyp)

    if not home_dot_gyp:
      home_vars = ['HOME']
      if sys.platform in ('cygwin', 'win32'):
        home_vars.append('USERPROFILE')
      for home_var in home_vars:
        home = os.getenv(home_var)
        if home != None:
          home_dot_gyp = os.path.join(home, '.gyp')
          if not os.path.exists(home_dot_gyp):
            home_dot_gyp = None
          else:
            break
  else:
    home_dot_gyp = os.path.expanduser(options.config_dir)

  if home_dot_gyp and not os.path.exists(home_dot_gyp):
    home_dot_gyp = None

  if not options.formats:
    # If no format was given on the command line, then check the env variable.
    generate_formats = []
    if options.use_environment:
      generate_formats = os.environ.get('GYP_GENERATORS', [])
    if generate_formats:
      generate_formats = re.split(r'[\s,]', generate_formats)
    if generate_formats:
      options.formats = generate_formats
    else:
      # Nothing in the variable, default based on platform.
      if sys.platform == 'darwin':
        options.formats = ['xcode']
      elif sys.platform in ('win32', 'cygwin'):
        options.formats = ['msvs']
      else:
        options.formats = ['make']

  if not options.generator_output and options.use_environment:
    g_o = os.environ.get('GYP_GENERATOR_OUTPUT')
    if g_o:
      options.generator_output = g_o

  options.parallel = not options.no_parallel

  for mode in options.debug:
    gyp.debug[mode] = 1

  # Do an extra check to avoid work when we're not debugging.
  if DEBUG_GENERAL in gyp.debug:
    DebugOutput(DEBUG_GENERAL, 'running with these options:')
    for option, value in sorted(options.__dict__.items()):
      if option[0] == '_':
        continue
      if isinstance(value, basestring):
        DebugOutput(DEBUG_GENERAL, "  %s: '%s'", option, value)
      else:
        DebugOutput(DEBUG_GENERAL, "  %s: %s", option, value)

  if not build_files:
    build_files = FindBuildFiles()
  if not build_files:
    raise GypError((usage + '\n\n%s: error: no build_file') %
                   (my_name, my_name))

  # TODO (mark): Chromium-specific hack! id:4023
  # For Chromium, the gyp "depth" variable should always be a relative path
  # to Chromium's top-level "src" directory.  If no depth variable was set
  # on the command line, try to find a "src" directory by looking at the
  # absolute path to each build file's directory.  The first "src" component
  # found will be treated as though it were the path used for --depth.
  if not options.depth:
    for build_file in build_files:
      build_file_dir = os.path.abspath(os.path.dirname(build_file))
      build_file_dir_components = build_file_dir.split(os.path.sep)
      components_len = len(build_file_dir_components)
      for index in xrange(components_len - 1, -1, -1):
        if build_file_dir_components[index] == 'src':
          options.depth = os.path.sep.join(build_file_dir_components)
          break
        del build_file_dir_components[index]

      # If the inner loop found something, break without advancing to another
      # build file.
      if options.depth:
        break

    if not options.depth:
      raise GypError('Could not automatically locate src directory.  This is'
                     'a temporary Chromium feature that will be removed.  Use'
                     '--depth as a workaround.')

  # If toplevel-dir is not set, we assume that depth is the root of our source
  # tree.
  if not options.toplevel_dir:
    options.toplevel_dir = options.depth

  # -D on the command line sets variable defaults - D isn't just for define,
  # it's for default.  Perhaps there should be a way to force (-F?) a
  # variable's value so that it can't be overridden by anything else.
  cmdline_default_variables = {}
  defines = []
  if options.use_environment:
    defines += ShlexEnv('GYP_DEFINES')
  if options.defines:
    defines += options.defines
  cmdline_default_variables = NameValueListToDict(defines)
  if DEBUG_GENERAL in gyp.debug:
    DebugOutput(DEBUG_GENERAL,
                "cmdline_default_variables: %s", cmdline_default_variables)

  # Set up includes.
  includes = []

  # If ~/.gyp/include.gypi exists, it'll be forcibly included into every
  # .gyp file that's loaded, before anything else is included.
  if home_dot_gyp != None:
    default_include = os.path.join(home_dot_gyp, 'include.gypi')
    if os.path.exists(default_include):
      print 'Using overrides found in ' + default_include
      includes.append(default_include)

  # Command-line --include files come after the default include.
  if options.includes:
    includes.extend(options.includes)

  # Generator flags should be prefixed with the target generator since they
  # are global across all generator runs.
  gen_flags = []
  if options.use_environment:
    gen_flags += ShlexEnv('GYP_GENERATOR_FLAGS')
  if options.generator_flags:
    gen_flags += options.generator_flags
  generator_flags = NameValueListToDict(gen_flags)
  if DEBUG_GENERAL in gyp.debug.keys():
    DebugOutput(DEBUG_GENERAL, "generator_flags: %s", generator_flags)

  # Generate all requested formats (use a set in case we got one format request
  # twice)
  for format in set(options.formats):
    params = {'options': options,
              'build_files': build_files,
              'generator_flags': generator_flags,
              'cwd': os.getcwd(),
              'build_files_arg': build_files_arg,
              'gyp_binary': sys.argv[0],
              'home_dot_gyp': home_dot_gyp,
              'parallel': options.parallel,
              'root_targets': options.root_targets,
              'target_arch': cmdline_default_variables.get('target_arch', '')}

    # Start with the default variables from the command line.
    [generator, flat_list, targets, data] = Load(
        build_files, format, cmdline_default_variables, includes, options.depth,
        params, options.check, options.circular_check,
        options.duplicate_basename_check)

    # TODO (mark): Pass |data| for now because the generator needs a list of id:3235
    # build files that came in.  In the future, maybe it should just accept
    # a list, and not the whole data dict.
    # NOTE: flat_list is the flattened dependency graph specifying the order id:3406
    # that targets may be built.  Build systems that operate serially or that
    # need to have dependencies defined before dependents reference them should
    # generate targets in the order specified in flat_list.
    generator.GenerateOutput(flat_list, targets, data, params)

    if options.configs:
      valid_configs = targets[flat_list[0]]['configurations'].keys()
      for conf in options.configs:
        if conf not in valid_configs:
          raise GypError('Invalid config specified via --build: %s' % conf)
      generator.PerformBuild(data, options.configs, params)

  # Done
  return 0
def gyp_main(args):
    my_name = os.path.basename(sys.argv[0])
    usage = "usage: %(prog)s [options ...] [build_file ...]"

    parser = RegeneratableOptionParser(usage=usage.replace("%s", "%(prog)s"))
    parser.add_argument(
        "--build",
        dest="configs",
        action="append",
        help="configuration for build after project generation",
    )
    parser.add_argument("--check",
                        dest="check",
                        action="store_true",
                        help="check format of gyp files")
    parser.add_argument(
        "--config-dir",
        dest="config_dir",
        action="store",
        env_name="GYP_CONFIG_DIR",
        default=None,
        help="The location for configuration files like "
        "include.gypi.",
    )
    parser.add_argument(
        "-d",
        "--debug",
        dest="debug",
        metavar="DEBUGMODE",
        action="append",
        default=[],
        help="turn on a debugging "
        'mode for debugging GYP.  Supported modes are "variables", '
        '"includes" and "general" or "all" for all of them.',
    )
    parser.add_argument(
        "-D",
        dest="defines",
        action="append",
        metavar="VAR=VAL",
        env_name="GYP_DEFINES",
        help="sets variable VAR to value VAL",
    )
    parser.add_argument(
        "--depth",
        dest="depth",
        metavar="PATH",
        type="path",
        help="set DEPTH gyp variable to a relative path to PATH",
    )
    parser.add_argument(
        "-f",
        "--format",
        dest="formats",
        action="append",
        env_name="GYP_GENERATORS",
        regenerate=False,
        help="output formats to generate",
    )
    parser.add_argument(
        "-G",
        dest="generator_flags",
        action="append",
        default=[],
        metavar="FLAG=VAL",
        env_name="GYP_GENERATOR_FLAGS",
        help="sets generator flag FLAG to VAL",
    )
    parser.add_argument(
        "--generator-output",
        dest="generator_output",
        action="store",
        default=None,
        metavar="DIR",
        type="path",
        env_name="GYP_GENERATOR_OUTPUT",
        help="puts generated build files under DIR",
    )
    parser.add_argument(
        "--ignore-environment",
        dest="use_environment",
        action="store_false",
        default=True,
        regenerate=False,
        help="do not read options from environment variables",
    )
    parser.add_argument(
        "-I",
        "--include",
        dest="includes",
        action="append",
        metavar="INCLUDE",
        type="path",
        help="files to include in all loaded .gyp files",
    )
    # --no-circular-check disables the check for circular relationships between
    # .gyp files.  These relationships should not exist, but they've only been
    # observed to be harmful with the Xcode generator.  Chromium's .gyp files
    # currently have some circular relationships on non-Mac platforms, so this
    # option allows the strict behavior to be used on Macs and the lenient
    # behavior to be used elsewhere.
    # TODO(mark): Remove this option when http://crbug.com/35878 is fixed.
    parser.add_argument(
        "--no-circular-check",
        dest="circular_check",
        action="store_false",
        default=True,
        regenerate=False,
        help="don't check for circular relationships between files",
    )
    # --no-duplicate-basename-check disables the check for duplicate basenames
    # in a static_library/shared_library project. Visual C++ 2008 generator
    # doesn't support this configuration. Libtool on Mac also generates warnings
    # when duplicate basenames are passed into Make generator on Mac.
    # TODO(yukawa): Remove this option when these legacy generators are
    # deprecated.
    parser.add_argument(
        "--no-duplicate-basename-check",
        dest="duplicate_basename_check",
        action="store_false",
        default=True,
        regenerate=False,
        help="don't check for duplicate basenames",
    )
    parser.add_argument(
        "--no-parallel",
        action="store_true",
        default=False,
        help="Disable multiprocessing",
    )
    parser.add_argument(
        "-S",
        "--suffix",
        dest="suffix",
        default="",
        help="suffix to add to generated files",
    )
    parser.add_argument(
        "--toplevel-dir",
        dest="toplevel_dir",
        action="store",
        default=None,
        metavar="DIR",
        type="path",
        help="directory to use as the root of the source tree",
    )
    parser.add_argument(
        "-R",
        "--root-target",
        dest="root_targets",
        action="append",
        metavar="TARGET",
        help="include only TARGET and its deep dependencies",
    )

    options, build_files_arg = parser.parse_args(args)
    build_files = build_files_arg

    # Set up the configuration directory (defaults to ~/.gyp)
    if not options.config_dir:
        home = None
        home_dot_gyp = None
        if options.use_environment:
            home_dot_gyp = os.environ.get("GYP_CONFIG_DIR", None)
            if home_dot_gyp:
                home_dot_gyp = os.path.expanduser(home_dot_gyp)

        if not home_dot_gyp:
            home_vars = ["HOME"]
            if sys.platform in ("cygwin", "win32"):
                home_vars.append("USERPROFILE")
            for home_var in home_vars:
                home = os.getenv(home_var)
                if home:
                    home_dot_gyp = os.path.join(home, ".gyp")
                    if not os.path.exists(home_dot_gyp):
                        home_dot_gyp = None
                    else:
                        break
    else:
        home_dot_gyp = os.path.expanduser(options.config_dir)

    if home_dot_gyp and not os.path.exists(home_dot_gyp):
        home_dot_gyp = None

    if not options.formats:
        # If no format was given on the command line, then check the env variable.
        generate_formats = []
        if options.use_environment:
            generate_formats = os.environ.get("GYP_GENERATORS", [])
        if generate_formats:
            generate_formats = re.split(r"[\s,]", generate_formats)
        if generate_formats:
            options.formats = generate_formats
        else:
            # Nothing in the variable, default based on platform.
            if sys.platform == "darwin":
                options.formats = ["xcode"]
            elif sys.platform in ("win32", "cygwin"):
                options.formats = ["msvs"]
            else:
                options.formats = ["make"]

    if not options.generator_output and options.use_environment:
        g_o = os.environ.get("GYP_GENERATOR_OUTPUT")
        if g_o:
            options.generator_output = g_o

    options.parallel = not options.no_parallel

    for mode in options.debug:
        gyp.debug[mode] = 1

    # Do an extra check to avoid work when we're not debugging.
    if DEBUG_GENERAL in gyp.debug:
        DebugOutput(DEBUG_GENERAL, "running with these options:")
        for option, value in sorted(options.__dict__.items()):
            if option[0] == "_":
                continue
            if isinstance(value, string_types):
                DebugOutput(DEBUG_GENERAL, "  %s: '%s'", option, value)
            else:
                DebugOutput(DEBUG_GENERAL, "  %s: %s", option, value)

    if not build_files:
        build_files = FindBuildFiles()
    if not build_files:
        raise GypError(
            (usage + "\n\n%s: error: no build_file") % (my_name, my_name))

    # TODO(mark): Chromium-specific hack!
    # For Chromium, the gyp "depth" variable should always be a relative path
    # to Chromium's top-level "src" directory.  If no depth variable was set
    # on the command line, try to find a "src" directory by looking at the
    # absolute path to each build file's directory.  The first "src" component
    # found will be treated as though it were the path used for --depth.
    if not options.depth:
        for build_file in build_files:
            build_file_dir = os.path.abspath(os.path.dirname(build_file))
            build_file_dir_components = build_file_dir.split(os.path.sep)
            components_len = len(build_file_dir_components)
            for index in range(components_len - 1, -1, -1):
                if build_file_dir_components[index] == "src":
                    options.depth = os.path.sep.join(build_file_dir_components)
                    break
                del build_file_dir_components[index]

            # If the inner loop found something, break without advancing to another
            # build file.
            if options.depth:
                break

        if not options.depth:
            raise GypError(
                "Could not automatically locate src directory.  This is"
                "a temporary Chromium feature that will be removed.  Use"
                "--depth as a workaround.")

    # If toplevel-dir is not set, we assume that depth is the root of our source
    # tree.
    if not options.toplevel_dir:
        options.toplevel_dir = options.depth

    # -D on the command line sets variable defaults - D isn't just for define,
    # it's for default.  Perhaps there should be a way to force (-F?) a
    # variable's value so that it can't be overridden by anything else.
    cmdline_default_variables = {}
    defines = []
    if options.use_environment:
        defines += ShlexEnv("GYP_DEFINES")
    if options.defines:
        defines += options.defines
    cmdline_default_variables = NameValueListToDict(defines)
    if DEBUG_GENERAL in gyp.debug:
        DebugOutput(DEBUG_GENERAL, "cmdline_default_variables: %s",
                    cmdline_default_variables)

    # Set up includes.
    includes = []

    # If ~/.gyp/include.gypi exists, it'll be forcibly included into every
    # .gyp file that's loaded, before anything else is included.
    if home_dot_gyp:
        default_include = os.path.join(home_dot_gyp, "include.gypi")
        if os.path.exists(default_include):
            print("Using overrides found in " + default_include)
            includes.append(default_include)

    # Command-line --include files come after the default include.
    if options.includes:
        includes.extend(options.includes)

    # Generator flags should be prefixed with the target generator since they
    # are global across all generator runs.
    gen_flags = []
    if options.use_environment:
        gen_flags += ShlexEnv("GYP_GENERATOR_FLAGS")
    if options.generator_flags:
        gen_flags += options.generator_flags
    generator_flags = NameValueListToDict(gen_flags)
    if DEBUG_GENERAL in gyp.debug.keys():
        DebugOutput(DEBUG_GENERAL, "generator_flags: %s", generator_flags)

    # Generate all requested formats (use a set in case we got one format request
    # twice)
    for format in set(options.formats):
        params = {
            "options": options,
            "build_files": build_files,
            "generator_flags": generator_flags,
            "cwd": os.getcwd(),
            "build_files_arg": build_files_arg,
            "gyp_binary": sys.argv[0],
            "home_dot_gyp": home_dot_gyp,
            "parallel": options.parallel,
            "root_targets": options.root_targets,
            "target_arch": cmdline_default_variables.get("target_arch", ""),
        }

        # Start with the default variables from the command line.
        [generator, flat_list, targets, data] = Load(
            build_files,
            format,
            cmdline_default_variables,
            includes,
            options.depth,
            params,
            options.check,
            options.circular_check,
            options.duplicate_basename_check,
        )

        # TODO(mark): Pass |data| for now because the generator needs a list of
        # build files that came in.  In the future, maybe it should just accept
        # a list, and not the whole data dict.
        # NOTE: flat_list is the flattened dependency graph specifying the order
        # that targets may be built.  Build systems that operate serially or that
        # need to have dependencies defined before dependents reference them should
        # generate targets in the order specified in flat_list.
        generator.GenerateOutput(flat_list, targets, data, params)

        if options.configs:
            valid_configs = targets[flat_list[0]]["configurations"]
            for conf in options.configs:
                if conf not in valid_configs:
                    raise GypError("Invalid config specified via --build: %s" %
                                   conf)
            generator.PerformBuild(data, options.configs, params)

    # Done
    return 0