Bug 1304125 - Perform WebIDL code generation in the tup backend; r=gps
authorMike Shal <mshal@mozilla.com>
Mon, 19 Sep 2016 13:30:03 -0400
changeset 315176 f7ad627dadd2ec1c314b599309b50a64f2502b3f
parent 315175 a33dcaa0f804a2114f13aa4a77affd8bf4cff5b5
child 315177 0ddc2c7f93d59b070d6443e005760e3402cc110f
push id82104
push userihsiao@mozilla.com
push dateMon, 26 Sep 2016 11:08:56 +0000
treeherdermozilla-inbound@87aeaae19f90 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1304125
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1304125 - Perform WebIDL code generation in the tup backend; r=gps MozReview-Commit-ID: Fnw8380zyGU
python/mozbuild/mozbuild/backend/tup.py
--- a/python/mozbuild/mozbuild/backend/tup.py
+++ b/python/mozbuild/mozbuild/backend/tup.py
@@ -10,17 +10,19 @@ import mozpack.path as mozpath
 from mozbuild.base import MozbuildObject
 from mozbuild.backend.base import PartialBackend, HybridBackend
 from mozbuild.backend.recursivemake import RecursiveMakeBackend
 from mozbuild.shellutil import quote as shell_quote
 
 from .common import CommonBackend
 from ..frontend.data import (
     ContextDerived,
+    Defines,
     GeneratedFile,
+    HostDefines,
 )
 from ..util import (
     FileAvoidWrite,
 )
 
 
 class BackendTupfile(object):
     """Represents a generated Tupfile.
@@ -30,36 +32,51 @@ class BackendTupfile(object):
         self.topsrcdir = topsrcdir
         self.srcdir = srcdir
         self.objdir = objdir
         self.relobjdir = mozpath.relpath(objdir, topobjdir)
         self.environment = environment
         self.name = mozpath.join(objdir, 'Tupfile')
         self.rules_included = False
         self.shell_exported = False
+        self.defines = []
+        self.host_defines = []
 
         self.fh = FileAvoidWrite(self.name, capture_diff=True)
         self.fh.write('# THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT.\n')
         self.fh.write('\n')
 
     def write(self, buf):
         self.fh.write(buf)
 
     def include_rules(self):
         if not self.rules_included:
             self.write('include_rules\n')
             self.rules_included = True
 
-    def rule(self, cmd, inputs=None, outputs=None, display=None, extra_outputs=None):
+    def rule(self, cmd, inputs=None, outputs=None, display=None, extra_outputs=None, check_unchanged=False):
         inputs = inputs or []
         outputs = outputs or []
+        display = display or ""
         self.include_rules()
+        flags = ""
+        if check_unchanged:
+            # This flag causes tup to compare the outputs with the previous run
+            # of the command, and skip the rest of the DAG for any that are the
+            # same.
+            flags += "o"
+
+        if display:
+            caret_text = flags + ' ' + display
+        else:
+            caret_text = flags
+
         self.write(': %(inputs)s |> %(display)s%(cmd)s |> %(outputs)s%(extra_outputs)s\n' % {
             'inputs': ' '.join(inputs),
-            'display': '^ %s^ ' % display if display else '',
+            'display': '^%s^ ' % caret_text if caret_text else '',
             'cmd': ' '.join(cmd),
             'outputs': ' '.join(outputs),
             'extra_outputs': ' | ' + ' '.join(extra_outputs) if extra_outputs else '',
         })
 
     def export_shell(self):
         if not self.shell_exported:
             # These are used by mach/mixin/process.py to determine the current
@@ -146,16 +163,20 @@ class TupOnly(CommonBackend, PartialBack
                 outputs.append('%s.pp' % obj.outputs[0])
 
                 backend_file.rule(
                     display='python {script}:{method} -> [%o]'.format(script=obj.script, method=obj.method),
                     cmd=cmd,
                     inputs=full_inputs,
                     outputs=outputs,
                 )
+        elif isinstance(obj, Defines):
+            self._process_defines(backend_file, obj)
+        elif isinstance(obj, HostDefines):
+            self._process_defines(backend_file, obj, host=True)
 
         return True
 
     def consume_finished(self):
         CommonBackend.consume_finished(self)
 
         for objdir, backend_file in sorted(self._backend_files.items()):
             with self._write_file(fh=backend_file):
@@ -179,16 +200,24 @@ class TupOnly(CommonBackend, PartialBack
             fh.write('IDL_PARSER_DIR = $(topsrcdir)/xpcom/idl-parser\n')
             fh.write('IDL_PARSER_CACHE_DIR = $(MOZ_OBJ_ROOT)/xpcom/idl-parser/xpidl\n')
 
         # Run 'tup init' if necessary.
         if not os.path.exists(mozpath.join(self.environment.topsrcdir, ".tup")):
             tup = self.environment.substs.get('TUP', 'tup')
             self._cmd.run_process(cwd=self.environment.topsrcdir, log_name='tup', args=[tup, 'init'])
 
+    def _process_defines(self, backend_file, obj, host=False):
+        defines = list(obj.get_defines())
+        if defines:
+            if host:
+                backend_file.host_defines = defines
+            else:
+                backend_file.defines = defines
+
     def _handle_idl_manager(self, manager):
         backend_file = self._get_backend_file('xpcom/xpidl')
         backend_file.export_shell()
 
         for module, data in sorted(manager.modules.iteritems()):
             dest, idls = data
             cmd = [
                 '$(PYTHON_PATH)',
@@ -211,28 +240,64 @@ class TupOnly(CommonBackend, PartialBack
                     '$(MOZ_OBJ_ROOT)/xpcom/idl-parser/xpidl/xpidllex.py',
                     '$(MOZ_OBJ_ROOT)/xpcom/idl-parser/xpidl/xpidlyacc.py',
                 ],
                 display='XPIDL %s' % module,
                 cmd=cmd,
                 outputs=outputs,
             )
 
+    def _preprocess(self, backend_file, input_file):
+        cmd = self._py_action('preprocessor')
+        cmd.extend(backend_file.defines)
+        cmd.extend(['$(ACDEFINES)', '%f', '-o', '%o'])
+
+        backend_file.rule(
+            inputs=[input_file],
+            display='Preprocess %o',
+            cmd=cmd,
+            outputs=[mozpath.basename(input_file)],
+        )
+
     def _handle_ipdl_sources(self, ipdl_dir, sorted_ipdl_sources,
                              unified_ipdl_cppsrcs_mapping):
         # TODO: This isn't implemented yet in the tup backend, but it is called
         # by the CommonBackend.
         pass
 
     def _handle_webidl_build(self, bindings_dir, unified_source_mapping,
                              webidls, expected_build_output_files,
                              global_define_files):
-        # TODO: This isn't implemented yet in the tup backend, but it is called
-        # by the CommonBackend.
-        pass
+        backend_file = self._get_backend_file('dom/bindings')
+        backend_file.export_shell()
+
+        for source in sorted(webidls.all_preprocessed_sources()):
+            self._preprocess(backend_file, source)
+
+        cmd = self._py_action('webidl')
+        cmd.append(mozpath.join(self.environment.topsrcdir, 'dom', 'bindings'))
+
+        # The WebIDLCodegenManager knows all of the .cpp and .h files that will
+        # be created (expected_build_output_files), but there are a few
+        # additional files that are also created by the webidl py_action.
+        outputs = [
+            '_cache/webidlyacc.py',
+            'codegen.json',
+            'codegen.pp',
+            'parser.out',
+        ]
+        outputs.extend(expected_build_output_files)
+
+        backend_file.rule(
+            display='WebIDL code generation',
+            cmd=cmd,
+            inputs=webidls.all_non_static_basenames(),
+            outputs=outputs,
+            check_unchanged=True,
+        )
 
 
 class TupBackend(HybridBackend(TupOnly, RecursiveMakeBackend)):
     def build(self, config, output, jobs, verbose):
         status = config._run_make(directory=self.environment.topobjdir, target='tup',
                                   line_handler=output.on_line, log=False, print_directory=False,
                                   ensure_exit_code=False, num_jobs=jobs, silent=not verbose,
                                   append_env={b'NO_BUILDSTATUS_MESSAGES': b'1'})