"Fossies" - the Fresh Open Source Software Archive

Member "node-v19.8.1-win-x64/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/generator/android.py" (16 Feb 2023, 51139 Bytes) of package /windows/www/node-v19.8.1-win-x64.zip:


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

    1 # Copyright (c) 2012 Google Inc. All rights reserved.
    2 # Use of this source code is governed by a BSD-style license that can be
    3 # found in the LICENSE file.
    4 
    5 # Notes:
    6 #
    7 # This generates makefiles suitable for inclusion into the Android build system
    8 # via an Android.mk file. It is based on make.py, the standard makefile
    9 # generator.
   10 #
   11 # The code below generates a separate .mk file for each target, but
   12 # all are sourced by the top-level GypAndroid.mk.  This means that all
   13 # variables in .mk-files clobber one another, and furthermore that any
   14 # variables set potentially clash with other Android build system variables.
   15 # Try to avoid setting global variables where possible.
   16 
   17 
   18 import gyp
   19 import gyp.common
   20 import gyp.generator.make as make  # Reuse global functions from make backend.
   21 import os
   22 import re
   23 import subprocess
   24 
   25 generator_default_variables = {
   26     "OS": "android",
   27     "EXECUTABLE_PREFIX": "",
   28     "EXECUTABLE_SUFFIX": "",
   29     "STATIC_LIB_PREFIX": "lib",
   30     "SHARED_LIB_PREFIX": "lib",
   31     "STATIC_LIB_SUFFIX": ".a",
   32     "SHARED_LIB_SUFFIX": ".so",
   33     "INTERMEDIATE_DIR": "$(gyp_intermediate_dir)",
   34     "SHARED_INTERMEDIATE_DIR": "$(gyp_shared_intermediate_dir)",
   35     "PRODUCT_DIR": "$(gyp_shared_intermediate_dir)",
   36     "SHARED_LIB_DIR": "$(builddir)/lib.$(TOOLSET)",
   37     "LIB_DIR": "$(obj).$(TOOLSET)",
   38     "RULE_INPUT_ROOT": "%(INPUT_ROOT)s",  # This gets expanded by Python.
   39     "RULE_INPUT_DIRNAME": "%(INPUT_DIRNAME)s",  # This gets expanded by Python.
   40     "RULE_INPUT_PATH": "$(RULE_SOURCES)",
   41     "RULE_INPUT_EXT": "$(suffix $<)",
   42     "RULE_INPUT_NAME": "$(notdir $<)",
   43     "CONFIGURATION_NAME": "$(GYP_CONFIGURATION)",
   44 }
   45 
   46 # Make supports multiple toolsets
   47 generator_supports_multiple_toolsets = True
   48 
   49 
   50 # Generator-specific gyp specs.
   51 generator_additional_non_configuration_keys = [
   52     # Boolean to declare that this target does not want its name mangled.
   53     "android_unmangled_name",
   54     # Map of android build system variables to set.
   55     "aosp_build_settings",
   56 ]
   57 generator_additional_path_sections = []
   58 generator_extra_sources_for_rules = []
   59 
   60 
   61 ALL_MODULES_FOOTER = """\
   62 # "gyp_all_modules" is a concatenation of the "gyp_all_modules" targets from
   63 # all the included sub-makefiles. This is just here to clarify.
   64 gyp_all_modules:
   65 """
   66 
   67 header = """\
   68 # This file is generated by gyp; do not edit.
   69 
   70 """
   71 
   72 # Map gyp target types to Android module classes.
   73 MODULE_CLASSES = {
   74     "static_library": "STATIC_LIBRARIES",
   75     "shared_library": "SHARED_LIBRARIES",
   76     "executable": "EXECUTABLES",
   77 }
   78 
   79 
   80 def IsCPPExtension(ext):
   81     return make.COMPILABLE_EXTENSIONS.get(ext) == "cxx"
   82 
   83 
   84 def Sourceify(path):
   85     """Convert a path to its source directory form. The Android backend does not
   86     support options.generator_output, so this function is a noop."""
   87     return path
   88 
   89 
   90 # Map from qualified target to path to output.
   91 # For Android, the target of these maps is a tuple ('static', 'modulename'),
   92 # ('dynamic', 'modulename'), or ('path', 'some/path') instead of a string,
   93 # since we link by module.
   94 target_outputs = {}
   95 # Map from qualified target to any linkable output.  A subset
   96 # of target_outputs.  E.g. when mybinary depends on liba, we want to
   97 # include liba in the linker line; when otherbinary depends on
   98 # mybinary, we just want to build mybinary first.
   99 target_link_deps = {}
  100 
  101 
  102 class AndroidMkWriter:
  103     """AndroidMkWriter packages up the writing of one target-specific Android.mk.
  104 
  105     Its only real entry point is Write(), and is mostly used for namespacing.
  106     """
  107 
  108     def __init__(self, android_top_dir):
  109         self.android_top_dir = android_top_dir
  110 
  111     def Write(
  112         self,
  113         qualified_target,
  114         relative_target,
  115         base_path,
  116         output_filename,
  117         spec,
  118         configs,
  119         part_of_all,
  120         write_alias_target,
  121         sdk_version,
  122     ):
  123         """The main entry point: writes a .mk file for a single target.
  124 
  125         Arguments:
  126           qualified_target: target we're generating
  127           relative_target: qualified target name relative to the root
  128           base_path: path relative to source root we're building in, used to resolve
  129                      target-relative paths
  130           output_filename: output .mk file name to write
  131           spec, configs: gyp info
  132           part_of_all: flag indicating this target is part of 'all'
  133           write_alias_target: flag indicating whether to create short aliases for
  134                               this target
  135           sdk_version: what to emit for LOCAL_SDK_VERSION in output
  136         """
  137         gyp.common.EnsureDirExists(output_filename)
  138 
  139         self.fp = open(output_filename, "w")
  140 
  141         self.fp.write(header)
  142 
  143         self.qualified_target = qualified_target
  144         self.relative_target = relative_target
  145         self.path = base_path
  146         self.target = spec["target_name"]
  147         self.type = spec["type"]
  148         self.toolset = spec["toolset"]
  149 
  150         deps, link_deps = self.ComputeDeps(spec)
  151 
  152         # Some of the generation below can add extra output, sources, or
  153         # link dependencies.  All of the out params of the functions that
  154         # follow use names like extra_foo.
  155         extra_outputs = []
  156         extra_sources = []
  157 
  158         self.android_class = MODULE_CLASSES.get(self.type, "GYP")
  159         self.android_module = self.ComputeAndroidModule(spec)
  160         (self.android_stem, self.android_suffix) = self.ComputeOutputParts(spec)
  161         self.output = self.output_binary = self.ComputeOutput(spec)
  162 
  163         # Standard header.
  164         self.WriteLn("include $(CLEAR_VARS)\n")
  165 
  166         # Module class and name.
  167         self.WriteLn("LOCAL_MODULE_CLASS := " + self.android_class)
  168         self.WriteLn("LOCAL_MODULE := " + self.android_module)
  169         # Only emit LOCAL_MODULE_STEM if it's different to LOCAL_MODULE.
  170         # The library module classes fail if the stem is set. ComputeOutputParts
  171         # makes sure that stem == modulename in these cases.
  172         if self.android_stem != self.android_module:
  173             self.WriteLn("LOCAL_MODULE_STEM := " + self.android_stem)
  174         self.WriteLn("LOCAL_MODULE_SUFFIX := " + self.android_suffix)
  175         if self.toolset == "host":
  176             self.WriteLn("LOCAL_IS_HOST_MODULE := true")
  177             self.WriteLn("LOCAL_MULTILIB := $(GYP_HOST_MULTILIB)")
  178         elif sdk_version > 0:
  179             self.WriteLn(
  180                 "LOCAL_MODULE_TARGET_ARCH := " "$(TARGET_$(GYP_VAR_PREFIX)ARCH)"
  181             )
  182             self.WriteLn("LOCAL_SDK_VERSION := %s" % sdk_version)
  183 
  184         # Grab output directories; needed for Actions and Rules.
  185         if self.toolset == "host":
  186             self.WriteLn(
  187                 "gyp_intermediate_dir := "
  188                 "$(call local-intermediates-dir,,$(GYP_HOST_VAR_PREFIX))"
  189             )
  190         else:
  191             self.WriteLn(
  192                 "gyp_intermediate_dir := "
  193                 "$(call local-intermediates-dir,,$(GYP_VAR_PREFIX))"
  194             )
  195         self.WriteLn(
  196             "gyp_shared_intermediate_dir := "
  197             "$(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))"
  198         )
  199         self.WriteLn()
  200 
  201         # List files this target depends on so that actions/rules/copies/sources
  202         # can depend on the list.
  203         # TODO: doesn't pull in things through transitive link deps; needed?
  204         target_dependencies = [x[1] for x in deps if x[0] == "path"]
  205         self.WriteLn("# Make sure our deps are built first.")
  206         self.WriteList(
  207             target_dependencies, "GYP_TARGET_DEPENDENCIES", local_pathify=True
  208         )
  209 
  210         # Actions must come first, since they can generate more OBJs for use below.
  211         if "actions" in spec:
  212             self.WriteActions(spec["actions"], extra_sources, extra_outputs)
  213 
  214         # Rules must be early like actions.
  215         if "rules" in spec:
  216             self.WriteRules(spec["rules"], extra_sources, extra_outputs)
  217 
  218         if "copies" in spec:
  219             self.WriteCopies(spec["copies"], extra_outputs)
  220 
  221         # GYP generated outputs.
  222         self.WriteList(extra_outputs, "GYP_GENERATED_OUTPUTS", local_pathify=True)
  223 
  224         # Set LOCAL_ADDITIONAL_DEPENDENCIES so that Android's build rules depend
  225         # on both our dependency targets and our generated files.
  226         self.WriteLn("# Make sure our deps and generated files are built first.")
  227         self.WriteLn(
  228             "LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) "
  229             "$(GYP_GENERATED_OUTPUTS)"
  230         )
  231         self.WriteLn()
  232 
  233         # Sources.
  234         if spec.get("sources", []) or extra_sources:
  235             self.WriteSources(spec, configs, extra_sources)
  236 
  237         self.WriteTarget(
  238             spec, configs, deps, link_deps, part_of_all, write_alias_target
  239         )
  240 
  241         # Update global list of target outputs, used in dependency tracking.
  242         target_outputs[qualified_target] = ("path", self.output_binary)
  243 
  244         # Update global list of link dependencies.
  245         if self.type == "static_library":
  246             target_link_deps[qualified_target] = ("static", self.android_module)
  247         elif self.type == "shared_library":
  248             target_link_deps[qualified_target] = ("shared", self.android_module)
  249 
  250         self.fp.close()
  251         return self.android_module
  252 
  253     def WriteActions(self, actions, extra_sources, extra_outputs):
  254         """Write Makefile code for any 'actions' from the gyp input.
  255 
  256         extra_sources: a list that will be filled in with newly generated source
  257                        files, if any
  258         extra_outputs: a list that will be filled in with any outputs of these
  259                        actions (used to make other pieces dependent on these
  260                        actions)
  261         """
  262         for action in actions:
  263             name = make.StringToMakefileVariable(
  264                 "{}_{}".format(self.relative_target, action["action_name"])
  265             )
  266             self.WriteLn('### Rules for action "%s":' % action["action_name"])
  267             inputs = action["inputs"]
  268             outputs = action["outputs"]
  269 
  270             # Build up a list of outputs.
  271             # Collect the output dirs we'll need.
  272             dirs = set()
  273             for out in outputs:
  274                 if not out.startswith("$"):
  275                     print(
  276                         'WARNING: Action for target "%s" writes output to local path '
  277                         '"%s".' % (self.target, out)
  278                     )
  279                 dir = os.path.split(out)[0]
  280                 if dir:
  281                     dirs.add(dir)
  282             if int(action.get("process_outputs_as_sources", False)):
  283                 extra_sources += outputs
  284 
  285             # Prepare the actual command.
  286             command = gyp.common.EncodePOSIXShellList(action["action"])
  287             if "message" in action:
  288                 quiet_cmd = "Gyp action: %s ($@)" % action["message"]
  289             else:
  290                 quiet_cmd = "Gyp action: %s ($@)" % name
  291             if len(dirs) > 0:
  292                 command = "mkdir -p %s" % " ".join(dirs) + "; " + command
  293 
  294             cd_action = "cd $(gyp_local_path)/%s; " % self.path
  295             command = cd_action + command
  296 
  297             # The makefile rules are all relative to the top dir, but the gyp actions
  298             # are defined relative to their containing dir.  This replaces the gyp_*
  299             # variables for the action rule with an absolute version so that the
  300             # output goes in the right place.
  301             # Only write the gyp_* rules for the "primary" output (:1);
  302             # it's superfluous for the "extra outputs", and this avoids accidentally
  303             # writing duplicate dummy rules for those outputs.
  304             main_output = make.QuoteSpaces(self.LocalPathify(outputs[0]))
  305             self.WriteLn("%s: gyp_local_path := $(LOCAL_PATH)" % main_output)
  306             self.WriteLn("%s: gyp_var_prefix := $(GYP_VAR_PREFIX)" % main_output)
  307             self.WriteLn(
  308                 "%s: gyp_intermediate_dir := "
  309                 "$(abspath $(gyp_intermediate_dir))" % main_output
  310             )
  311             self.WriteLn(
  312                 "%s: gyp_shared_intermediate_dir := "
  313                 "$(abspath $(gyp_shared_intermediate_dir))" % main_output
  314             )
  315 
  316             # Android's envsetup.sh adds a number of directories to the path including
  317             # the built host binary directory. This causes actions/rules invoked by
  318             # gyp to sometimes use these instead of system versions, e.g. bison.
  319             # The built host binaries may not be suitable, and can cause errors.
  320             # So, we remove them from the PATH using the ANDROID_BUILD_PATHS variable
  321             # set by envsetup.
  322             self.WriteLn(
  323                 "%s: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))"
  324                 % main_output
  325             )
  326 
  327             # Don't allow spaces in input/output filenames, but make an exception for
  328             # filenames which start with '$(' since it's okay for there to be spaces
  329             # inside of make function/macro invocations.
  330             for input in inputs:
  331                 if not input.startswith("$(") and " " in input:
  332                     raise gyp.common.GypError(
  333                         'Action input filename "%s" in target %s contains a space'
  334                         % (input, self.target)
  335                     )
  336             for output in outputs:
  337                 if not output.startswith("$(") and " " in output:
  338                     raise gyp.common.GypError(
  339                         'Action output filename "%s" in target %s contains a space'
  340                         % (output, self.target)
  341                     )
  342 
  343             self.WriteLn(
  344                 "%s: %s $(GYP_TARGET_DEPENDENCIES)"
  345                 % (main_output, " ".join(map(self.LocalPathify, inputs)))
  346             )
  347             self.WriteLn('\t@echo "%s"' % quiet_cmd)
  348             self.WriteLn("\t$(hide)%s\n" % command)
  349             for output in outputs[1:]:
  350                 # Make each output depend on the main output, with an empty command
  351                 # to force make to notice that the mtime has changed.
  352                 self.WriteLn(f"{self.LocalPathify(output)}: {main_output} ;")
  353 
  354             extra_outputs += outputs
  355             self.WriteLn()
  356 
  357         self.WriteLn()
  358 
  359     def WriteRules(self, rules, extra_sources, extra_outputs):
  360         """Write Makefile code for any 'rules' from the gyp input.
  361 
  362         extra_sources: a list that will be filled in with newly generated source
  363                        files, if any
  364         extra_outputs: a list that will be filled in with any outputs of these
  365                        rules (used to make other pieces dependent on these rules)
  366         """
  367         if len(rules) == 0:
  368             return
  369 
  370         for rule in rules:
  371             if len(rule.get("rule_sources", [])) == 0:
  372                 continue
  373             name = make.StringToMakefileVariable(
  374                 "{}_{}".format(self.relative_target, rule["rule_name"])
  375             )
  376             self.WriteLn('\n### Generated for rule "%s":' % name)
  377             self.WriteLn('# "%s":' % rule)
  378 
  379             inputs = rule.get("inputs")
  380             for rule_source in rule.get("rule_sources", []):
  381                 (rule_source_dirname, rule_source_basename) = os.path.split(rule_source)
  382                 (rule_source_root, rule_source_ext) = os.path.splitext(
  383                     rule_source_basename
  384                 )
  385 
  386                 outputs = [
  387                     self.ExpandInputRoot(out, rule_source_root, rule_source_dirname)
  388                     for out in rule["outputs"]
  389                 ]
  390 
  391                 dirs = set()
  392                 for out in outputs:
  393                     if not out.startswith("$"):
  394                         print(
  395                             "WARNING: Rule for target %s writes output to local path %s"
  396                             % (self.target, out)
  397                         )
  398                     dir = os.path.dirname(out)
  399                     if dir:
  400                         dirs.add(dir)
  401                 extra_outputs += outputs
  402                 if int(rule.get("process_outputs_as_sources", False)):
  403                     extra_sources.extend(outputs)
  404 
  405                 components = []
  406                 for component in rule["action"]:
  407                     component = self.ExpandInputRoot(
  408                         component, rule_source_root, rule_source_dirname
  409                     )
  410                     if "$(RULE_SOURCES)" in component:
  411                         component = component.replace("$(RULE_SOURCES)", rule_source)
  412                     components.append(component)
  413 
  414                 command = gyp.common.EncodePOSIXShellList(components)
  415                 cd_action = "cd $(gyp_local_path)/%s; " % self.path
  416                 command = cd_action + command
  417                 if dirs:
  418                     command = "mkdir -p %s" % " ".join(dirs) + "; " + command
  419 
  420                 # We set up a rule to build the first output, and then set up
  421                 # a rule for each additional output to depend on the first.
  422                 outputs = map(self.LocalPathify, outputs)
  423                 main_output = outputs[0]
  424                 self.WriteLn("%s: gyp_local_path := $(LOCAL_PATH)" % main_output)
  425                 self.WriteLn("%s: gyp_var_prefix := $(GYP_VAR_PREFIX)" % main_output)
  426                 self.WriteLn(
  427                     "%s: gyp_intermediate_dir := "
  428                     "$(abspath $(gyp_intermediate_dir))" % main_output
  429                 )
  430                 self.WriteLn(
  431                     "%s: gyp_shared_intermediate_dir := "
  432                     "$(abspath $(gyp_shared_intermediate_dir))" % main_output
  433                 )
  434 
  435                 # See explanation in WriteActions.
  436                 self.WriteLn(
  437                     "%s: export PATH := "
  438                     "$(subst $(ANDROID_BUILD_PATHS),,$(PATH))" % main_output
  439                 )
  440 
  441                 main_output_deps = self.LocalPathify(rule_source)
  442                 if inputs:
  443                     main_output_deps += " "
  444                     main_output_deps += " ".join([self.LocalPathify(f) for f in inputs])
  445 
  446                 self.WriteLn(
  447                     "%s: %s $(GYP_TARGET_DEPENDENCIES)"
  448                     % (main_output, main_output_deps)
  449                 )
  450                 self.WriteLn("\t%s\n" % command)
  451                 for output in outputs[1:]:
  452                     # Make each output depend on the main output, with an empty command
  453                     # to force make to notice that the mtime has changed.
  454                     self.WriteLn(f"{output}: {main_output} ;")
  455                 self.WriteLn()
  456 
  457         self.WriteLn()
  458 
  459     def WriteCopies(self, copies, extra_outputs):
  460         """Write Makefile code for any 'copies' from the gyp input.
  461 
  462         extra_outputs: a list that will be filled in with any outputs of this action
  463                        (used to make other pieces dependent on this action)
  464         """
  465         self.WriteLn("### Generated for copy rule.")
  466 
  467         variable = make.StringToMakefileVariable(self.relative_target + "_copies")
  468         outputs = []
  469         for copy in copies:
  470             for path in copy["files"]:
  471                 # The Android build system does not allow generation of files into the
  472                 # source tree. The destination should start with a variable, which will
  473                 # typically be $(gyp_intermediate_dir) or
  474                 # $(gyp_shared_intermediate_dir). Note that we can't use an assertion
  475                 # because some of the gyp tests depend on this.
  476                 if not copy["destination"].startswith("$"):
  477                     print(
  478                         "WARNING: Copy rule for target %s writes output to "
  479                         "local path %s" % (self.target, copy["destination"])
  480                     )
  481 
  482                 # LocalPathify() calls normpath, stripping trailing slashes.
  483                 path = Sourceify(self.LocalPathify(path))
  484                 filename = os.path.split(path)[1]
  485                 output = Sourceify(
  486                     self.LocalPathify(os.path.join(copy["destination"], filename))
  487                 )
  488 
  489                 self.WriteLn(f"{output}: {path} $(GYP_TARGET_DEPENDENCIES) | $(ACP)")
  490                 self.WriteLn("\t@echo Copying: $@")
  491                 self.WriteLn("\t$(hide) mkdir -p $(dir $@)")
  492                 self.WriteLn("\t$(hide) $(ACP) -rpf $< $@")
  493                 self.WriteLn()
  494                 outputs.append(output)
  495         self.WriteLn(
  496             "{} = {}".format(variable, " ".join(map(make.QuoteSpaces, outputs)))
  497         )
  498         extra_outputs.append("$(%s)" % variable)
  499         self.WriteLn()
  500 
  501     def WriteSourceFlags(self, spec, configs):
  502         """Write out the flags and include paths used to compile source files for
  503         the current target.
  504 
  505         Args:
  506           spec, configs: input from gyp.
  507         """
  508         for configname, config in sorted(configs.items()):
  509             extracted_includes = []
  510 
  511             self.WriteLn("\n# Flags passed to both C and C++ files.")
  512             cflags, includes_from_cflags = self.ExtractIncludesFromCFlags(
  513                 config.get("cflags", []) + config.get("cflags_c", [])
  514             )
  515             extracted_includes.extend(includes_from_cflags)
  516             self.WriteList(cflags, "MY_CFLAGS_%s" % configname)
  517 
  518             self.WriteList(
  519                 config.get("defines"),
  520                 "MY_DEFS_%s" % configname,
  521                 prefix="-D",
  522                 quoter=make.EscapeCppDefine,
  523             )
  524 
  525             self.WriteLn("\n# Include paths placed before CFLAGS/CPPFLAGS")
  526             includes = list(config.get("include_dirs", []))
  527             includes.extend(extracted_includes)
  528             includes = map(Sourceify, map(self.LocalPathify, includes))
  529             includes = self.NormalizeIncludePaths(includes)
  530             self.WriteList(includes, "LOCAL_C_INCLUDES_%s" % configname)
  531 
  532             self.WriteLn("\n# Flags passed to only C++ (and not C) files.")
  533             self.WriteList(config.get("cflags_cc"), "LOCAL_CPPFLAGS_%s" % configname)
  534 
  535         self.WriteLn(
  536             "\nLOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) "
  537             "$(MY_DEFS_$(GYP_CONFIGURATION))"
  538         )
  539         # Undefine ANDROID for host modules
  540         # TODO: the source code should not use macro ANDROID to tell if it's host
  541         # or target module.
  542         if self.toolset == "host":
  543             self.WriteLn("# Undefine ANDROID for host modules")
  544             self.WriteLn("LOCAL_CFLAGS += -UANDROID")
  545         self.WriteLn(
  546             "LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) "
  547             "$(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))"
  548         )
  549         self.WriteLn("LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))")
  550         # Android uses separate flags for assembly file invocations, but gyp expects
  551         # the same CFLAGS to be applied:
  552         self.WriteLn("LOCAL_ASFLAGS := $(LOCAL_CFLAGS)")
  553 
  554     def WriteSources(self, spec, configs, extra_sources):
  555         """Write Makefile code for any 'sources' from the gyp input.
  556         These are source files necessary to build the current target.
  557         We need to handle shared_intermediate directory source files as
  558         a special case by copying them to the intermediate directory and
  559         treating them as a generated sources. Otherwise the Android build
  560         rules won't pick them up.
  561 
  562         Args:
  563           spec, configs: input from gyp.
  564           extra_sources: Sources generated from Actions or Rules.
  565         """
  566         sources = filter(make.Compilable, spec.get("sources", []))
  567         generated_not_sources = [x for x in extra_sources if not make.Compilable(x)]
  568         extra_sources = filter(make.Compilable, extra_sources)
  569 
  570         # Determine and output the C++ extension used by these sources.
  571         # We simply find the first C++ file and use that extension.
  572         all_sources = sources + extra_sources
  573         local_cpp_extension = ".cpp"
  574         for source in all_sources:
  575             (root, ext) = os.path.splitext(source)
  576             if IsCPPExtension(ext):
  577                 local_cpp_extension = ext
  578                 break
  579         if local_cpp_extension != ".cpp":
  580             self.WriteLn("LOCAL_CPP_EXTENSION := %s" % local_cpp_extension)
  581 
  582         # We need to move any non-generated sources that are coming from the
  583         # shared intermediate directory out of LOCAL_SRC_FILES and put them
  584         # into LOCAL_GENERATED_SOURCES. We also need to move over any C++ files
  585         # that don't match our local_cpp_extension, since Android will only
  586         # generate Makefile rules for a single LOCAL_CPP_EXTENSION.
  587         local_files = []
  588         for source in sources:
  589             (root, ext) = os.path.splitext(source)
  590             if "$(gyp_shared_intermediate_dir)" in source:
  591                 extra_sources.append(source)
  592             elif "$(gyp_intermediate_dir)" in source:
  593                 extra_sources.append(source)
  594             elif IsCPPExtension(ext) and ext != local_cpp_extension:
  595                 extra_sources.append(source)
  596             else:
  597                 local_files.append(os.path.normpath(os.path.join(self.path, source)))
  598 
  599         # For any generated source, if it is coming from the shared intermediate
  600         # directory then we add a Make rule to copy them to the local intermediate
  601         # directory first. This is because the Android LOCAL_GENERATED_SOURCES
  602         # must be in the local module intermediate directory for the compile rules
  603         # to work properly. If the file has the wrong C++ extension, then we add
  604         # a rule to copy that to intermediates and use the new version.
  605         final_generated_sources = []
  606         # If a source file gets copied, we still need to add the original source
  607         # directory as header search path, for GCC searches headers in the
  608         # directory that contains the source file by default.
  609         origin_src_dirs = []
  610         for source in extra_sources:
  611             local_file = source
  612             if "$(gyp_intermediate_dir)/" not in local_file:
  613                 basename = os.path.basename(local_file)
  614                 local_file = "$(gyp_intermediate_dir)/" + basename
  615             (root, ext) = os.path.splitext(local_file)
  616             if IsCPPExtension(ext) and ext != local_cpp_extension:
  617                 local_file = root + local_cpp_extension
  618             if local_file != source:
  619                 self.WriteLn(f"{local_file}: {self.LocalPathify(source)}")
  620                 self.WriteLn("\tmkdir -p $(@D); cp $< $@")
  621                 origin_src_dirs.append(os.path.dirname(source))
  622             final_generated_sources.append(local_file)
  623 
  624         # We add back in all of the non-compilable stuff to make sure that the
  625         # make rules have dependencies on them.
  626         final_generated_sources.extend(generated_not_sources)
  627         self.WriteList(final_generated_sources, "LOCAL_GENERATED_SOURCES")
  628 
  629         origin_src_dirs = gyp.common.uniquer(origin_src_dirs)
  630         origin_src_dirs = map(Sourceify, map(self.LocalPathify, origin_src_dirs))
  631         self.WriteList(origin_src_dirs, "GYP_COPIED_SOURCE_ORIGIN_DIRS")
  632 
  633         self.WriteList(local_files, "LOCAL_SRC_FILES")
  634 
  635         # Write out the flags used to compile the source; this must be done last
  636         # so that GYP_COPIED_SOURCE_ORIGIN_DIRS can be used as an include path.
  637         self.WriteSourceFlags(spec, configs)
  638 
  639     def ComputeAndroidModule(self, spec):
  640         """Return the Android module name used for a gyp spec.
  641 
  642         We use the complete qualified target name to avoid collisions between
  643         duplicate targets in different directories. We also add a suffix to
  644         distinguish gyp-generated module names.
  645         """
  646 
  647         if int(spec.get("android_unmangled_name", 0)):
  648             assert self.type != "shared_library" or self.target.startswith("lib")
  649             return self.target
  650 
  651         if self.type == "shared_library":
  652             # For reasons of convention, the Android build system requires that all
  653             # shared library modules are named 'libfoo' when generating -l flags.
  654             prefix = "lib_"
  655         else:
  656             prefix = ""
  657 
  658         if spec["toolset"] == "host":
  659             suffix = "_$(TARGET_$(GYP_VAR_PREFIX)ARCH)_host_gyp"
  660         else:
  661             suffix = "_gyp"
  662 
  663         if self.path:
  664             middle = make.StringToMakefileVariable(f"{self.path}_{self.target}")
  665         else:
  666             middle = make.StringToMakefileVariable(self.target)
  667 
  668         return "".join([prefix, middle, suffix])
  669 
  670     def ComputeOutputParts(self, spec):
  671         """Return the 'output basename' of a gyp spec, split into filename + ext.
  672 
  673         Android libraries must be named the same thing as their module name,
  674         otherwise the linker can't find them, so product_name and so on must be
  675         ignored if we are building a library, and the "lib" prepending is
  676         not done for Android.
  677         """
  678         assert self.type != "loadable_module"  # TODO: not supported?
  679 
  680         target = spec["target_name"]
  681         target_prefix = ""
  682         target_ext = ""
  683         if self.type == "static_library":
  684             target = self.ComputeAndroidModule(spec)
  685             target_ext = ".a"
  686         elif self.type == "shared_library":
  687             target = self.ComputeAndroidModule(spec)
  688             target_ext = ".so"
  689         elif self.type == "none":
  690             target_ext = ".stamp"
  691         elif self.type != "executable":
  692             print(
  693                 "ERROR: What output file should be generated?",
  694                 "type",
  695                 self.type,
  696                 "target",
  697                 target,
  698             )
  699 
  700         if self.type != "static_library" and self.type != "shared_library":
  701             target_prefix = spec.get("product_prefix", target_prefix)
  702             target = spec.get("product_name", target)
  703             product_ext = spec.get("product_extension")
  704             if product_ext:
  705                 target_ext = "." + product_ext
  706 
  707         target_stem = target_prefix + target
  708         return (target_stem, target_ext)
  709 
  710     def ComputeOutputBasename(self, spec):
  711         """Return the 'output basename' of a gyp spec.
  712 
  713         E.g., the loadable module 'foobar' in directory 'baz' will produce
  714           'libfoobar.so'
  715         """
  716         return "".join(self.ComputeOutputParts(spec))
  717 
  718     def ComputeOutput(self, spec):
  719         """Return the 'output' (full output path) of a gyp spec.
  720 
  721         E.g., the loadable module 'foobar' in directory 'baz' will produce
  722           '$(obj)/baz/libfoobar.so'
  723         """
  724         if self.type == "executable":
  725             # We install host executables into shared_intermediate_dir so they can be
  726             # run by gyp rules that refer to PRODUCT_DIR.
  727             path = "$(gyp_shared_intermediate_dir)"
  728         elif self.type == "shared_library":
  729             if self.toolset == "host":
  730                 path = "$($(GYP_HOST_VAR_PREFIX)HOST_OUT_INTERMEDIATE_LIBRARIES)"
  731             else:
  732                 path = "$($(GYP_VAR_PREFIX)TARGET_OUT_INTERMEDIATE_LIBRARIES)"
  733         else:
  734             # Other targets just get built into their intermediate dir.
  735             if self.toolset == "host":
  736                 path = (
  737                     "$(call intermediates-dir-for,%s,%s,true,,"
  738                     "$(GYP_HOST_VAR_PREFIX))"
  739                     % (self.android_class, self.android_module)
  740                 )
  741             else:
  742                 path = "$(call intermediates-dir-for,{},{},,,$(GYP_VAR_PREFIX))".format(
  743                     self.android_class,
  744                     self.android_module,
  745                 )
  746 
  747         assert spec.get("product_dir") is None  # TODO: not supported?
  748         return os.path.join(path, self.ComputeOutputBasename(spec))
  749 
  750     def NormalizeIncludePaths(self, include_paths):
  751         """Normalize include_paths.
  752         Convert absolute paths to relative to the Android top directory.
  753 
  754         Args:
  755           include_paths: A list of unprocessed include paths.
  756         Returns:
  757           A list of normalized include paths.
  758         """
  759         normalized = []
  760         for path in include_paths:
  761             if path[0] == "/":
  762                 path = gyp.common.RelativePath(path, self.android_top_dir)
  763             normalized.append(path)
  764         return normalized
  765 
  766     def ExtractIncludesFromCFlags(self, cflags):
  767         """Extract includes "-I..." out from cflags
  768 
  769         Args:
  770           cflags: A list of compiler flags, which may be mixed with "-I.."
  771         Returns:
  772           A tuple of lists: (clean_clfags, include_paths). "-I.." is trimmed.
  773         """
  774         clean_cflags = []
  775         include_paths = []
  776         for flag in cflags:
  777             if flag.startswith("-I"):
  778                 include_paths.append(flag[2:])
  779             else:
  780                 clean_cflags.append(flag)
  781 
  782         return (clean_cflags, include_paths)
  783 
  784     def FilterLibraries(self, libraries):
  785         """Filter the 'libraries' key to separate things that shouldn't be ldflags.
  786 
  787         Library entries that look like filenames should be converted to android
  788         module names instead of being passed to the linker as flags.
  789 
  790         Args:
  791           libraries: the value of spec.get('libraries')
  792         Returns:
  793           A tuple (static_lib_modules, dynamic_lib_modules, ldflags)
  794         """
  795         static_lib_modules = []
  796         dynamic_lib_modules = []
  797         ldflags = []
  798         for libs in libraries:
  799             # Libs can have multiple words.
  800             for lib in libs.split():
  801                 # Filter the system libraries, which are added by default by the Android
  802                 # build system.
  803                 if (
  804                     lib == "-lc"
  805                     or lib == "-lstdc++"
  806                     or lib == "-lm"
  807                     or lib.endswith("libgcc.a")
  808                 ):
  809                     continue
  810                 match = re.search(r"([^/]+)\.a$", lib)
  811                 if match:
  812                     static_lib_modules.append(match.group(1))
  813                     continue
  814                 match = re.search(r"([^/]+)\.so$", lib)
  815                 if match:
  816                     dynamic_lib_modules.append(match.group(1))
  817                     continue
  818                 if lib.startswith("-l"):
  819                     ldflags.append(lib)
  820         return (static_lib_modules, dynamic_lib_modules, ldflags)
  821 
  822     def ComputeDeps(self, spec):
  823         """Compute the dependencies of a gyp spec.
  824 
  825         Returns a tuple (deps, link_deps), where each is a list of
  826         filenames that will need to be put in front of make for either
  827         building (deps) or linking (link_deps).
  828         """
  829         deps = []
  830         link_deps = []
  831         if "dependencies" in spec:
  832             deps.extend(
  833                 [
  834                     target_outputs[dep]
  835                     for dep in spec["dependencies"]
  836                     if target_outputs[dep]
  837                 ]
  838             )
  839             for dep in spec["dependencies"]:
  840                 if dep in target_link_deps:
  841                     link_deps.append(target_link_deps[dep])
  842             deps.extend(link_deps)
  843         return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps))
  844 
  845     def WriteTargetFlags(self, spec, configs, link_deps):
  846         """Write Makefile code to specify the link flags and library dependencies.
  847 
  848         spec, configs: input from gyp.
  849         link_deps: link dependency list; see ComputeDeps()
  850         """
  851         # Libraries (i.e. -lfoo)
  852         # These must be included even for static libraries as some of them provide
  853         # implicit include paths through the build system.
  854         libraries = gyp.common.uniquer(spec.get("libraries", []))
  855         static_libs, dynamic_libs, ldflags_libs = self.FilterLibraries(libraries)
  856 
  857         if self.type != "static_library":
  858             for configname, config in sorted(configs.items()):
  859                 ldflags = list(config.get("ldflags", []))
  860                 self.WriteLn("")
  861                 self.WriteList(ldflags, "LOCAL_LDFLAGS_%s" % configname)
  862             self.WriteList(ldflags_libs, "LOCAL_GYP_LIBS")
  863             self.WriteLn(
  864                 "LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION)) "
  865                 "$(LOCAL_GYP_LIBS)"
  866             )
  867 
  868         # Link dependencies (i.e. other gyp targets this target depends on)
  869         # These need not be included for static libraries as within the gyp build
  870         # we do not use the implicit include path mechanism.
  871         if self.type != "static_library":
  872             static_link_deps = [x[1] for x in link_deps if x[0] == "static"]
  873             shared_link_deps = [x[1] for x in link_deps if x[0] == "shared"]
  874         else:
  875             static_link_deps = []
  876             shared_link_deps = []
  877 
  878         # Only write the lists if they are non-empty.
  879         if static_libs or static_link_deps:
  880             self.WriteLn("")
  881             self.WriteList(static_libs + static_link_deps, "LOCAL_STATIC_LIBRARIES")
  882             self.WriteLn("# Enable grouping to fix circular references")
  883             self.WriteLn("LOCAL_GROUP_STATIC_LIBRARIES := true")
  884         if dynamic_libs or shared_link_deps:
  885             self.WriteLn("")
  886             self.WriteList(dynamic_libs + shared_link_deps, "LOCAL_SHARED_LIBRARIES")
  887 
  888     def WriteTarget(
  889         self, spec, configs, deps, link_deps, part_of_all, write_alias_target
  890     ):
  891         """Write Makefile code to produce the final target of the gyp spec.
  892 
  893         spec, configs: input from gyp.
  894         deps, link_deps: dependency lists; see ComputeDeps()
  895         part_of_all: flag indicating this target is part of 'all'
  896         write_alias_target: flag indicating whether to create short aliases for this
  897                             target
  898         """
  899         self.WriteLn("### Rules for final target.")
  900 
  901         if self.type != "none":
  902             self.WriteTargetFlags(spec, configs, link_deps)
  903 
  904         settings = spec.get("aosp_build_settings", {})
  905         if settings:
  906             self.WriteLn("### Set directly by aosp_build_settings.")
  907             for k, v in settings.items():
  908                 if isinstance(v, list):
  909                     self.WriteList(v, k)
  910                 else:
  911                     self.WriteLn(f"{k} := {make.QuoteIfNecessary(v)}")
  912             self.WriteLn("")
  913 
  914         # Add to the set of targets which represent the gyp 'all' target. We use the
  915         # name 'gyp_all_modules' as the Android build system doesn't allow the use
  916         # of the Make target 'all' and because 'all_modules' is the equivalent of
  917         # the Make target 'all' on Android.
  918         if part_of_all and write_alias_target:
  919             self.WriteLn('# Add target alias to "gyp_all_modules" target.')
  920             self.WriteLn(".PHONY: gyp_all_modules")
  921             self.WriteLn("gyp_all_modules: %s" % self.android_module)
  922             self.WriteLn("")
  923 
  924         # Add an alias from the gyp target name to the Android module name. This
  925         # simplifies manual builds of the target, and is required by the test
  926         # framework.
  927         if self.target != self.android_module and write_alias_target:
  928             self.WriteLn("# Alias gyp target name.")
  929             self.WriteLn(".PHONY: %s" % self.target)
  930             self.WriteLn(f"{self.target}: {self.android_module}")
  931             self.WriteLn("")
  932 
  933         # Add the command to trigger build of the target type depending
  934         # on the toolset. Ex: BUILD_STATIC_LIBRARY vs. BUILD_HOST_STATIC_LIBRARY
  935         # NOTE: This has to come last!
  936         modifier = ""
  937         if self.toolset == "host":
  938             modifier = "HOST_"
  939         if self.type == "static_library":
  940             self.WriteLn("include $(BUILD_%sSTATIC_LIBRARY)" % modifier)
  941         elif self.type == "shared_library":
  942             self.WriteLn("LOCAL_PRELINK_MODULE := false")
  943             self.WriteLn("include $(BUILD_%sSHARED_LIBRARY)" % modifier)
  944         elif self.type == "executable":
  945             self.WriteLn("LOCAL_CXX_STL := libc++_static")
  946             # Executables are for build and test purposes only, so they're installed
  947             # to a directory that doesn't get included in the system image.
  948             self.WriteLn("LOCAL_MODULE_PATH := $(gyp_shared_intermediate_dir)")
  949             self.WriteLn("include $(BUILD_%sEXECUTABLE)" % modifier)
  950         else:
  951             self.WriteLn("LOCAL_MODULE_PATH := $(PRODUCT_OUT)/gyp_stamp")
  952             self.WriteLn("LOCAL_UNINSTALLABLE_MODULE := true")
  953             if self.toolset == "target":
  954                 self.WriteLn("LOCAL_2ND_ARCH_VAR_PREFIX := $(GYP_VAR_PREFIX)")
  955             else:
  956                 self.WriteLn("LOCAL_2ND_ARCH_VAR_PREFIX := $(GYP_HOST_VAR_PREFIX)")
  957             self.WriteLn()
  958             self.WriteLn("include $(BUILD_SYSTEM)/base_rules.mk")
  959             self.WriteLn()
  960             self.WriteLn("$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)")
  961             self.WriteLn('\t$(hide) echo "Gyp timestamp: $@"')
  962             self.WriteLn("\t$(hide) mkdir -p $(dir $@)")
  963             self.WriteLn("\t$(hide) touch $@")
  964             self.WriteLn()
  965             self.WriteLn("LOCAL_2ND_ARCH_VAR_PREFIX :=")
  966 
  967     def WriteList(
  968         self,
  969         value_list,
  970         variable=None,
  971         prefix="",
  972         quoter=make.QuoteIfNecessary,
  973         local_pathify=False,
  974     ):
  975         """Write a variable definition that is a list of values.
  976 
  977         E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out
  978              foo = blaha blahb
  979         but in a pretty-printed style.
  980         """
  981         values = ""
  982         if value_list:
  983             value_list = [quoter(prefix + value) for value in value_list]
  984             if local_pathify:
  985                 value_list = [self.LocalPathify(value) for value in value_list]
  986             values = " \\\n\t" + " \\\n\t".join(value_list)
  987         self.fp.write(f"{variable} :={values}\n\n")
  988 
  989     def WriteLn(self, text=""):
  990         self.fp.write(text + "\n")
  991 
  992     def LocalPathify(self, path):
  993         """Convert a subdirectory-relative path into a normalized path which starts
  994         with the make variable $(LOCAL_PATH) (i.e. the top of the project tree).
  995         Absolute paths, or paths that contain variables, are just normalized."""
  996         if "$(" in path or os.path.isabs(path):
  997             # path is not a file in the project tree in this case, but calling
  998             # normpath is still important for trimming trailing slashes.
  999             return os.path.normpath(path)
 1000         local_path = os.path.join("$(LOCAL_PATH)", self.path, path)
 1001         local_path = os.path.normpath(local_path)
 1002         # Check that normalizing the path didn't ../ itself out of $(LOCAL_PATH)
 1003         # - i.e. that the resulting path is still inside the project tree. The
 1004         # path may legitimately have ended up containing just $(LOCAL_PATH), though,
 1005         # so we don't look for a slash.
 1006         assert local_path.startswith(
 1007             "$(LOCAL_PATH)"
 1008         ), f"Path {path} attempts to escape from gyp path {self.path} !)"
 1009         return local_path
 1010 
 1011     def ExpandInputRoot(self, template, expansion, dirname):
 1012         if "%(INPUT_ROOT)s" not in template and "%(INPUT_DIRNAME)s" not in template:
 1013             return template
 1014         path = template % {
 1015             "INPUT_ROOT": expansion,
 1016             "INPUT_DIRNAME": dirname,
 1017         }
 1018         return os.path.normpath(path)
 1019 
 1020 
 1021 def PerformBuild(data, configurations, params):
 1022     # The android backend only supports the default configuration.
 1023     options = params["options"]
 1024     makefile = os.path.abspath(os.path.join(options.toplevel_dir, "GypAndroid.mk"))
 1025     env = dict(os.environ)
 1026     env["ONE_SHOT_MAKEFILE"] = makefile
 1027     arguments = ["make", "-C", os.environ["ANDROID_BUILD_TOP"], "gyp_all_modules"]
 1028     print("Building: %s" % arguments)
 1029     subprocess.check_call(arguments, env=env)
 1030 
 1031 
 1032 def GenerateOutput(target_list, target_dicts, data, params):
 1033     options = params["options"]
 1034     generator_flags = params.get("generator_flags", {})
 1035     limit_to_target_all = generator_flags.get("limit_to_target_all", False)
 1036     write_alias_targets = generator_flags.get("write_alias_targets", True)
 1037     sdk_version = generator_flags.get("aosp_sdk_version", 0)
 1038     android_top_dir = os.environ.get("ANDROID_BUILD_TOP")
 1039     assert android_top_dir, "$ANDROID_BUILD_TOP not set; you need to run lunch."
 1040 
 1041     def CalculateMakefilePath(build_file, base_name):
 1042         """Determine where to write a Makefile for a given gyp file."""
 1043         # Paths in gyp files are relative to the .gyp file, but we want
 1044         # paths relative to the source root for the master makefile.  Grab
 1045         # the path of the .gyp file as the base to relativize against.
 1046         # E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp".
 1047         base_path = gyp.common.RelativePath(os.path.dirname(build_file), options.depth)
 1048         # We write the file in the base_path directory.
 1049         output_file = os.path.join(options.depth, base_path, base_name)
 1050         assert (
 1051             not options.generator_output
 1052         ), "The Android backend does not support options.generator_output."
 1053         base_path = gyp.common.RelativePath(
 1054             os.path.dirname(build_file), options.toplevel_dir
 1055         )
 1056         return base_path, output_file
 1057 
 1058     # TODO:  search for the first non-'Default' target.  This can go
 1059     # away when we add verification that all targets have the
 1060     # necessary configurations.
 1061     default_configuration = None
 1062     for target in target_list:
 1063         spec = target_dicts[target]
 1064         if spec["default_configuration"] != "Default":
 1065             default_configuration = spec["default_configuration"]
 1066             break
 1067     if not default_configuration:
 1068         default_configuration = "Default"
 1069 
 1070     makefile_name = "GypAndroid" + options.suffix + ".mk"
 1071     makefile_path = os.path.join(options.toplevel_dir, makefile_name)
 1072     assert (
 1073         not options.generator_output
 1074     ), "The Android backend does not support options.generator_output."
 1075     gyp.common.EnsureDirExists(makefile_path)
 1076     root_makefile = open(makefile_path, "w")
 1077 
 1078     root_makefile.write(header)
 1079 
 1080     # We set LOCAL_PATH just once, here, to the top of the project tree. This
 1081     # allows all the other paths we use to be relative to the Android.mk file,
 1082     # as the Android build system expects.
 1083     root_makefile.write("\nLOCAL_PATH := $(call my-dir)\n")
 1084 
 1085     # Find the list of targets that derive from the gyp file(s) being built.
 1086     needed_targets = set()
 1087     for build_file in params["build_files"]:
 1088         for target in gyp.common.AllTargets(target_list, target_dicts, build_file):
 1089             needed_targets.add(target)
 1090 
 1091     build_files = set()
 1092     include_list = set()
 1093     android_modules = {}
 1094     for qualified_target in target_list:
 1095         build_file, target, toolset = gyp.common.ParseQualifiedTarget(qualified_target)
 1096         relative_build_file = gyp.common.RelativePath(build_file, options.toplevel_dir)
 1097         build_files.add(relative_build_file)
 1098         included_files = data[build_file]["included_files"]
 1099         for included_file in included_files:
 1100             # The included_files entries are relative to the dir of the build file
 1101             # that included them, so we have to undo that and then make them relative
 1102             # to the root dir.
 1103             relative_include_file = gyp.common.RelativePath(
 1104                 gyp.common.UnrelativePath(included_file, build_file),
 1105                 options.toplevel_dir,
 1106             )
 1107             abs_include_file = os.path.abspath(relative_include_file)
 1108             # If the include file is from the ~/.gyp dir, we should use absolute path
 1109             # so that relocating the src dir doesn't break the path.
 1110             if params["home_dot_gyp"] and abs_include_file.startswith(
 1111                 params["home_dot_gyp"]
 1112             ):
 1113                 build_files.add(abs_include_file)
 1114             else:
 1115                 build_files.add(relative_include_file)
 1116 
 1117         base_path, output_file = CalculateMakefilePath(
 1118             build_file, target + "." + toolset + options.suffix + ".mk"
 1119         )
 1120 
 1121         spec = target_dicts[qualified_target]
 1122         configs = spec["configurations"]
 1123 
 1124         part_of_all = qualified_target in needed_targets
 1125         if limit_to_target_all and not part_of_all:
 1126             continue
 1127 
 1128         relative_target = gyp.common.QualifiedTarget(
 1129             relative_build_file, target, toolset
 1130         )
 1131         writer = AndroidMkWriter(android_top_dir)
 1132         android_module = writer.Write(
 1133             qualified_target,
 1134             relative_target,
 1135             base_path,
 1136             output_file,
 1137             spec,
 1138             configs,
 1139             part_of_all=part_of_all,
 1140             write_alias_target=write_alias_targets,
 1141             sdk_version=sdk_version,
 1142         )
 1143         if android_module in android_modules:
 1144             print(
 1145                 "ERROR: Android module names must be unique. The following "
 1146                 "targets both generate Android module name %s.\n  %s\n  %s"
 1147                 % (android_module, android_modules[android_module], qualified_target)
 1148             )
 1149             return
 1150         android_modules[android_module] = qualified_target
 1151 
 1152         # Our root_makefile lives at the source root.  Compute the relative path
 1153         # from there to the output_file for including.
 1154         mkfile_rel_path = gyp.common.RelativePath(
 1155             output_file, os.path.dirname(makefile_path)
 1156         )
 1157         include_list.add(mkfile_rel_path)
 1158 
 1159     root_makefile.write("GYP_CONFIGURATION ?= %s\n" % default_configuration)
 1160     root_makefile.write("GYP_VAR_PREFIX ?=\n")
 1161     root_makefile.write("GYP_HOST_VAR_PREFIX ?=\n")
 1162     root_makefile.write("GYP_HOST_MULTILIB ?= first\n")
 1163 
 1164     # Write out the sorted list of includes.
 1165     root_makefile.write("\n")
 1166     for include_file in sorted(include_list):
 1167         root_makefile.write("include $(LOCAL_PATH)/" + include_file + "\n")
 1168     root_makefile.write("\n")
 1169 
 1170     if write_alias_targets:
 1171         root_makefile.write(ALL_MODULES_FOOTER)
 1172 
 1173     root_makefile.close()