11cb0ef41Sopenharmony_ci# Copyright (c) 2014 Google Inc. All rights reserved.
21cb0ef41Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci# found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci"""
61cb0ef41Sopenharmony_ciThis script is intended for use as a GYP_GENERATOR. It takes as input (by way of
71cb0ef41Sopenharmony_cithe generator flag config_path) the path of a json file that dictates the files
81cb0ef41Sopenharmony_ciand targets to search for. The following keys are supported:
91cb0ef41Sopenharmony_cifiles: list of paths (relative) of the files to search for.
101cb0ef41Sopenharmony_citest_targets: unqualified target names to search for. Any target in this list
111cb0ef41Sopenharmony_cithat depends upon a file in |files| is output regardless of the type of target
121cb0ef41Sopenharmony_cior chain of dependencies.
131cb0ef41Sopenharmony_ciadditional_compile_targets: Unqualified targets to search for in addition to
141cb0ef41Sopenharmony_citest_targets. Targets in the combined list that depend upon a file in |files|
151cb0ef41Sopenharmony_ciare not necessarily output. For example, if the target is of type none then the
161cb0ef41Sopenharmony_citarget is not output (but one of the descendants of the target will be).
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ciThe following is output:
191cb0ef41Sopenharmony_cierror: only supplied if there is an error.
201cb0ef41Sopenharmony_cicompile_targets: minimal set of targets that directly or indirectly (for
211cb0ef41Sopenharmony_ci  targets of type none) depend on the files in |files| and is one of the
221cb0ef41Sopenharmony_ci  supplied targets or a target that one of the supplied targets depends on.
231cb0ef41Sopenharmony_ci  The expectation is this set of targets is passed into a build step. This list
241cb0ef41Sopenharmony_ci  always contains the output of test_targets as well.
251cb0ef41Sopenharmony_citest_targets: set of targets from the supplied |test_targets| that either
261cb0ef41Sopenharmony_ci  directly or indirectly depend upon a file in |files|. This list if useful
271cb0ef41Sopenharmony_ci  if additional processing needs to be done for certain targets after the
281cb0ef41Sopenharmony_ci  build, such as running tests.
291cb0ef41Sopenharmony_cistatus: outputs one of three values: none of the supplied files were found,
301cb0ef41Sopenharmony_ci  one of the include files changed so that it should be assumed everything
311cb0ef41Sopenharmony_ci  changed (in this case test_targets and compile_targets are not output) or at
321cb0ef41Sopenharmony_ci  least one file was found.
331cb0ef41Sopenharmony_ciinvalid_targets: list of supplied targets that were not found.
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ciExample:
361cb0ef41Sopenharmony_ciConsider a graph like the following:
371cb0ef41Sopenharmony_ci  A     D
381cb0ef41Sopenharmony_ci / \
391cb0ef41Sopenharmony_ciB   C
401cb0ef41Sopenharmony_ciA depends upon both B and C, A is of type none and B and C are executables.
411cb0ef41Sopenharmony_ciD is an executable, has no dependencies and nothing depends on it.
421cb0ef41Sopenharmony_ciIf |additional_compile_targets| = ["A"], |test_targets| = ["B", "C"] and
431cb0ef41Sopenharmony_cifiles = ["b.cc", "d.cc"] (B depends upon b.cc and D depends upon d.cc), then
441cb0ef41Sopenharmony_cithe following is output:
451cb0ef41Sopenharmony_ci|compile_targets| = ["B"] B must built as it depends upon the changed file b.cc
461cb0ef41Sopenharmony_ciand the supplied target A depends upon it. A is not output as a build_target
471cb0ef41Sopenharmony_cias it is of type none with no rules and actions.
481cb0ef41Sopenharmony_ci|test_targets| = ["B"] B directly depends upon the change file b.cc.
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ciEven though the file d.cc, which D depends upon, has changed D is not output
511cb0ef41Sopenharmony_cias it was not supplied by way of |additional_compile_targets| or |test_targets|.
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ciIf the generator flag analyzer_output_path is specified, output is written
541cb0ef41Sopenharmony_cithere. Otherwise output is written to stdout.
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ciIn Gyp the "all" target is shorthand for the root targets in the files passed
571cb0ef41Sopenharmony_cito gyp. For example, if file "a.gyp" contains targets "a1" and
581cb0ef41Sopenharmony_ci"a2", and file "b.gyp" contains targets "b1" and "b2" and "a2" has a dependency
591cb0ef41Sopenharmony_cion "b2" and gyp is supplied "a.gyp" then "all" consists of "a1" and "a2".
601cb0ef41Sopenharmony_ciNotice that "b1" and "b2" are not in the "all" target as "b.gyp" was not
611cb0ef41Sopenharmony_cidirectly supplied to gyp. OTOH if both "a.gyp" and "b.gyp" are supplied to gyp
621cb0ef41Sopenharmony_cithen the "all" target includes "b1" and "b2".
631cb0ef41Sopenharmony_ci"""
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ciimport gyp.common
671cb0ef41Sopenharmony_ciimport json
681cb0ef41Sopenharmony_ciimport os
691cb0ef41Sopenharmony_ciimport posixpath
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_cidebug = False
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_cifound_dependency_string = "Found dependency"
741cb0ef41Sopenharmony_cino_dependency_string = "No dependencies"
751cb0ef41Sopenharmony_ci# Status when it should be assumed that everything has changed.
761cb0ef41Sopenharmony_ciall_changed_string = "Found dependency (all)"
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci# MatchStatus is used indicate if and how a target depends upon the supplied
791cb0ef41Sopenharmony_ci# sources.
801cb0ef41Sopenharmony_ci# The target's sources contain one of the supplied paths.
811cb0ef41Sopenharmony_ciMATCH_STATUS_MATCHES = 1
821cb0ef41Sopenharmony_ci# The target has a dependency on another target that contains one of the
831cb0ef41Sopenharmony_ci# supplied paths.
841cb0ef41Sopenharmony_ciMATCH_STATUS_MATCHES_BY_DEPENDENCY = 2
851cb0ef41Sopenharmony_ci# The target's sources weren't in the supplied paths and none of the target's
861cb0ef41Sopenharmony_ci# dependencies depend upon a target that matched.
871cb0ef41Sopenharmony_ciMATCH_STATUS_DOESNT_MATCH = 3
881cb0ef41Sopenharmony_ci# The target doesn't contain the source, but the dependent targets have not yet
891cb0ef41Sopenharmony_ci# been visited to determine a more specific status yet.
901cb0ef41Sopenharmony_ciMATCH_STATUS_TBD = 4
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_cigenerator_supports_multiple_toolsets = gyp.common.CrossCompileRequested()
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_cigenerator_wants_static_library_dependencies_adjusted = False
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_cigenerator_default_variables = {}
971cb0ef41Sopenharmony_cifor dirname in [
981cb0ef41Sopenharmony_ci    "INTERMEDIATE_DIR",
991cb0ef41Sopenharmony_ci    "SHARED_INTERMEDIATE_DIR",
1001cb0ef41Sopenharmony_ci    "PRODUCT_DIR",
1011cb0ef41Sopenharmony_ci    "LIB_DIR",
1021cb0ef41Sopenharmony_ci    "SHARED_LIB_DIR",
1031cb0ef41Sopenharmony_ci]:
1041cb0ef41Sopenharmony_ci    generator_default_variables[dirname] = "!!!"
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_cifor unused in [
1071cb0ef41Sopenharmony_ci    "RULE_INPUT_PATH",
1081cb0ef41Sopenharmony_ci    "RULE_INPUT_ROOT",
1091cb0ef41Sopenharmony_ci    "RULE_INPUT_NAME",
1101cb0ef41Sopenharmony_ci    "RULE_INPUT_DIRNAME",
1111cb0ef41Sopenharmony_ci    "RULE_INPUT_EXT",
1121cb0ef41Sopenharmony_ci    "EXECUTABLE_PREFIX",
1131cb0ef41Sopenharmony_ci    "EXECUTABLE_SUFFIX",
1141cb0ef41Sopenharmony_ci    "STATIC_LIB_PREFIX",
1151cb0ef41Sopenharmony_ci    "STATIC_LIB_SUFFIX",
1161cb0ef41Sopenharmony_ci    "SHARED_LIB_PREFIX",
1171cb0ef41Sopenharmony_ci    "SHARED_LIB_SUFFIX",
1181cb0ef41Sopenharmony_ci    "CONFIGURATION_NAME",
1191cb0ef41Sopenharmony_ci]:
1201cb0ef41Sopenharmony_ci    generator_default_variables[unused] = ""
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_cidef _ToGypPath(path):
1241cb0ef41Sopenharmony_ci    """Converts a path to the format used by gyp."""
1251cb0ef41Sopenharmony_ci    if os.sep == "\\" and os.altsep == "/":
1261cb0ef41Sopenharmony_ci        return path.replace("\\", "/")
1271cb0ef41Sopenharmony_ci    return path
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_cidef _ResolveParent(path, base_path_components):
1311cb0ef41Sopenharmony_ci    """Resolves |path|, which starts with at least one '../'. Returns an empty
1321cb0ef41Sopenharmony_ci  string if the path shouldn't be considered. See _AddSources() for a
1331cb0ef41Sopenharmony_ci  description of |base_path_components|."""
1341cb0ef41Sopenharmony_ci    depth = 0
1351cb0ef41Sopenharmony_ci    while path.startswith("../"):
1361cb0ef41Sopenharmony_ci        depth += 1
1371cb0ef41Sopenharmony_ci        path = path[3:]
1381cb0ef41Sopenharmony_ci    # Relative includes may go outside the source tree. For example, an action may
1391cb0ef41Sopenharmony_ci    # have inputs in /usr/include, which are not in the source tree.
1401cb0ef41Sopenharmony_ci    if depth > len(base_path_components):
1411cb0ef41Sopenharmony_ci        return ""
1421cb0ef41Sopenharmony_ci    if depth == len(base_path_components):
1431cb0ef41Sopenharmony_ci        return path
1441cb0ef41Sopenharmony_ci    return (
1451cb0ef41Sopenharmony_ci        "/".join(base_path_components[0 : len(base_path_components) - depth])
1461cb0ef41Sopenharmony_ci        + "/"
1471cb0ef41Sopenharmony_ci        + path
1481cb0ef41Sopenharmony_ci    )
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_cidef _AddSources(sources, base_path, base_path_components, result):
1521cb0ef41Sopenharmony_ci    """Extracts valid sources from |sources| and adds them to |result|. Each
1531cb0ef41Sopenharmony_ci  source file is relative to |base_path|, but may contain '..'. To make
1541cb0ef41Sopenharmony_ci  resolving '..' easier |base_path_components| contains each of the
1551cb0ef41Sopenharmony_ci  directories in |base_path|. Additionally each source may contain variables.
1561cb0ef41Sopenharmony_ci  Such sources are ignored as it is assumed dependencies on them are expressed
1571cb0ef41Sopenharmony_ci  and tracked in some other means."""
1581cb0ef41Sopenharmony_ci    # NOTE: gyp paths are always posix style.
1591cb0ef41Sopenharmony_ci    for source in sources:
1601cb0ef41Sopenharmony_ci        if not len(source) or source.startswith("!!!") or source.startswith("$"):
1611cb0ef41Sopenharmony_ci            continue
1621cb0ef41Sopenharmony_ci        # variable expansion may lead to //.
1631cb0ef41Sopenharmony_ci        org_source = source
1641cb0ef41Sopenharmony_ci        source = source[0] + source[1:].replace("//", "/")
1651cb0ef41Sopenharmony_ci        if source.startswith("../"):
1661cb0ef41Sopenharmony_ci            source = _ResolveParent(source, base_path_components)
1671cb0ef41Sopenharmony_ci            if len(source):
1681cb0ef41Sopenharmony_ci                result.append(source)
1691cb0ef41Sopenharmony_ci            continue
1701cb0ef41Sopenharmony_ci        result.append(base_path + source)
1711cb0ef41Sopenharmony_ci        if debug:
1721cb0ef41Sopenharmony_ci            print("AddSource", org_source, result[len(result) - 1])
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_cidef _ExtractSourcesFromAction(action, base_path, base_path_components, results):
1761cb0ef41Sopenharmony_ci    if "inputs" in action:
1771cb0ef41Sopenharmony_ci        _AddSources(action["inputs"], base_path, base_path_components, results)
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_cidef _ToLocalPath(toplevel_dir, path):
1811cb0ef41Sopenharmony_ci    """Converts |path| to a path relative to |toplevel_dir|."""
1821cb0ef41Sopenharmony_ci    if path == toplevel_dir:
1831cb0ef41Sopenharmony_ci        return ""
1841cb0ef41Sopenharmony_ci    if path.startswith(toplevel_dir + "/"):
1851cb0ef41Sopenharmony_ci        return path[len(toplevel_dir) + len("/") :]
1861cb0ef41Sopenharmony_ci    return path
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_cidef _ExtractSources(target, target_dict, toplevel_dir):
1901cb0ef41Sopenharmony_ci    # |target| is either absolute or relative and in the format of the OS. Gyp
1911cb0ef41Sopenharmony_ci    # source paths are always posix. Convert |target| to a posix path relative to
1921cb0ef41Sopenharmony_ci    # |toplevel_dir_|. This is done to make it easy to build source paths.
1931cb0ef41Sopenharmony_ci    base_path = posixpath.dirname(_ToLocalPath(toplevel_dir, _ToGypPath(target)))
1941cb0ef41Sopenharmony_ci    base_path_components = base_path.split("/")
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_ci    # Add a trailing '/' so that _AddSources() can easily build paths.
1971cb0ef41Sopenharmony_ci    if len(base_path):
1981cb0ef41Sopenharmony_ci        base_path += "/"
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci    if debug:
2011cb0ef41Sopenharmony_ci        print("ExtractSources", target, base_path)
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci    results = []
2041cb0ef41Sopenharmony_ci    if "sources" in target_dict:
2051cb0ef41Sopenharmony_ci        _AddSources(target_dict["sources"], base_path, base_path_components, results)
2061cb0ef41Sopenharmony_ci    # Include the inputs from any actions. Any changes to these affect the
2071cb0ef41Sopenharmony_ci    # resulting output.
2081cb0ef41Sopenharmony_ci    if "actions" in target_dict:
2091cb0ef41Sopenharmony_ci        for action in target_dict["actions"]:
2101cb0ef41Sopenharmony_ci            _ExtractSourcesFromAction(action, base_path, base_path_components, results)
2111cb0ef41Sopenharmony_ci    if "rules" in target_dict:
2121cb0ef41Sopenharmony_ci        for rule in target_dict["rules"]:
2131cb0ef41Sopenharmony_ci            _ExtractSourcesFromAction(rule, base_path, base_path_components, results)
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ci    return results
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ciclass Target:
2191cb0ef41Sopenharmony_ci    """Holds information about a particular target:
2201cb0ef41Sopenharmony_ci  deps: set of Targets this Target depends upon. This is not recursive, only the
2211cb0ef41Sopenharmony_ci    direct dependent Targets.
2221cb0ef41Sopenharmony_ci  match_status: one of the MatchStatus values.
2231cb0ef41Sopenharmony_ci  back_deps: set of Targets that have a dependency on this Target.
2241cb0ef41Sopenharmony_ci  visited: used during iteration to indicate whether we've visited this target.
2251cb0ef41Sopenharmony_ci    This is used for two iterations, once in building the set of Targets and
2261cb0ef41Sopenharmony_ci    again in _GetBuildTargets().
2271cb0ef41Sopenharmony_ci  name: fully qualified name of the target.
2281cb0ef41Sopenharmony_ci  requires_build: True if the target type is such that it needs to be built.
2291cb0ef41Sopenharmony_ci    See _DoesTargetTypeRequireBuild for details.
2301cb0ef41Sopenharmony_ci  added_to_compile_targets: used when determining if the target was added to the
2311cb0ef41Sopenharmony_ci    set of targets that needs to be built.
2321cb0ef41Sopenharmony_ci  in_roots: true if this target is a descendant of one of the root nodes.
2331cb0ef41Sopenharmony_ci  is_executable: true if the type of target is executable.
2341cb0ef41Sopenharmony_ci  is_static_library: true if the type of target is static_library.
2351cb0ef41Sopenharmony_ci  is_or_has_linked_ancestor: true if the target does a link (eg executable), or
2361cb0ef41Sopenharmony_ci    if there is a target in back_deps that does a link."""
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ci    def __init__(self, name):
2391cb0ef41Sopenharmony_ci        self.deps = set()
2401cb0ef41Sopenharmony_ci        self.match_status = MATCH_STATUS_TBD
2411cb0ef41Sopenharmony_ci        self.back_deps = set()
2421cb0ef41Sopenharmony_ci        self.name = name
2431cb0ef41Sopenharmony_ci        # TODO(sky): I don't like hanging this off Target. This state is specific
2441cb0ef41Sopenharmony_ci        # to certain functions and should be isolated there.
2451cb0ef41Sopenharmony_ci        self.visited = False
2461cb0ef41Sopenharmony_ci        self.requires_build = False
2471cb0ef41Sopenharmony_ci        self.added_to_compile_targets = False
2481cb0ef41Sopenharmony_ci        self.in_roots = False
2491cb0ef41Sopenharmony_ci        self.is_executable = False
2501cb0ef41Sopenharmony_ci        self.is_static_library = False
2511cb0ef41Sopenharmony_ci        self.is_or_has_linked_ancestor = False
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ciclass Config:
2551cb0ef41Sopenharmony_ci    """Details what we're looking for
2561cb0ef41Sopenharmony_ci  files: set of files to search for
2571cb0ef41Sopenharmony_ci  targets: see file description for details."""
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_ci    def __init__(self):
2601cb0ef41Sopenharmony_ci        self.files = []
2611cb0ef41Sopenharmony_ci        self.targets = set()
2621cb0ef41Sopenharmony_ci        self.additional_compile_target_names = set()
2631cb0ef41Sopenharmony_ci        self.test_target_names = set()
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ci    def Init(self, params):
2661cb0ef41Sopenharmony_ci        """Initializes Config. This is a separate method as it raises an exception
2671cb0ef41Sopenharmony_ci    if there is a parse error."""
2681cb0ef41Sopenharmony_ci        generator_flags = params.get("generator_flags", {})
2691cb0ef41Sopenharmony_ci        config_path = generator_flags.get("config_path", None)
2701cb0ef41Sopenharmony_ci        if not config_path:
2711cb0ef41Sopenharmony_ci            return
2721cb0ef41Sopenharmony_ci        try:
2731cb0ef41Sopenharmony_ci            f = open(config_path)
2741cb0ef41Sopenharmony_ci            config = json.load(f)
2751cb0ef41Sopenharmony_ci            f.close()
2761cb0ef41Sopenharmony_ci        except OSError:
2771cb0ef41Sopenharmony_ci            raise Exception("Unable to open file " + config_path)
2781cb0ef41Sopenharmony_ci        except ValueError as e:
2791cb0ef41Sopenharmony_ci            raise Exception("Unable to parse config file " + config_path + str(e))
2801cb0ef41Sopenharmony_ci        if not isinstance(config, dict):
2811cb0ef41Sopenharmony_ci            raise Exception("config_path must be a JSON file containing a dictionary")
2821cb0ef41Sopenharmony_ci        self.files = config.get("files", [])
2831cb0ef41Sopenharmony_ci        self.additional_compile_target_names = set(
2841cb0ef41Sopenharmony_ci            config.get("additional_compile_targets", [])
2851cb0ef41Sopenharmony_ci        )
2861cb0ef41Sopenharmony_ci        self.test_target_names = set(config.get("test_targets", []))
2871cb0ef41Sopenharmony_ci
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_cidef _WasBuildFileModified(build_file, data, files, toplevel_dir):
2901cb0ef41Sopenharmony_ci    """Returns true if the build file |build_file| is either in |files| or
2911cb0ef41Sopenharmony_ci  one of the files included by |build_file| is in |files|. |toplevel_dir| is
2921cb0ef41Sopenharmony_ci  the root of the source tree."""
2931cb0ef41Sopenharmony_ci    if _ToLocalPath(toplevel_dir, _ToGypPath(build_file)) in files:
2941cb0ef41Sopenharmony_ci        if debug:
2951cb0ef41Sopenharmony_ci            print("gyp file modified", build_file)
2961cb0ef41Sopenharmony_ci        return True
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ci    # First element of included_files is the file itself.
2991cb0ef41Sopenharmony_ci    if len(data[build_file]["included_files"]) <= 1:
3001cb0ef41Sopenharmony_ci        return False
3011cb0ef41Sopenharmony_ci
3021cb0ef41Sopenharmony_ci    for include_file in data[build_file]["included_files"][1:]:
3031cb0ef41Sopenharmony_ci        # |included_files| are relative to the directory of the |build_file|.
3041cb0ef41Sopenharmony_ci        rel_include_file = _ToGypPath(
3051cb0ef41Sopenharmony_ci            gyp.common.UnrelativePath(include_file, build_file)
3061cb0ef41Sopenharmony_ci        )
3071cb0ef41Sopenharmony_ci        if _ToLocalPath(toplevel_dir, rel_include_file) in files:
3081cb0ef41Sopenharmony_ci            if debug:
3091cb0ef41Sopenharmony_ci                print(
3101cb0ef41Sopenharmony_ci                    "included gyp file modified, gyp_file=",
3111cb0ef41Sopenharmony_ci                    build_file,
3121cb0ef41Sopenharmony_ci                    "included file=",
3131cb0ef41Sopenharmony_ci                    rel_include_file,
3141cb0ef41Sopenharmony_ci                )
3151cb0ef41Sopenharmony_ci            return True
3161cb0ef41Sopenharmony_ci    return False
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_cidef _GetOrCreateTargetByName(targets, target_name):
3201cb0ef41Sopenharmony_ci    """Creates or returns the Target at targets[target_name]. If there is no
3211cb0ef41Sopenharmony_ci  Target for |target_name| one is created. Returns a tuple of whether a new
3221cb0ef41Sopenharmony_ci  Target was created and the Target."""
3231cb0ef41Sopenharmony_ci    if target_name in targets:
3241cb0ef41Sopenharmony_ci        return False, targets[target_name]
3251cb0ef41Sopenharmony_ci    target = Target(target_name)
3261cb0ef41Sopenharmony_ci    targets[target_name] = target
3271cb0ef41Sopenharmony_ci    return True, target
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci
3301cb0ef41Sopenharmony_cidef _DoesTargetTypeRequireBuild(target_dict):
3311cb0ef41Sopenharmony_ci    """Returns true if the target type is such that it needs to be built."""
3321cb0ef41Sopenharmony_ci    # If a 'none' target has rules or actions we assume it requires a build.
3331cb0ef41Sopenharmony_ci    return bool(
3341cb0ef41Sopenharmony_ci        target_dict["type"] != "none"
3351cb0ef41Sopenharmony_ci        or target_dict.get("actions")
3361cb0ef41Sopenharmony_ci        or target_dict.get("rules")
3371cb0ef41Sopenharmony_ci    )
3381cb0ef41Sopenharmony_ci
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_cidef _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files, build_files):
3411cb0ef41Sopenharmony_ci    """Returns a tuple of the following:
3421cb0ef41Sopenharmony_ci  . A dictionary mapping from fully qualified name to Target.
3431cb0ef41Sopenharmony_ci  . A list of the targets that have a source file in |files|.
3441cb0ef41Sopenharmony_ci  . Targets that constitute the 'all' target. See description at top of file
3451cb0ef41Sopenharmony_ci    for details on the 'all' target.
3461cb0ef41Sopenharmony_ci  This sets the |match_status| of the targets that contain any of the source
3471cb0ef41Sopenharmony_ci  files in |files| to MATCH_STATUS_MATCHES.
3481cb0ef41Sopenharmony_ci  |toplevel_dir| is the root of the source tree."""
3491cb0ef41Sopenharmony_ci    # Maps from target name to Target.
3501cb0ef41Sopenharmony_ci    name_to_target = {}
3511cb0ef41Sopenharmony_ci
3521cb0ef41Sopenharmony_ci    # Targets that matched.
3531cb0ef41Sopenharmony_ci    matching_targets = []
3541cb0ef41Sopenharmony_ci
3551cb0ef41Sopenharmony_ci    # Queue of targets to visit.
3561cb0ef41Sopenharmony_ci    targets_to_visit = target_list[:]
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_ci    # Maps from build file to a boolean indicating whether the build file is in
3591cb0ef41Sopenharmony_ci    # |files|.
3601cb0ef41Sopenharmony_ci    build_file_in_files = {}
3611cb0ef41Sopenharmony_ci
3621cb0ef41Sopenharmony_ci    # Root targets across all files.
3631cb0ef41Sopenharmony_ci    roots = set()
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_ci    # Set of Targets in |build_files|.
3661cb0ef41Sopenharmony_ci    build_file_targets = set()
3671cb0ef41Sopenharmony_ci
3681cb0ef41Sopenharmony_ci    while len(targets_to_visit) > 0:
3691cb0ef41Sopenharmony_ci        target_name = targets_to_visit.pop()
3701cb0ef41Sopenharmony_ci        created_target, target = _GetOrCreateTargetByName(name_to_target, target_name)
3711cb0ef41Sopenharmony_ci        if created_target:
3721cb0ef41Sopenharmony_ci            roots.add(target)
3731cb0ef41Sopenharmony_ci        elif target.visited:
3741cb0ef41Sopenharmony_ci            continue
3751cb0ef41Sopenharmony_ci
3761cb0ef41Sopenharmony_ci        target.visited = True
3771cb0ef41Sopenharmony_ci        target.requires_build = _DoesTargetTypeRequireBuild(target_dicts[target_name])
3781cb0ef41Sopenharmony_ci        target_type = target_dicts[target_name]["type"]
3791cb0ef41Sopenharmony_ci        target.is_executable = target_type == "executable"
3801cb0ef41Sopenharmony_ci        target.is_static_library = target_type == "static_library"
3811cb0ef41Sopenharmony_ci        target.is_or_has_linked_ancestor = (
3821cb0ef41Sopenharmony_ci            target_type == "executable" or target_type == "shared_library"
3831cb0ef41Sopenharmony_ci        )
3841cb0ef41Sopenharmony_ci
3851cb0ef41Sopenharmony_ci        build_file = gyp.common.ParseQualifiedTarget(target_name)[0]
3861cb0ef41Sopenharmony_ci        if build_file not in build_file_in_files:
3871cb0ef41Sopenharmony_ci            build_file_in_files[build_file] = _WasBuildFileModified(
3881cb0ef41Sopenharmony_ci                build_file, data, files, toplevel_dir
3891cb0ef41Sopenharmony_ci            )
3901cb0ef41Sopenharmony_ci
3911cb0ef41Sopenharmony_ci        if build_file in build_files:
3921cb0ef41Sopenharmony_ci            build_file_targets.add(target)
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ci        # If a build file (or any of its included files) is modified we assume all
3951cb0ef41Sopenharmony_ci        # targets in the file are modified.
3961cb0ef41Sopenharmony_ci        if build_file_in_files[build_file]:
3971cb0ef41Sopenharmony_ci            print("matching target from modified build file", target_name)
3981cb0ef41Sopenharmony_ci            target.match_status = MATCH_STATUS_MATCHES
3991cb0ef41Sopenharmony_ci            matching_targets.append(target)
4001cb0ef41Sopenharmony_ci        else:
4011cb0ef41Sopenharmony_ci            sources = _ExtractSources(
4021cb0ef41Sopenharmony_ci                target_name, target_dicts[target_name], toplevel_dir
4031cb0ef41Sopenharmony_ci            )
4041cb0ef41Sopenharmony_ci            for source in sources:
4051cb0ef41Sopenharmony_ci                if _ToGypPath(os.path.normpath(source)) in files:
4061cb0ef41Sopenharmony_ci                    print("target", target_name, "matches", source)
4071cb0ef41Sopenharmony_ci                    target.match_status = MATCH_STATUS_MATCHES
4081cb0ef41Sopenharmony_ci                    matching_targets.append(target)
4091cb0ef41Sopenharmony_ci                    break
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci        # Add dependencies to visit as well as updating back pointers for deps.
4121cb0ef41Sopenharmony_ci        for dep in target_dicts[target_name].get("dependencies", []):
4131cb0ef41Sopenharmony_ci            targets_to_visit.append(dep)
4141cb0ef41Sopenharmony_ci
4151cb0ef41Sopenharmony_ci            created_dep_target, dep_target = _GetOrCreateTargetByName(
4161cb0ef41Sopenharmony_ci                name_to_target, dep
4171cb0ef41Sopenharmony_ci            )
4181cb0ef41Sopenharmony_ci            if not created_dep_target:
4191cb0ef41Sopenharmony_ci                roots.discard(dep_target)
4201cb0ef41Sopenharmony_ci
4211cb0ef41Sopenharmony_ci            target.deps.add(dep_target)
4221cb0ef41Sopenharmony_ci            dep_target.back_deps.add(target)
4231cb0ef41Sopenharmony_ci
4241cb0ef41Sopenharmony_ci    return name_to_target, matching_targets, roots & build_file_targets
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_cidef _GetUnqualifiedToTargetMapping(all_targets, to_find):
4281cb0ef41Sopenharmony_ci    """Returns a tuple of the following:
4291cb0ef41Sopenharmony_ci  . mapping (dictionary) from unqualified name to Target for all the
4301cb0ef41Sopenharmony_ci    Targets in |to_find|.
4311cb0ef41Sopenharmony_ci  . any target names not found. If this is empty all targets were found."""
4321cb0ef41Sopenharmony_ci    result = {}
4331cb0ef41Sopenharmony_ci    if not to_find:
4341cb0ef41Sopenharmony_ci        return {}, []
4351cb0ef41Sopenharmony_ci    to_find = set(to_find)
4361cb0ef41Sopenharmony_ci    for target_name in all_targets.keys():
4371cb0ef41Sopenharmony_ci        extracted = gyp.common.ParseQualifiedTarget(target_name)
4381cb0ef41Sopenharmony_ci        if len(extracted) > 1 and extracted[1] in to_find:
4391cb0ef41Sopenharmony_ci            to_find.remove(extracted[1])
4401cb0ef41Sopenharmony_ci            result[extracted[1]] = all_targets[target_name]
4411cb0ef41Sopenharmony_ci            if not to_find:
4421cb0ef41Sopenharmony_ci                return result, []
4431cb0ef41Sopenharmony_ci    return result, [x for x in to_find]
4441cb0ef41Sopenharmony_ci
4451cb0ef41Sopenharmony_ci
4461cb0ef41Sopenharmony_cidef _DoesTargetDependOnMatchingTargets(target):
4471cb0ef41Sopenharmony_ci    """Returns true if |target| or any of its dependencies is one of the
4481cb0ef41Sopenharmony_ci  targets containing the files supplied as input to analyzer. This updates
4491cb0ef41Sopenharmony_ci  |matches| of the Targets as it recurses.
4501cb0ef41Sopenharmony_ci  target: the Target to look for."""
4511cb0ef41Sopenharmony_ci    if target.match_status == MATCH_STATUS_DOESNT_MATCH:
4521cb0ef41Sopenharmony_ci        return False
4531cb0ef41Sopenharmony_ci    if (
4541cb0ef41Sopenharmony_ci        target.match_status == MATCH_STATUS_MATCHES
4551cb0ef41Sopenharmony_ci        or target.match_status == MATCH_STATUS_MATCHES_BY_DEPENDENCY
4561cb0ef41Sopenharmony_ci    ):
4571cb0ef41Sopenharmony_ci        return True
4581cb0ef41Sopenharmony_ci    for dep in target.deps:
4591cb0ef41Sopenharmony_ci        if _DoesTargetDependOnMatchingTargets(dep):
4601cb0ef41Sopenharmony_ci            target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
4611cb0ef41Sopenharmony_ci            print("\t", target.name, "matches by dep", dep.name)
4621cb0ef41Sopenharmony_ci            return True
4631cb0ef41Sopenharmony_ci    target.match_status = MATCH_STATUS_DOESNT_MATCH
4641cb0ef41Sopenharmony_ci    return False
4651cb0ef41Sopenharmony_ci
4661cb0ef41Sopenharmony_ci
4671cb0ef41Sopenharmony_cidef _GetTargetsDependingOnMatchingTargets(possible_targets):
4681cb0ef41Sopenharmony_ci    """Returns the list of Targets in |possible_targets| that depend (either
4691cb0ef41Sopenharmony_ci  directly on indirectly) on at least one of the targets containing the files
4701cb0ef41Sopenharmony_ci  supplied as input to analyzer.
4711cb0ef41Sopenharmony_ci  possible_targets: targets to search from."""
4721cb0ef41Sopenharmony_ci    found = []
4731cb0ef41Sopenharmony_ci    print("Targets that matched by dependency:")
4741cb0ef41Sopenharmony_ci    for target in possible_targets:
4751cb0ef41Sopenharmony_ci        if _DoesTargetDependOnMatchingTargets(target):
4761cb0ef41Sopenharmony_ci            found.append(target)
4771cb0ef41Sopenharmony_ci    return found
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ci
4801cb0ef41Sopenharmony_cidef _AddCompileTargets(target, roots, add_if_no_ancestor, result):
4811cb0ef41Sopenharmony_ci    """Recurses through all targets that depend on |target|, adding all targets
4821cb0ef41Sopenharmony_ci  that need to be built (and are in |roots|) to |result|.
4831cb0ef41Sopenharmony_ci  roots: set of root targets.
4841cb0ef41Sopenharmony_ci  add_if_no_ancestor: If true and there are no ancestors of |target| then add
4851cb0ef41Sopenharmony_ci  |target| to |result|. |target| must still be in |roots|.
4861cb0ef41Sopenharmony_ci  result: targets that need to be built are added here."""
4871cb0ef41Sopenharmony_ci    if target.visited:
4881cb0ef41Sopenharmony_ci        return
4891cb0ef41Sopenharmony_ci
4901cb0ef41Sopenharmony_ci    target.visited = True
4911cb0ef41Sopenharmony_ci    target.in_roots = target in roots
4921cb0ef41Sopenharmony_ci
4931cb0ef41Sopenharmony_ci    for back_dep_target in target.back_deps:
4941cb0ef41Sopenharmony_ci        _AddCompileTargets(back_dep_target, roots, False, result)
4951cb0ef41Sopenharmony_ci        target.added_to_compile_targets |= back_dep_target.added_to_compile_targets
4961cb0ef41Sopenharmony_ci        target.in_roots |= back_dep_target.in_roots
4971cb0ef41Sopenharmony_ci        target.is_or_has_linked_ancestor |= back_dep_target.is_or_has_linked_ancestor
4981cb0ef41Sopenharmony_ci
4991cb0ef41Sopenharmony_ci    # Always add 'executable' targets. Even though they may be built by other
5001cb0ef41Sopenharmony_ci    # targets that depend upon them it makes detection of what is going to be
5011cb0ef41Sopenharmony_ci    # built easier.
5021cb0ef41Sopenharmony_ci    # And always add static_libraries that have no dependencies on them from
5031cb0ef41Sopenharmony_ci    # linkables. This is necessary as the other dependencies on them may be
5041cb0ef41Sopenharmony_ci    # static libraries themselves, which are not compile time dependencies.
5051cb0ef41Sopenharmony_ci    if target.in_roots and (
5061cb0ef41Sopenharmony_ci        target.is_executable
5071cb0ef41Sopenharmony_ci        or (
5081cb0ef41Sopenharmony_ci            not target.added_to_compile_targets
5091cb0ef41Sopenharmony_ci            and (add_if_no_ancestor or target.requires_build)
5101cb0ef41Sopenharmony_ci        )
5111cb0ef41Sopenharmony_ci        or (
5121cb0ef41Sopenharmony_ci            target.is_static_library
5131cb0ef41Sopenharmony_ci            and add_if_no_ancestor
5141cb0ef41Sopenharmony_ci            and not target.is_or_has_linked_ancestor
5151cb0ef41Sopenharmony_ci        )
5161cb0ef41Sopenharmony_ci    ):
5171cb0ef41Sopenharmony_ci        print(
5181cb0ef41Sopenharmony_ci            "\t\tadding to compile targets",
5191cb0ef41Sopenharmony_ci            target.name,
5201cb0ef41Sopenharmony_ci            "executable",
5211cb0ef41Sopenharmony_ci            target.is_executable,
5221cb0ef41Sopenharmony_ci            "added_to_compile_targets",
5231cb0ef41Sopenharmony_ci            target.added_to_compile_targets,
5241cb0ef41Sopenharmony_ci            "add_if_no_ancestor",
5251cb0ef41Sopenharmony_ci            add_if_no_ancestor,
5261cb0ef41Sopenharmony_ci            "requires_build",
5271cb0ef41Sopenharmony_ci            target.requires_build,
5281cb0ef41Sopenharmony_ci            "is_static_library",
5291cb0ef41Sopenharmony_ci            target.is_static_library,
5301cb0ef41Sopenharmony_ci            "is_or_has_linked_ancestor",
5311cb0ef41Sopenharmony_ci            target.is_or_has_linked_ancestor,
5321cb0ef41Sopenharmony_ci        )
5331cb0ef41Sopenharmony_ci        result.add(target)
5341cb0ef41Sopenharmony_ci        target.added_to_compile_targets = True
5351cb0ef41Sopenharmony_ci
5361cb0ef41Sopenharmony_ci
5371cb0ef41Sopenharmony_cidef _GetCompileTargets(matching_targets, supplied_targets):
5381cb0ef41Sopenharmony_ci    """Returns the set of Targets that require a build.
5391cb0ef41Sopenharmony_ci  matching_targets: targets that changed and need to be built.
5401cb0ef41Sopenharmony_ci  supplied_targets: set of targets supplied to analyzer to search from."""
5411cb0ef41Sopenharmony_ci    result = set()
5421cb0ef41Sopenharmony_ci    for target in matching_targets:
5431cb0ef41Sopenharmony_ci        print("finding compile targets for match", target.name)
5441cb0ef41Sopenharmony_ci        _AddCompileTargets(target, supplied_targets, True, result)
5451cb0ef41Sopenharmony_ci    return result
5461cb0ef41Sopenharmony_ci
5471cb0ef41Sopenharmony_ci
5481cb0ef41Sopenharmony_cidef _WriteOutput(params, **values):
5491cb0ef41Sopenharmony_ci    """Writes the output, either to stdout or a file is specified."""
5501cb0ef41Sopenharmony_ci    if "error" in values:
5511cb0ef41Sopenharmony_ci        print("Error:", values["error"])
5521cb0ef41Sopenharmony_ci    if "status" in values:
5531cb0ef41Sopenharmony_ci        print(values["status"])
5541cb0ef41Sopenharmony_ci    if "targets" in values:
5551cb0ef41Sopenharmony_ci        values["targets"].sort()
5561cb0ef41Sopenharmony_ci        print("Supplied targets that depend on changed files:")
5571cb0ef41Sopenharmony_ci        for target in values["targets"]:
5581cb0ef41Sopenharmony_ci            print("\t", target)
5591cb0ef41Sopenharmony_ci    if "invalid_targets" in values:
5601cb0ef41Sopenharmony_ci        values["invalid_targets"].sort()
5611cb0ef41Sopenharmony_ci        print("The following targets were not found:")
5621cb0ef41Sopenharmony_ci        for target in values["invalid_targets"]:
5631cb0ef41Sopenharmony_ci            print("\t", target)
5641cb0ef41Sopenharmony_ci    if "build_targets" in values:
5651cb0ef41Sopenharmony_ci        values["build_targets"].sort()
5661cb0ef41Sopenharmony_ci        print("Targets that require a build:")
5671cb0ef41Sopenharmony_ci        for target in values["build_targets"]:
5681cb0ef41Sopenharmony_ci            print("\t", target)
5691cb0ef41Sopenharmony_ci    if "compile_targets" in values:
5701cb0ef41Sopenharmony_ci        values["compile_targets"].sort()
5711cb0ef41Sopenharmony_ci        print("Targets that need to be built:")
5721cb0ef41Sopenharmony_ci        for target in values["compile_targets"]:
5731cb0ef41Sopenharmony_ci            print("\t", target)
5741cb0ef41Sopenharmony_ci    if "test_targets" in values:
5751cb0ef41Sopenharmony_ci        values["test_targets"].sort()
5761cb0ef41Sopenharmony_ci        print("Test targets:")
5771cb0ef41Sopenharmony_ci        for target in values["test_targets"]:
5781cb0ef41Sopenharmony_ci            print("\t", target)
5791cb0ef41Sopenharmony_ci
5801cb0ef41Sopenharmony_ci    output_path = params.get("generator_flags", {}).get("analyzer_output_path", None)
5811cb0ef41Sopenharmony_ci    if not output_path:
5821cb0ef41Sopenharmony_ci        print(json.dumps(values))
5831cb0ef41Sopenharmony_ci        return
5841cb0ef41Sopenharmony_ci    try:
5851cb0ef41Sopenharmony_ci        f = open(output_path, "w")
5861cb0ef41Sopenharmony_ci        f.write(json.dumps(values) + "\n")
5871cb0ef41Sopenharmony_ci        f.close()
5881cb0ef41Sopenharmony_ci    except OSError as e:
5891cb0ef41Sopenharmony_ci        print("Error writing to output file", output_path, str(e))
5901cb0ef41Sopenharmony_ci
5911cb0ef41Sopenharmony_ci
5921cb0ef41Sopenharmony_cidef _WasGypIncludeFileModified(params, files):
5931cb0ef41Sopenharmony_ci    """Returns true if one of the files in |files| is in the set of included
5941cb0ef41Sopenharmony_ci  files."""
5951cb0ef41Sopenharmony_ci    if params["options"].includes:
5961cb0ef41Sopenharmony_ci        for include in params["options"].includes:
5971cb0ef41Sopenharmony_ci            if _ToGypPath(os.path.normpath(include)) in files:
5981cb0ef41Sopenharmony_ci                print("Include file modified, assuming all changed", include)
5991cb0ef41Sopenharmony_ci                return True
6001cb0ef41Sopenharmony_ci    return False
6011cb0ef41Sopenharmony_ci
6021cb0ef41Sopenharmony_ci
6031cb0ef41Sopenharmony_cidef _NamesNotIn(names, mapping):
6041cb0ef41Sopenharmony_ci    """Returns a list of the values in |names| that are not in |mapping|."""
6051cb0ef41Sopenharmony_ci    return [name for name in names if name not in mapping]
6061cb0ef41Sopenharmony_ci
6071cb0ef41Sopenharmony_ci
6081cb0ef41Sopenharmony_cidef _LookupTargets(names, mapping):
6091cb0ef41Sopenharmony_ci    """Returns a list of the mapping[name] for each value in |names| that is in
6101cb0ef41Sopenharmony_ci  |mapping|."""
6111cb0ef41Sopenharmony_ci    return [mapping[name] for name in names if name in mapping]
6121cb0ef41Sopenharmony_ci
6131cb0ef41Sopenharmony_ci
6141cb0ef41Sopenharmony_cidef CalculateVariables(default_variables, params):
6151cb0ef41Sopenharmony_ci    """Calculate additional variables for use in the build (called by gyp)."""
6161cb0ef41Sopenharmony_ci    flavor = gyp.common.GetFlavor(params)
6171cb0ef41Sopenharmony_ci    if flavor == "mac":
6181cb0ef41Sopenharmony_ci        default_variables.setdefault("OS", "mac")
6191cb0ef41Sopenharmony_ci    elif flavor == "win":
6201cb0ef41Sopenharmony_ci        default_variables.setdefault("OS", "win")
6211cb0ef41Sopenharmony_ci        gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
6221cb0ef41Sopenharmony_ci    else:
6231cb0ef41Sopenharmony_ci        operating_system = flavor
6241cb0ef41Sopenharmony_ci        if flavor == "android":
6251cb0ef41Sopenharmony_ci            operating_system = "linux"  # Keep this legacy behavior for now.
6261cb0ef41Sopenharmony_ci        default_variables.setdefault("OS", operating_system)
6271cb0ef41Sopenharmony_ci
6281cb0ef41Sopenharmony_ci
6291cb0ef41Sopenharmony_ciclass TargetCalculator:
6301cb0ef41Sopenharmony_ci    """Calculates the matching test_targets and matching compile_targets."""
6311cb0ef41Sopenharmony_ci
6321cb0ef41Sopenharmony_ci    def __init__(
6331cb0ef41Sopenharmony_ci        self,
6341cb0ef41Sopenharmony_ci        files,
6351cb0ef41Sopenharmony_ci        additional_compile_target_names,
6361cb0ef41Sopenharmony_ci        test_target_names,
6371cb0ef41Sopenharmony_ci        data,
6381cb0ef41Sopenharmony_ci        target_list,
6391cb0ef41Sopenharmony_ci        target_dicts,
6401cb0ef41Sopenharmony_ci        toplevel_dir,
6411cb0ef41Sopenharmony_ci        build_files,
6421cb0ef41Sopenharmony_ci    ):
6431cb0ef41Sopenharmony_ci        self._additional_compile_target_names = set(additional_compile_target_names)
6441cb0ef41Sopenharmony_ci        self._test_target_names = set(test_target_names)
6451cb0ef41Sopenharmony_ci        (
6461cb0ef41Sopenharmony_ci            self._name_to_target,
6471cb0ef41Sopenharmony_ci            self._changed_targets,
6481cb0ef41Sopenharmony_ci            self._root_targets,
6491cb0ef41Sopenharmony_ci        ) = _GenerateTargets(
6501cb0ef41Sopenharmony_ci            data, target_list, target_dicts, toplevel_dir, frozenset(files), build_files
6511cb0ef41Sopenharmony_ci        )
6521cb0ef41Sopenharmony_ci        (
6531cb0ef41Sopenharmony_ci            self._unqualified_mapping,
6541cb0ef41Sopenharmony_ci            self.invalid_targets,
6551cb0ef41Sopenharmony_ci        ) = _GetUnqualifiedToTargetMapping(
6561cb0ef41Sopenharmony_ci            self._name_to_target, self._supplied_target_names_no_all()
6571cb0ef41Sopenharmony_ci        )
6581cb0ef41Sopenharmony_ci
6591cb0ef41Sopenharmony_ci    def _supplied_target_names(self):
6601cb0ef41Sopenharmony_ci        return self._additional_compile_target_names | self._test_target_names
6611cb0ef41Sopenharmony_ci
6621cb0ef41Sopenharmony_ci    def _supplied_target_names_no_all(self):
6631cb0ef41Sopenharmony_ci        """Returns the supplied test targets without 'all'."""
6641cb0ef41Sopenharmony_ci        result = self._supplied_target_names()
6651cb0ef41Sopenharmony_ci        result.discard("all")
6661cb0ef41Sopenharmony_ci        return result
6671cb0ef41Sopenharmony_ci
6681cb0ef41Sopenharmony_ci    def is_build_impacted(self):
6691cb0ef41Sopenharmony_ci        """Returns true if the supplied files impact the build at all."""
6701cb0ef41Sopenharmony_ci        return self._changed_targets
6711cb0ef41Sopenharmony_ci
6721cb0ef41Sopenharmony_ci    def find_matching_test_target_names(self):
6731cb0ef41Sopenharmony_ci        """Returns the set of output test targets."""
6741cb0ef41Sopenharmony_ci        assert self.is_build_impacted()
6751cb0ef41Sopenharmony_ci        # Find the test targets first. 'all' is special cased to mean all the
6761cb0ef41Sopenharmony_ci        # root targets. To deal with all the supplied |test_targets| are expanded
6771cb0ef41Sopenharmony_ci        # to include the root targets during lookup. If any of the root targets
6781cb0ef41Sopenharmony_ci        # match, we remove it and replace it with 'all'.
6791cb0ef41Sopenharmony_ci        test_target_names_no_all = set(self._test_target_names)
6801cb0ef41Sopenharmony_ci        test_target_names_no_all.discard("all")
6811cb0ef41Sopenharmony_ci        test_targets_no_all = _LookupTargets(
6821cb0ef41Sopenharmony_ci            test_target_names_no_all, self._unqualified_mapping
6831cb0ef41Sopenharmony_ci        )
6841cb0ef41Sopenharmony_ci        test_target_names_contains_all = "all" in self._test_target_names
6851cb0ef41Sopenharmony_ci        if test_target_names_contains_all:
6861cb0ef41Sopenharmony_ci            test_targets = [
6871cb0ef41Sopenharmony_ci                x for x in (set(test_targets_no_all) | set(self._root_targets))
6881cb0ef41Sopenharmony_ci            ]
6891cb0ef41Sopenharmony_ci        else:
6901cb0ef41Sopenharmony_ci            test_targets = [x for x in test_targets_no_all]
6911cb0ef41Sopenharmony_ci        print("supplied test_targets")
6921cb0ef41Sopenharmony_ci        for target_name in self._test_target_names:
6931cb0ef41Sopenharmony_ci            print("\t", target_name)
6941cb0ef41Sopenharmony_ci        print("found test_targets")
6951cb0ef41Sopenharmony_ci        for target in test_targets:
6961cb0ef41Sopenharmony_ci            print("\t", target.name)
6971cb0ef41Sopenharmony_ci        print("searching for matching test targets")
6981cb0ef41Sopenharmony_ci        matching_test_targets = _GetTargetsDependingOnMatchingTargets(test_targets)
6991cb0ef41Sopenharmony_ci        matching_test_targets_contains_all = test_target_names_contains_all and set(
7001cb0ef41Sopenharmony_ci            matching_test_targets
7011cb0ef41Sopenharmony_ci        ) & set(self._root_targets)
7021cb0ef41Sopenharmony_ci        if matching_test_targets_contains_all:
7031cb0ef41Sopenharmony_ci            # Remove any of the targets for all that were not explicitly supplied,
7041cb0ef41Sopenharmony_ci            # 'all' is subsequentely added to the matching names below.
7051cb0ef41Sopenharmony_ci            matching_test_targets = [
7061cb0ef41Sopenharmony_ci                x for x in (set(matching_test_targets) & set(test_targets_no_all))
7071cb0ef41Sopenharmony_ci            ]
7081cb0ef41Sopenharmony_ci        print("matched test_targets")
7091cb0ef41Sopenharmony_ci        for target in matching_test_targets:
7101cb0ef41Sopenharmony_ci            print("\t", target.name)
7111cb0ef41Sopenharmony_ci        matching_target_names = [
7121cb0ef41Sopenharmony_ci            gyp.common.ParseQualifiedTarget(target.name)[1]
7131cb0ef41Sopenharmony_ci            for target in matching_test_targets
7141cb0ef41Sopenharmony_ci        ]
7151cb0ef41Sopenharmony_ci        if matching_test_targets_contains_all:
7161cb0ef41Sopenharmony_ci            matching_target_names.append("all")
7171cb0ef41Sopenharmony_ci            print("\tall")
7181cb0ef41Sopenharmony_ci        return matching_target_names
7191cb0ef41Sopenharmony_ci
7201cb0ef41Sopenharmony_ci    def find_matching_compile_target_names(self):
7211cb0ef41Sopenharmony_ci        """Returns the set of output compile targets."""
7221cb0ef41Sopenharmony_ci        assert self.is_build_impacted()
7231cb0ef41Sopenharmony_ci        # Compile targets are found by searching up from changed targets.
7241cb0ef41Sopenharmony_ci        # Reset the visited status for _GetBuildTargets.
7251cb0ef41Sopenharmony_ci        for target in self._name_to_target.values():
7261cb0ef41Sopenharmony_ci            target.visited = False
7271cb0ef41Sopenharmony_ci
7281cb0ef41Sopenharmony_ci        supplied_targets = _LookupTargets(
7291cb0ef41Sopenharmony_ci            self._supplied_target_names_no_all(), self._unqualified_mapping
7301cb0ef41Sopenharmony_ci        )
7311cb0ef41Sopenharmony_ci        if "all" in self._supplied_target_names():
7321cb0ef41Sopenharmony_ci            supplied_targets = [
7331cb0ef41Sopenharmony_ci                x for x in (set(supplied_targets) | set(self._root_targets))
7341cb0ef41Sopenharmony_ci            ]
7351cb0ef41Sopenharmony_ci        print("Supplied test_targets & compile_targets")
7361cb0ef41Sopenharmony_ci        for target in supplied_targets:
7371cb0ef41Sopenharmony_ci            print("\t", target.name)
7381cb0ef41Sopenharmony_ci        print("Finding compile targets")
7391cb0ef41Sopenharmony_ci        compile_targets = _GetCompileTargets(self._changed_targets, supplied_targets)
7401cb0ef41Sopenharmony_ci        return [
7411cb0ef41Sopenharmony_ci            gyp.common.ParseQualifiedTarget(target.name)[1]
7421cb0ef41Sopenharmony_ci            for target in compile_targets
7431cb0ef41Sopenharmony_ci        ]
7441cb0ef41Sopenharmony_ci
7451cb0ef41Sopenharmony_ci
7461cb0ef41Sopenharmony_cidef GenerateOutput(target_list, target_dicts, data, params):
7471cb0ef41Sopenharmony_ci    """Called by gyp as the final stage. Outputs results."""
7481cb0ef41Sopenharmony_ci    config = Config()
7491cb0ef41Sopenharmony_ci    try:
7501cb0ef41Sopenharmony_ci        config.Init(params)
7511cb0ef41Sopenharmony_ci
7521cb0ef41Sopenharmony_ci        if not config.files:
7531cb0ef41Sopenharmony_ci            raise Exception(
7541cb0ef41Sopenharmony_ci                "Must specify files to analyze via config_path generator " "flag"
7551cb0ef41Sopenharmony_ci            )
7561cb0ef41Sopenharmony_ci
7571cb0ef41Sopenharmony_ci        toplevel_dir = _ToGypPath(os.path.abspath(params["options"].toplevel_dir))
7581cb0ef41Sopenharmony_ci        if debug:
7591cb0ef41Sopenharmony_ci            print("toplevel_dir", toplevel_dir)
7601cb0ef41Sopenharmony_ci
7611cb0ef41Sopenharmony_ci        if _WasGypIncludeFileModified(params, config.files):
7621cb0ef41Sopenharmony_ci            result_dict = {
7631cb0ef41Sopenharmony_ci                "status": all_changed_string,
7641cb0ef41Sopenharmony_ci                "test_targets": list(config.test_target_names),
7651cb0ef41Sopenharmony_ci                "compile_targets": list(
7661cb0ef41Sopenharmony_ci                    config.additional_compile_target_names | config.test_target_names
7671cb0ef41Sopenharmony_ci                ),
7681cb0ef41Sopenharmony_ci            }
7691cb0ef41Sopenharmony_ci            _WriteOutput(params, **result_dict)
7701cb0ef41Sopenharmony_ci            return
7711cb0ef41Sopenharmony_ci
7721cb0ef41Sopenharmony_ci        calculator = TargetCalculator(
7731cb0ef41Sopenharmony_ci            config.files,
7741cb0ef41Sopenharmony_ci            config.additional_compile_target_names,
7751cb0ef41Sopenharmony_ci            config.test_target_names,
7761cb0ef41Sopenharmony_ci            data,
7771cb0ef41Sopenharmony_ci            target_list,
7781cb0ef41Sopenharmony_ci            target_dicts,
7791cb0ef41Sopenharmony_ci            toplevel_dir,
7801cb0ef41Sopenharmony_ci            params["build_files"],
7811cb0ef41Sopenharmony_ci        )
7821cb0ef41Sopenharmony_ci        if not calculator.is_build_impacted():
7831cb0ef41Sopenharmony_ci            result_dict = {
7841cb0ef41Sopenharmony_ci                "status": no_dependency_string,
7851cb0ef41Sopenharmony_ci                "test_targets": [],
7861cb0ef41Sopenharmony_ci                "compile_targets": [],
7871cb0ef41Sopenharmony_ci            }
7881cb0ef41Sopenharmony_ci            if calculator.invalid_targets:
7891cb0ef41Sopenharmony_ci                result_dict["invalid_targets"] = calculator.invalid_targets
7901cb0ef41Sopenharmony_ci            _WriteOutput(params, **result_dict)
7911cb0ef41Sopenharmony_ci            return
7921cb0ef41Sopenharmony_ci
7931cb0ef41Sopenharmony_ci        test_target_names = calculator.find_matching_test_target_names()
7941cb0ef41Sopenharmony_ci        compile_target_names = calculator.find_matching_compile_target_names()
7951cb0ef41Sopenharmony_ci        found_at_least_one_target = compile_target_names or test_target_names
7961cb0ef41Sopenharmony_ci        result_dict = {
7971cb0ef41Sopenharmony_ci            "test_targets": test_target_names,
7981cb0ef41Sopenharmony_ci            "status": found_dependency_string
7991cb0ef41Sopenharmony_ci            if found_at_least_one_target
8001cb0ef41Sopenharmony_ci            else no_dependency_string,
8011cb0ef41Sopenharmony_ci            "compile_targets": list(set(compile_target_names) | set(test_target_names)),
8021cb0ef41Sopenharmony_ci        }
8031cb0ef41Sopenharmony_ci        if calculator.invalid_targets:
8041cb0ef41Sopenharmony_ci            result_dict["invalid_targets"] = calculator.invalid_targets
8051cb0ef41Sopenharmony_ci        _WriteOutput(params, **result_dict)
8061cb0ef41Sopenharmony_ci
8071cb0ef41Sopenharmony_ci    except Exception as e:
8081cb0ef41Sopenharmony_ci        _WriteOutput(params, error=str(e))
809