# 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 # later. See https://bugzilla.mozilla.org/show_bug.cgi?id=1645986#c0 as # 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,{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")