Bug 1302704 - part 3 - propagate information about CARGO_TARGET_DIR from the frontend into the backend; r=chmanchester
authorNathan Froyd <froydnj@mozilla.com>
Thu, 23 Feb 2017 10:35:07 -0500
changeset 344596 3c3ffbed3a4b22e613f0912c2ecb0378e7f8a35e
parent 344595 17b7f6a479363762110c33625771be609be00990
child 344597 95b0a622699271828ef3bcb644837be4a5bf0d7d
push id31414
push usercbook@mozilla.com
push dateFri, 24 Feb 2017 10:47:41 +0000
treeherdermozilla-central@be661bae6cb9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerschmanchester
bugs1302704
milestone54.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 1302704 - part 3 - propagate information about CARGO_TARGET_DIR from the frontend into the backend; r=chmanchester Rust libraries can set RUST_LIBRARY_TARGET_DIR so that they can share compilation artifacts with other libraries. This setting needs to be propagated to the backend so it can be communicated to Cargo.
build/templates.mozbuild
python/mozbuild/mozbuild/backend/recursivemake.py
python/mozbuild/mozbuild/frontend/context.py
python/mozbuild/mozbuild/frontend/data.py
python/mozbuild/mozbuild/frontend/emitter.py
python/mozbuild/mozbuild/test/backend/test_recursivemake.py
--- a/build/templates.mozbuild
+++ b/build/templates.mozbuild
@@ -56,25 +56,28 @@ def CppUnitTests(names, ext='.cpp'):
 
 @template
 def Library(name):
     '''Template for libraries.'''
     LIBRARY_NAME = name
 
 
 @template
-def RustLibrary(name, features=None):
+def RustLibrary(name, features=None, target_dir=None):
     '''Template for Rust libraries.'''
     Library(name)
 
     IS_RUST_LIBRARY = True
 
     if features:
         RUST_LIBRARY_FEATURES = features
 
+    if target_dir:
+        RUST_LIBRARY_TARGET_DIR = target_dir
+
 
 @template
 def SharedLibrary(name):
     '''Template for shared libraries.'''
     Library(name)
 
     FORCE_SHARED_LIB = True
 
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -1246,17 +1246,23 @@ class RecursiveMakeBackend(CommonBackend
     def _process_rust_library(self, libdef, backend_file):
         lib_var = 'RUST_LIBRARY_FILE'
         feature_var = 'RUST_LIBRARY_FEATURES'
         if isinstance(libdef, HostRustLibrary):
             lib_var = 'HOST_RUST_LIBRARY_FILE'
             feature_var = 'HOST_RUST_LIBRARY_FEATURES'
         backend_file.write_once('%s := %s\n' % (libdef.LIB_FILE_VAR, libdef.import_name))
         backend_file.write('CARGO_FILE := $(srcdir)/Cargo.toml\n')
-        backend_file.write('CARGO_TARGET_DIR := .\n')
+        # Need to normalize the path so Cargo sees the same paths from all
+        # possible invocations of Cargo with this CARGO_TARGET_DIR.  Otherwise,
+        # Cargo's dependency calculations don't work as we expect and we wind
+        # up recompiling lots of things.
+        target_dir = mozpath.join(backend_file.objdir, libdef.target_dir)
+        target_dir = mozpath.normpath(target_dir)
+        backend_file.write('CARGO_TARGET_DIR := %s\n' % target_dir)
         if libdef.features:
             backend_file.write('%s := %s\n' % (libdef.FEATURES_VAR, ' '.join(libdef.features)))
 
     def _process_host_library(self, libdef, backend_file):
         backend_file.write('HOST_LIBRARY_NAME = %s\n' % libdef.basename)
 
     def _build_target_for_obj(self, obj):
         return '%s/%s' % (mozpath.relpath(obj.objdir,
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -954,16 +954,25 @@ VARIABLES = {
 
     'RUST_LIBRARY_FEATURES': (List, list,
         """Cargo features to activate for this library.
 
         This variable should not be used directly; you should be using the
         RustLibrary template instead.
         """),
 
+    'RUST_LIBRARY_TARGET_DIR': (unicode, unicode,
+        """Where CARGO_TARGET_DIR should point when compiling this library.  If
+        not set, it defaults to the current objdir.  It should be a relative path
+        to the current objdir; absolute paths should not be used.
+
+        This variable should not be used directly; you should be using the
+        RustLibrary template instead.
+        """),
+
     'HOST_RUST_LIBRARY_FEATURES': (List, list,
         """Cargo features to activate for this host library.
 
         This variable should not be used directly; you should be using the
         HostRustLibrary template instead.
         """),
 
     'UNIFIED_SOURCES': (ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList), list,
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -518,39 +518,42 @@ class StaticLibrary(Library):
 class RustLibrary(StaticLibrary):
     """Context derived container object for a static library"""
     __slots__ = (
         'cargo_file',
         'crate_type',
         'dependencies',
         'deps_path',
         'features',
+        'target_dir',
     )
     TARGET_SUBST_VAR = 'RUST_TARGET'
     FEATURES_VAR = 'RUST_LIBRARY_FEATURES'
     LIB_FILE_VAR = 'RUST_LIBRARY_FILE'
 
     def __init__(self, context, basename, cargo_file, crate_type, dependencies,
-                 features, **args):
+                 features, target_dir, **args):
         StaticLibrary.__init__(self, context, basename, **args)
         self.cargo_file = cargo_file
         self.crate_type = crate_type
         # We need to adjust our naming here because cargo replaces '-' in
         # package names defined in Cargo.toml with underscores in actual
         # filenames. But we need to keep the basename consistent because
         # many other things in the build system depend on that.
         assert self.crate_type == 'staticlib'
         self.lib_name = '%s%s%s' % (context.config.lib_prefix,
                                      basename.replace('-', '_'),
                                      context.config.lib_suffix)
         self.dependencies = dependencies
-        build_dir = cargo_output_directory(context, self.TARGET_SUBST_VAR)
+        build_dir = mozpath.join(target_dir,
+                                 cargo_output_directory(context, self.TARGET_SUBST_VAR))
         self.import_name = mozpath.join(build_dir, self.lib_name)
         self.deps_path = mozpath.join(build_dir, 'deps')
         self.features = features
+        self.target_dir = target_dir
 
 
 class SharedLibrary(Library):
     """Context derived container object for a shared library"""
     __slots__ = (
         'soname',
         'variant',
         'symbols_file',
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -460,27 +460,29 @@ class TreeMetadataEmitter(LoggingMixin):
 
             panic = profile.get('panic', None)
             if panic != 'abort':
                 raise SandboxValidationError(
                     ('Cargo.toml for %s does not specify `panic = "abort"`'
                      ' in [profile.%s] section') % (libname, profile_name),
                     context)
 
+        cargo_target_dir = context.get('RUST_LIBRARY_TARGET_DIR', '.')
+
         dependencies = set(config.get('dependencies', {}).iterkeys())
 
         features = context.get(cls.FEATURES_VAR, [])
         unique_features = set(features)
         if len(features) != len(unique_features):
             raise SandboxValidationError(
                 'features for %s should not contain duplicates: %s' % (libname, features),
                 context)
 
         return cls(context, libname, cargo_file, crate_type, dependencies,
-                   features, **static_args)
+                   features, cargo_target_dir, **static_args)
 
 
     def _handle_linkables(self, context, passthru, generated_files):
         linkables = []
         host_linkables = []
         def add_program(prog, var):
             if var.startswith('HOST_'):
                 host_linkables.append(prog)
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -759,63 +759,63 @@ class TestRecursiveMakeBackend(BackendTe
         env = self._consume('rust-library', RecursiveMakeBackend)
 
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
         lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
 
         expected = [
             'RUST_LIBRARY_FILE := x86_64-unknown-linux-gnu/release/libgkrust.a',
             'CARGO_FILE := $(srcdir)/Cargo.toml',
-            'CARGO_TARGET_DIR := .',
+            'CARGO_TARGET_DIR := %s' % env.topobjdir,
         ]
 
         self.assertEqual(lines, expected)
 
     def test_host_rust_library(self):
         """Test that a Rust library is written to backend.mk correctly."""
         env = self._consume('host-rust-library', RecursiveMakeBackend)
 
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
         lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
 
         expected = [
             'HOST_RUST_LIBRARY_FILE := x86_64-unknown-linux-gnu/release/libhostrusttool.a',
             'CARGO_FILE := $(srcdir)/Cargo.toml',
-            'CARGO_TARGET_DIR := .',
+            'CARGO_TARGET_DIR := %s' % env.topobjdir,
         ]
 
         self.assertEqual(lines, expected)
 
     def test_host_rust_library_with_features(self):
         """Test that a host Rust library with features is written to backend.mk correctly."""
         env = self._consume('host-rust-library-features', RecursiveMakeBackend)
 
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
         lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
 
         expected = [
             'HOST_RUST_LIBRARY_FILE := x86_64-unknown-linux-gnu/release/libhostrusttool.a',
             'CARGO_FILE := $(srcdir)/Cargo.toml',
-            'CARGO_TARGET_DIR := .',
+            'CARGO_TARGET_DIR := %s' % env.topobjdir,
             'HOST_RUST_LIBRARY_FEATURES := musthave cantlivewithout',
         ]
 
         self.assertEqual(lines, expected)
 
     def test_rust_library_with_features(self):
         """Test that a Rust library with features is written to backend.mk correctly."""
         env = self._consume('rust-library-features', RecursiveMakeBackend)
 
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
         lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
 
         expected = [
             'RUST_LIBRARY_FILE := x86_64-unknown-linux-gnu/release/libgkrust.a',
             'CARGO_FILE := $(srcdir)/Cargo.toml',
-            'CARGO_TARGET_DIR := .',
+            'CARGO_TARGET_DIR := %s' % env.topobjdir,
             'RUST_LIBRARY_FEATURES := musthave cantlivewithout',
         ]
 
         self.assertEqual(lines, expected)
 
     def test_rust_programs(self):
         """Test that {HOST_,}RUST_PROGRAMS are written to backend.mk correctly."""
         env = self._consume('rust-programs', RecursiveMakeBackend)