Source code

Revision control

Copy as Markdown

Other Tools

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import mozpack.path as mozpath
from mozbuild.frontend.data import GeneratedFile
from mozbuild.shellutil import quote as shell_quote
from .common import CommonBackend
class MakeBackend(CommonBackend):
"""Class encapsulating logic for backends that use Make."""
def _init(self):
CommonBackend._init(self)
def _format_statements_for_generated_file(self, obj, tier, extra_dependencies=""):
"""Return the list of statements to write to the Makefile for this
GeneratedFile.
This function will invoke _format_generated_file_input_name and
_format_generated_file_output_name to munge the input/output filenames
before sending them to the output.
"""
assert isinstance(obj, GeneratedFile)
# Localized generated files can use {AB_CD} and {AB_rCD} in their
# output paths.
if obj.localized:
substs = {"AB_CD": "$(AB_CD)", "AB_rCD": "$(AB_rCD)"}
else:
substs = {}
outputs = []
needs_AB_rCD = False
for o in obj.outputs:
needs_AB_rCD = needs_AB_rCD or ("AB_rCD" in o)
try:
outputs.append(
self._format_generated_file_output_name(o.format(**substs), obj)
)
except KeyError as e:
raise ValueError(
"%s not in %s is not a valid substitution in %s"
% (e.args[0], ", ".join(sorted(substs.keys())), o)
)
first_output = outputs[0]
dep_file = mozpath.join(
mozpath.dirname(first_output),
"$(MDDEPDIR)",
"%s.pp" % mozpath.basename(first_output),
)
# The stub target file needs to go in MDDEPDIR so that it doesn't
# get written into generated Android resource directories, breaking
# Gradle tooling and/or polluting the Android packages.
stub_file = mozpath.join(
mozpath.dirname(first_output),
"$(MDDEPDIR)",
"%s.stub" % mozpath.basename(first_output),
)
if obj.inputs:
inputs = [
self._format_generated_file_input_name(f, obj) for f in obj.inputs
]
else:
inputs = []
force = ""
if obj.force:
force = " FORCE"
elif obj.localized:
force = " $(if $(IS_LANGUAGE_REPACK),FORCE)"
ret = []
if obj.script:
# If we are doing an artifact build, we don't run compiler, so
# we can skip generated files that are needed during compile,
# or let the rule run as the result of something depending on
# it.
if (
not (obj.required_before_compile or obj.required_during_compile)
or not self.environment.is_artifact_build
):
if tier and not needs_AB_rCD:
# Android localized resources have special Makefile
# handling.
# Double-colon tiers via a variable that the backend adds as a dependency
# to why.
if tier in ("export", "pre-compile", "libs", "misc"):
dep = "%s_TARGETS" % tier.replace("-", "_").upper()
ret.append("%s += %s" % (dep, stub_file))
else:
ret.append("%s: %s" % (tier, stub_file))
for output in outputs:
ret.append("%s: %s ;" % (output, stub_file))
ret.append("EXTRA_MDDEPEND_FILES += %s" % dep_file)
ret.append(
(
"""{stub}: {script}{inputs}{backend}{force}
\t$(REPORT_BUILD)
\t$(call py_action,file_generate {output},{locale}{script} """ # wrap for E501
"""{method} {output} {dep_file} {stub}{inputs}{flags})
\t@$(TOUCH) $@
"""
).format(
stub=stub_file,
output=first_output,
dep_file=dep_file,
inputs=" " + " ".join(inputs) if inputs else "",
flags=" " + " ".join(shell_quote(f) for f in obj.flags)
if obj.flags
else "",
backend=" " + extra_dependencies if extra_dependencies else "",
# Locale repacks repack multiple locales from a single configured objdir,
# so standard mtime dependencies won't work properly when the build is re-run
# with a different locale as input. IS_LANGUAGE_REPACK will reliably be set
# in this situation, so simply force the generation to run in that case.
force=force,
locale="--locale=$(AB_CD) " if obj.localized else "",
script=obj.script,
method=obj.method,
)
)
return ret
def _format_generated_file_input_name(self, path, obj):
raise NotImplementedError("Subclass must implement")
def _format_generated_file_output_name(self, path, obj):
raise NotImplementedError("Subclass must implement")