rust: Add libstd linkage mutator for rlibs.

The current state of linkage is that device targets always link
libstd dynamically except for rust_ffi_static which requires a static
libstd linkage. However this prevents producing rust_ffi_static
modules which depend on other Rust libraries as those dependencies
will link libstd dynamically and cause a collision. We also want our
rust_test modules to statically link in libstd as well.

This adds a linkage mutator for rlibs that creates a variant for each
libstd linkage. Dependent modules can then select the variant that
matches their linkage of libstd.

Also fixes an issue where installation paths were being generated for
rlibs and static libs even though they weren't being installed. This broke
when adding the linkage mutator as Make would complain about multiple
targets producing the same output.

Bug: 168729404
Test: rust_ffi_static module with other rustlib dependency can be built.
Change-Id: I955b484bf5809e8fc5517750c7f8df82d3ca8895
diff --git a/rust/androidmk.go b/rust/androidmk.go
index edae0e6..5a33f77 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -178,6 +178,10 @@
 }
 
 func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	if compiler.path == (android.InstallPath{}) {
+		return
+	}
+
 	var unstrippedOutputFile android.OptionalPath
 	// Soong installation is only supported for host modules. Have Make
 	// installation trigger Soong installation.
diff --git a/rust/binary_test.go b/rust/binary_test.go
index cfef57a..394abfc 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -40,7 +40,7 @@
 	fizzBuzzHost := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
 	fizzBuzzDevice := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module)
 
-	if !android.InList("libfoo", fizzBuzzHost.Properties.AndroidMkRlibs) {
+	if !android.InList("libfoo.rlib-std", fizzBuzzHost.Properties.AndroidMkRlibs) {
 		t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules")
 	}
 
diff --git a/rust/compiler.go b/rust/compiler.go
index 664578d..aeb904b 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -146,8 +146,13 @@
 	panic("baseCompiler does not implement coverageOutputZipPath()")
 }
 
-func (compiler *baseCompiler) static() bool {
-	return false
+func (compiler *baseCompiler) staticStd(ctx *depsContext) bool {
+	// For devices, we always link stdlibs in as dylibs by default.
+	if ctx.Device() {
+		return false
+	} else {
+		return true
+	}
 }
 
 var _ compiler = (*baseCompiler)(nil)
@@ -221,15 +226,7 @@
 				stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
 			}
 
-			// For devices, we always link stdlibs in as dylibs except for ffi static libraries.
-			// (rustc does not support linking libstd as a dylib for ffi static libraries)
-			if ctx.Host() {
-				deps.Rustlibs = append(deps.Rustlibs, stdlib)
-			} else if ctx.RustModule().compiler.static() {
-				deps.Rlibs = append(deps.Rlibs, stdlib)
-			} else {
-				deps.Dylibs = append(deps.Dylibs, stdlib)
-			}
+			deps.Stdlibs = append(deps.Stdlibs, stdlib)
 		}
 	}
 	return deps
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index 56a8ef8..a25523c 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -191,7 +191,7 @@
 			crate_name: "foo",
 		}`)
 	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
-	fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Module().(*Module)
+	fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module)
 	fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
 
 	if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) {
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index 73673d0..90155ca 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -154,12 +154,12 @@
 	}
 
 	// Make sure the expected inputs are provided to the zip rule.
-	if !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_rlib_cov/librlib.gcno") ||
+	if !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_rlib_dylib-std_cov/librlib.gcno") ||
 		!android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_static_cov/libbaz.gcno") ||
 		!android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_cov/fizz.gcno") {
 		t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", fizzZipInputs)
 	}
-	if !android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_rlib_cov/librlib.gcno") ||
+	if !android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_rlib_dylib-std_cov/librlib.gcno") ||
 		!android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_dylib_cov/libfoo.dylib.gcno") {
 		t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", libfooZipInputs)
 	}
diff --git a/rust/library.go b/rust/library.go
index a442933..4931f19 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -21,6 +21,11 @@
 	"android/soong/android"
 )
 
+var (
+	DylibStdlibSuffix = ".dylib-std"
+	RlibStdlibSuffix  = ".rlib-std"
+)
+
 func init() {
 	android.RegisterModuleType("rust_library", RustLibraryFactory)
 	android.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory)
@@ -49,6 +54,9 @@
 
 	// path to include directories to pass to cc_* modules, only relevant for static/shared variants.
 	Include_dirs []string `android:"path,arch_variant"`
+
+	// Whether this library is part of the Rust toolchain sysroot.
+	Sysroot *bool
 }
 
 type LibraryMutatedProperties struct {
@@ -73,6 +81,9 @@
 	// This variant is disabled and should not be compiled
 	// (used for SourceProvider variants that produce only source)
 	VariantIsDisabled bool `blueprint:"mutated"`
+
+	// Whether this library variant should be link libstd via rlibs
+	VariantIsStaticStd bool `blueprint:"mutated"`
 }
 
 type libraryDecorator struct {
@@ -91,6 +102,7 @@
 	dylib() bool
 	static() bool
 	shared() bool
+	sysroot() bool
 
 	// Returns true if the build options for the module have selected a particular build type
 	buildRlib() bool
@@ -104,6 +116,10 @@
 	setShared()
 	setStatic()
 
+	// Set libstd linkage
+	setRlibStd()
+	setDylibStd()
+
 	// Build a specific library variant
 	BuildOnlyFFI()
 	BuildOnlyRust()
@@ -121,6 +137,10 @@
 	return library.MutatedProperties.VariantIsRlib
 }
 
+func (library *libraryDecorator) sysroot() bool {
+	return Bool(library.Properties.Sysroot)
+}
+
 func (library *libraryDecorator) dylib() bool {
 	return library.MutatedProperties.VariantIsDylib
 }
@@ -133,6 +153,11 @@
 	return library.MutatedProperties.VariantIsStatic
 }
 
+func (library *libraryDecorator) staticStd(ctx *depsContext) bool {
+	// libraries should only request the staticStd when building a static FFI or when variant is staticStd
+	return library.static() || library.MutatedProperties.VariantIsStaticStd
+}
+
 func (library *libraryDecorator) buildRlib() bool {
 	return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
 }
@@ -163,6 +188,14 @@
 	library.MutatedProperties.VariantIsShared = false
 }
 
+func (library *libraryDecorator) setRlibStd() {
+	library.MutatedProperties.VariantIsStaticStd = true
+}
+
+func (library *libraryDecorator) setDylibStd() {
+	library.MutatedProperties.VariantIsStaticStd = false
+}
+
 func (library *libraryDecorator) setShared() {
 	library.MutatedProperties.VariantIsStatic = false
 	library.MutatedProperties.VariantIsShared = true
@@ -450,6 +483,13 @@
 	return stem + String(library.baseCompiler.Properties.Suffix)
 }
 
+func (library *libraryDecorator) install(ctx ModuleContext) {
+	// Only shared and dylib variants make sense to install.
+	if library.shared() || library.dylib() {
+		library.baseCompiler.install(ctx)
+	}
+}
+
 func (library *libraryDecorator) Disabled() bool {
 	return library.MutatedProperties.VariantIsDisabled
 }
@@ -493,7 +533,6 @@
 				dylib := modules[1].(*Module)
 				rlib.compiler.(libraryInterface).setRlib()
 				dylib.compiler.(libraryInterface).setDylib()
-
 				if m.sourceProvider != nil {
 					// This library is SourceProvider generated, so the non-library-producing
 					// variant needs to disable it's compiler and skip installation.
@@ -515,3 +554,23 @@
 		}
 	}
 }
+
+func LibstdMutator(mctx android.BottomUpMutatorContext) {
+	if m, ok := mctx.Module().(*Module); ok && m.compiler != nil && !m.compiler.Disabled() {
+		switch library := m.compiler.(type) {
+		case libraryInterface:
+			// Only create a variant if a library is actually being built.
+			if library.rlib() && !library.sysroot() {
+				variants := []string{"rlib-std", "dylib-std"}
+				modules := mctx.CreateLocalVariations(variants...)
+
+				rlib := modules[0].(*Module)
+				dylib := modules[1].(*Module)
+				rlib.compiler.(libraryInterface).setRlibStd()
+				dylib.compiler.(libraryInterface).setDylibStd()
+				rlib.Properties.SubName += RlibStdlibSuffix
+				dylib.Properties.SubName += DylibStdlibSuffix
+			}
+		}
+	}
+}
diff --git a/rust/library_test.go b/rust/library_test.go
index f1bc050..fec3992 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -37,7 +37,7 @@
                 }`)
 
 	// Test all variants are being built.
-	libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib").Output("libfoo.rlib")
+	libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Output("libfoo.rlib")
 	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
 	libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Output("libfoo.ffi.a")
 	libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Output("libfoo.ffi.so")
@@ -182,14 +182,14 @@
                         rustlibs: ["libbar"],
                 }`)
 
-	libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib")
+	libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std")
 	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib")
 	libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static")
 	libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared")
 
 	for _, static := range []android.TestingModule{libfooRlib, libfooStatic} {
-		if !android.InList("libbar", static.Module().(*Module).Properties.AndroidMkRlibs) {
-			t.Errorf("libbar not present as static dependency in static lib")
+		if !android.InList("libbar.rlib-std", static.Module().(*Module).Properties.AndroidMkRlibs) {
+			t.Errorf("libbar not present as rlib dependency in static lib")
 		}
 		if android.InList("libbar", static.Module().(*Module).Properties.AndroidMkDylibs) {
 			t.Errorf("libbar present as dynamic dependency in static lib")
@@ -200,8 +200,8 @@
 		if !android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkDylibs) {
 			t.Errorf("libbar not present as dynamic dependency in dynamic lib")
 		}
-		if android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
-			t.Errorf("libbar present as static dependency in dynamic lib")
+		if android.InList("libbar.dylib-std", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
+			t.Errorf("libbar present as rlib dependency in dynamic lib")
 		}
 
 	}
@@ -238,3 +238,45 @@
 		t.Errorf("stripped version of bar has been generated")
 	}
 }
+
+func TestLibstdLinkage(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+		}
+		rust_ffi {
+			name: "libbar",
+			srcs: ["foo.rs"],
+			crate_name: "bar",
+			rustlibs: ["libfoo"],
+		}`)
+
+	libfooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
+	libfooRlibStatic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module)
+	libfooRlibDynamic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module)
+
+	libbarShared := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module().(*Module)
+	libbarStatic := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module().(*Module)
+
+	if !android.InList("libstd", libfooRlibStatic.Properties.AndroidMkRlibs) {
+		t.Errorf("rlib-std variant for device rust_library_rlib does not link libstd as an rlib")
+	}
+	if !android.InList("libstd", libfooRlibDynamic.Properties.AndroidMkDylibs) {
+		t.Errorf("dylib-std variant for device rust_library_rlib does not link libstd as an dylib")
+	}
+	if !android.InList("libstd", libfooDylib.Properties.AndroidMkDylibs) {
+		t.Errorf("Device rust_library_dylib does not link libstd as an dylib")
+	}
+
+	if !android.InList("libstd", libbarShared.Properties.AndroidMkDylibs) {
+		t.Errorf("Device rust_ffi_shared does not link libstd as an dylib")
+	}
+	if !android.InList("libstd", libbarStatic.Properties.AndroidMkRlibs) {
+		t.Errorf("Device rust_ffi_static does not link libstd as an rlib")
+	}
+	if !android.InList("libfoo.rlib-std", libbarStatic.Properties.AndroidMkRlibs) {
+		t.Errorf("Device rust_ffi_static does not link dependent rustlib rlib-std variant")
+	}
+}
diff --git a/rust/rust.go b/rust/rust.go
index b98992c..e561477 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -40,6 +40,7 @@
 	android.RegisterModuleType("rust_defaults", defaultsFactory)
 	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
+		ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel()
 		ctx.BottomUp("rust_begin", BeginMutator).Parallel()
 	})
 	pctx.Import("android/soong/rust/config")
@@ -237,6 +238,7 @@
 	Dylibs     []string
 	Rlibs      []string
 	Rustlibs   []string
+	Stdlibs    []string
 	ProcMacros []string
 	SharedLibs []string
 	StaticLibs []string
@@ -293,7 +295,7 @@
 	Disabled() bool
 	SetDisabled()
 
-	static() bool
+	staticStd(ctx *depsContext) bool
 }
 
 type exportedFlagsProducer interface {
@@ -782,14 +784,15 @@
 				directDylibDeps = append(directDylibDeps, rustDep)
 				mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, depName)
 			case rlibDepTag:
+
 				rlib, ok := rustDep.compiler.(libraryInterface)
 				if !ok || !rlib.rlib() {
-					ctx.ModuleErrorf("mod %q not an rlib library", depName)
+					ctx.ModuleErrorf("mod %q not an rlib library", depName+rustDep.Properties.SubName)
 					return
 				}
 				depPaths.coverageFiles = append(depPaths.coverageFiles, rustDep.CoverageFiles()...)
 				directRlibDeps = append(directRlibDeps, rustDep)
-				mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName)
+				mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName+rustDep.Properties.SubName)
 			case procMacroDepTag:
 				directProcMacroDeps = append(directProcMacroDeps, rustDep)
 				mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName)
@@ -976,8 +979,19 @@
 		commonDepVariations = append(commonDepVariations,
 			blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
 	}
+	stdLinkage := "dylib-std"
+	if mod.compiler.staticStd(ctx) {
+		stdLinkage = "rlib-std"
+	}
+
+	rlibDepVariations := commonDepVariations
+	if lib, ok := mod.compiler.(libraryInterface); !ok || !lib.sysroot() {
+		rlibDepVariations = append(rlibDepVariations,
+			blueprint.Variation{Mutator: "rust_stdlinkage", Variation: stdLinkage})
+	}
+
 	actx.AddVariationDependencies(
-		append(commonDepVariations, []blueprint.Variation{
+		append(rlibDepVariations, []blueprint.Variation{
 			{Mutator: "rust_libraries", Variation: "rlib"}}...),
 		rlibDepTag, deps.Rlibs...)
 	actx.AddVariationDependencies(
@@ -987,12 +1001,27 @@
 
 	if deps.Rustlibs != nil && !mod.compiler.Disabled() {
 		autoDep := mod.compiler.(autoDeppable).autoDep(ctx)
-		actx.AddVariationDependencies(
-			append(commonDepVariations, []blueprint.Variation{
-				{Mutator: "rust_libraries", Variation: autoDep.variation}}...),
-			autoDep.depTag, deps.Rustlibs...)
+		if autoDep.depTag == rlibDepTag {
+			actx.AddVariationDependencies(
+				append(rlibDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation}),
+				autoDep.depTag, deps.Rustlibs...)
+		} else {
+			actx.AddVariationDependencies(
+				append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation}),
+				autoDep.depTag, deps.Rustlibs...)
+		}
 	}
-
+	if deps.Stdlibs != nil {
+		if mod.compiler.staticStd(ctx) {
+			actx.AddVariationDependencies(
+				append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: "rlib"}),
+				rlibDepTag, deps.Stdlibs...)
+		} else {
+			actx.AddVariationDependencies(
+				append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"}),
+				dylibDepTag, deps.Stdlibs...)
+		}
+	}
 	actx.AddVariationDependencies(append(commonDepVariations,
 		blueprint.Variation{Mutator: "link", Variation: "shared"}),
 		cc.SharedDepTag(), deps.SharedLibs...)
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 89ce359..4842a4c 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -189,7 +189,7 @@
 		t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)")
 	}
 
-	if !android.InList("librlib", module.Properties.AndroidMkRlibs) {
+	if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) {
 		t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)")
 	}
 
@@ -253,7 +253,7 @@
         }
 	`)
 
-	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Rule("rustc")
+	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Rule("rustc")
 	if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/bindings.rs") {
 		t.Errorf("rust_bindgen generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings())
 	}
@@ -279,15 +279,15 @@
 
 	// Check that our bindings are picked up as crate dependencies as well
 	libfooMod := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
-	if !android.InList("libbindings", libfooMod.Properties.AndroidMkRlibs) {
+	if !android.InList("libbindings.dylib-std", libfooMod.Properties.AndroidMkRlibs) {
 		t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
 	}
 	fizzBuzzMod := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Module().(*Module)
-	if !android.InList("libbindings", fizzBuzzMod.Properties.AndroidMkRlibs) {
+	if !android.InList("libbindings.dylib-std", fizzBuzzMod.Properties.AndroidMkRlibs) {
 		t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
 	}
 	libprocmacroMod := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Module().(*Module)
-	if !android.InList("libbindings", libprocmacroMod.Properties.AndroidMkRlibs) {
+	if !android.InList("libbindings.rlib-std", libprocmacroMod.Properties.AndroidMkRlibs) {
 		t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
 	}
 
@@ -365,6 +365,6 @@
 			crate_name: "foo",
 		}`)
 
-	_ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib")
-	_ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib")
+	_ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std")
+	_ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib_dylib-std")
 }
diff --git a/rust/test.go b/rust/test.go
index d93fc31..0679448 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -133,3 +133,7 @@
 	module, _ := NewRustTest(android.HostSupported)
 	return module.Init()
 }
+
+func (test *testDecorator) staticStd(ctx *depsContext) bool {
+	return true
+}
diff --git a/rust/test_test.go b/rust/test_test.go
index 2382b18..fea2ad0 100644
--- a/rust/test_test.go
+++ b/rust/test_test.go
@@ -17,6 +17,8 @@
 import (
 	"strings"
 	"testing"
+
+	"android/soong/android"
 )
 
 func TestRustTest(t *testing.T) {
@@ -33,3 +35,35 @@
 		t.Errorf("wrong output path: %v;  expected: %v", outPath, expectedOut)
 	}
 }
+
+func TestRustTestLinkage(t *testing.T) {
+	ctx := testRust(t, `
+		rust_test {
+			name: "my_test",
+			srcs: ["foo.rs"],
+			rustlibs: ["libfoo"],
+            rlibs: ["libbar"],
+		}
+		rust_library {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+		}
+		rust_library {
+			name: "libbar",
+			srcs: ["foo.rs"],
+			crate_name: "bar",
+		}`)
+
+	testingModule := ctx.ModuleForTests("my_test", "android_arm64_armv8-a").Module().(*Module)
+
+	if !android.InList("libfoo.rlib-std", testingModule.Properties.AndroidMkRlibs) {
+		t.Errorf("rlib-std variant for libfoo not detected as a rustlib-defined rlib dependency for device rust_test module")
+	}
+	if !android.InList("libbar.rlib-std", testingModule.Properties.AndroidMkRlibs) {
+		t.Errorf("rlib-std variant for libbar not detected as an rlib dependency for device rust_test module")
+	}
+	if !android.InList("libstd", testingModule.Properties.AndroidMkRlibs) {
+		t.Errorf("Device rust_test module 'my_test' does not link libstd as an rlib")
+	}
+}
diff --git a/rust/testing.go b/rust/testing.go
index 0144c82..ee303ed 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -32,6 +32,7 @@
                                     srcs: ["libstd.so"],
                                 },
 				host_supported: true,
+				sysroot: true,
 		}
 		rust_prebuilt_library {
 				name: "libtest_x86_64-unknown-linux-gnu",
@@ -43,6 +44,7 @@
                                     srcs: ["libtest.so"],
                                 },
 				host_supported: true,
+				sysroot: true,
 		}
 		rust_prebuilt_library {
 				name: "libstd_x86_64-apple-darwin",
@@ -54,6 +56,7 @@
                                     srcs: ["libstd.so"],
                                 },
 				host_supported: true,
+				sysroot: true,
 		}
 		rust_prebuilt_library {
 				name: "libtest_x86_64-apple-darwin",
@@ -65,6 +68,7 @@
                                     srcs: ["libtest.so"],
                                 },
 				host_supported: true,
+				sysroot: true,
 		}
 		//////////////////////////////
 		// Device module requirements
@@ -82,6 +86,7 @@
 			no_stdlibs: true,
 			host_supported: true,
                         native_coverage: false,
+			sysroot: true,
 		}
 		rust_library {
 			name: "libtest",
@@ -90,6 +95,7 @@
 			no_stdlibs: true,
 			host_supported: true,
                         native_coverage: false,
+			sysroot: true,
 		}
 		rust_library {
 			name: "libprotobuf",
@@ -134,6 +140,7 @@
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		// rust mutators
 		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
+		ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel()
 		ctx.BottomUp("rust_begin", BeginMutator).Parallel()
 	})
 	ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)