Bug 1468547 - Build the gtest libxul in the tup backend. draft
authorChris Manchester <cmanchester@mozilla.com>
Mon, 09 Jul 2018 14:28:58 -0700
changeset 815748 51f6a7ac5075e8f7618d2d03371447a3c6235787
parent 815747 76f83aeffbb993fad2309705ee497ec5b4fcb6a1
child 815749 6f7dda6f4719ba373eb5146c76ab0ef16792d107
push id115642
push userbmo:cmanchester@mozilla.com
push dateMon, 09 Jul 2018 21:41:32 +0000
bugs1468547
milestone63.0a1
Bug 1468547 - Build the gtest libxul in the tup backend. MozReview-Commit-ID: 8EISyDauwgD
python/mozbuild/mozbuild/backend/tup.py
--- a/python/mozbuild/mozbuild/backend/tup.py
+++ b/python/mozbuild/mozbuild/backend/tup.py
@@ -84,17 +84,16 @@ class BackendTupfile(object):
         self.outputs = set()
         self.delayed_generated_files = []
         self.delayed_installed_files = []
         self.per_source_flags = defaultdict(list)
         self.local_flags = defaultdict(list)
         self.sources = defaultdict(list)
         self.host_sources = defaultdict(list)
         self.variables = {}
-        self.rust_library = None
         self.static_lib = None
         self.shared_lib = None
         self.programs = []
         self.host_programs = []
         self.host_library = None
         self.exports = set()
 
         self._default_group = default_group
@@ -257,21 +256,29 @@ class TupBackend(CommonBackend):
         self._installed_idls = '$(MOZ_OBJ_ROOT)/<installed-idls>'
         self._installed_files = '$(MOZ_OBJ_ROOT)/<installed-files>'
         self._rust_libs = '$(MOZ_OBJ_ROOT)/<rust-libs>'
         # The preprocessor including source-repo.h and buildid.h creates
         # dependencies that aren't specified by moz.build and cause errors
         # in Tup. Express these as a group dependency.
         self._early_generated_files = '$(MOZ_OBJ_ROOT)/<early-generated-files>'
 
+        self._shlibs = '$(MOZ_OBJ_ROOT)/<shlibs>'
+        self._gtests = '$(MOZ_OBJ_ROOT)/<gtest>'
+        self._default_group = '$(MOZ_OBJ_ROOT)/<default>'
+
+        # The two rust libraries in the tree share many prerequisites, so we need
+        # to prune common dependencies and therefore build all rust from the same
+        # Tupfile.
+        self._rust_outputs = set()
+        self._rust_backend_file = self._get_backend_file('toolkit/library/rust')
+
         self._built_in_addons = set()
         self._built_in_addons_file = 'dist/bin/browser/chrome/browser/content/browser/built_in_addons.json'
 
-        self._shlibs = '$(MOZ_OBJ_ROOT)/<shlibs>'
-        self._default_group = '$(MOZ_OBJ_ROOT)/<default>'
 
     def _get_mozconfig_env(self, config):
         env = {}
         loader = MozconfigLoader(config.topsrcdir)
         mozconfig = loader.read_mozconfig(config.substs['MOZCONFIG'])
         make_extra = mozconfig['make_extra'] or []
         env = {}
         for line in make_extra:
@@ -327,18 +334,19 @@ class TupBackend(CommonBackend):
 
     def _lib_paths(self, objdir, libs):
         return [mozpath.relpath(mozpath.join(l.objdir, l.import_name), objdir)
                 for l in libs]
 
     def _gen_shared_library(self, backend_file):
         shlib = backend_file.shared_lib
 
-        if backend_file.objdir.endswith('gtest') and shlib.name == 'libxul.so':
-            return
+        output_group = self._shlibs
+        if 'toolkit/library/gtest' in backend_file.objdir:
+            output_group = self._gtests
 
         if shlib.cxx_link:
             mkshlib = (
                 [backend_file.environment.substs['CXX']] +
                 backend_file.local_flags['CXX_LDFLAGS']
             )
         else:
             mkshlib = (
@@ -387,25 +395,25 @@ class TupBackend(CommonBackend):
             [backend_file.environment.substs['OS_LIBS']] +
             os_libs
         )
         backend_file.rule(
             cmd=cmd,
             inputs=inputs,
             extra_inputs=extra_inputs,
             outputs=[shlib.lib_name],
-            output_group=self._shlibs,
+            output_group=output_group,
             display='LINK %o'
         )
         backend_file.symlink_rule(mozpath.join(backend_file.objdir,
                                                shlib.lib_name),
                                   output=mozpath.join(self.environment.topobjdir,
                                                       shlib.install_target,
                                                       shlib.lib_name),
-                                  output_group=self._shlibs)
+                                  output_group=output_group)
 
     def _gen_programs(self, backend_file):
         for p in backend_file.programs:
             self._gen_program(backend_file, p)
 
     def _gen_program(self, backend_file, prog):
         cc_or_cxx = 'CXX' if prog.cxx_link else 'CC'
         objs, _, shared_libs, os_libs, static_libs = self._expand_libs(prog)
@@ -580,17 +588,17 @@ class TupBackend(CommonBackend):
             self._process_computed_flags(obj, backend_file)
         elif isinstance(obj, (Sources, GeneratedSources)):
             backend_file.sources[obj.canonical_suffix].extend(obj.files)
         elif isinstance(obj, HostSources):
             backend_file.host_sources[obj.canonical_suffix].extend(obj.files)
         elif isinstance(obj, VariablePassthru):
             backend_file.variables = obj.variables
         elif isinstance(obj, RustLibrary):
-            backend_file.rust_library = obj
+            self._gen_rust_rules(obj, backend_file)
         elif isinstance(obj, StaticLibrary):
             backend_file.static_lib = obj
         elif isinstance(obj, SharedLibrary):
             backend_file.shared_lib = obj
         elif isinstance(obj, (HostProgram, HostSimpleProgram)):
             backend_file.host_programs.append(obj)
         elif isinstance(obj, HostLibrary):
             backend_file.host_library = obj
@@ -618,18 +626,17 @@ class TupBackend(CommonBackend):
 
         for objdir, backend_file in sorted(self._backend_files.items()):
             backend_file.gen_sources_rules([self._installed_files])
             for var, gen_method in ((backend_file.shared_lib, self._gen_shared_library),
                                     (backend_file.static_lib and backend_file.static_lib.no_expand_lib,
                                      self._gen_static_library),
                                     (backend_file.programs, self._gen_programs),
                                     (backend_file.host_programs, self._gen_host_programs),
-                                    (backend_file.host_library, self._gen_host_library),
-                                    (backend_file.rust_library, self._gen_rust)):
+                                    (backend_file.host_library, self._gen_host_library)):
                 if var:
                     backend_file.export_shell()
                     gen_method(backend_file)
             for obj in backend_file.delayed_generated_files:
                 self._process_generated_file(backend_file, obj)
             for path, output, output_group in backend_file.delayed_installed_files:
                 backend_file.symlink_rule(path, output=output, output_group=output_group)
             with self._write_file(fh=backend_file):
@@ -674,18 +681,17 @@ class TupBackend(CommonBackend):
             '--target=%s' % self.environment.substs['RUST_TARGET'],
         ]
         if obj.features:
             cargo_flags += [
                 '--features', ' '.join(obj.features)
             ]
         return cargo_flags
 
-    def _get_cargo_env(self, backend_file):
-        lib = backend_file.rust_library
+    def _get_cargo_env(self, lib, backend_file):
         env = {
             'CARGO_TARGET_DIR': mozpath.normpath(mozpath.join(lib.objdir,
                                                               lib.target_dir)),
             'RUSTC': self.environment.substs['RUSTC'],
             'MOZ_SRC': self.environment.topsrcdir,
             'MOZ_DIST': self.environment.substs['DIST'],
             'LIBCLANG_PATH': self.environment.substs['MOZ_LIBCLANG_PATH'],
             'CLANG_PATH': self.environment.substs['MOZ_CLANG_PATH'],
@@ -785,41 +791,40 @@ class TupBackend(CommonBackend):
                 header = 'RUSTC'
             else:
                 inputs.add(invocation['program'])
                 header = 'RUN'
 
             invocation['full-deps'] = set(inputs)
             invocation['full-deps'].update(invocation['outputs'])
 
-            backend_file.rule(
-                command,
-                inputs=sorted(inputs),
-                outputs=outputs,
-                output_group=self._rust_libs,
-                extra_inputs=[self._installed_files],
-                display='%s %s' % (header, display_name(invocation)),
-            )
+            output_key = tuple(outputs)
+            if output_key not in self._rust_outputs:
+                self._rust_outputs.add(output_key)
+                self._rust_backend_file.rule(
+                    command,
+                    inputs=sorted(inputs),
+                    outputs=outputs,
+                    output_group=self._rust_libs,
+                    extra_inputs=[self._installed_files],
+                    display='%s %s' % (header, display_name(invocation)),
+                )
 
-            for dst, link in invocation['links'].iteritems():
-                backend_file.symlink_rule(link, dst, self._rust_libs)
+                for dst, link in invocation['links'].iteritems():
+                    self._rust_outputs.add(output_key)
+                    self._rust_backend_file.symlink_rule(link, dst,
+                                                         self._rust_libs)
 
         for val in enumerate(invocations):
             _process(*val)
 
 
-    def _gen_rust(self, backend_file):
-        # TODO (bug 1468547): The gtest rust library depends on many of the same
-        # libraries as the main rust library, so we'll need to handle these all
-        # at once in order to build the gtest rust library.
-        if 'toolkit/library/gtest' in backend_file.objdir:
-            return
-
-        cargo_flags = self._get_cargo_flags(backend_file.rust_library)
-        cargo_env = self._get_cargo_env(backend_file)
+    def _gen_rust_rules(self, obj, backend_file):
+        cargo_flags = self._get_cargo_flags(obj)
+        cargo_env = self._get_cargo_env(obj, backend_file)
 
         output_lines = []
         def accumulate_output(line):
             output_lines.append(line)
 
         cargo_status = self._cmd.run_process(
             [self.environment.substs['CARGO'], 'build'] + cargo_flags,
             line_handler=accumulate_output,