rust: Alias rust_ffi_rlib to rust_library_rlib

With the new transition mutators, the distinctions between rust_ffi_rlib
and rust_library_rlib are not necessary. This CL removes the remaining
distinctions to allow an unusual use case where a rust_library and a
rust_ffi_rlib would otherwise be created from the same source. This
would allow defining a single rust_library_rlib that works for both rust
modules and cc modules.

One key change is that rust_ffi_rlibs only produced an rlib-std variant
previously, and now produce dylib-std variants as well.This surfaced an
issue where a libstd linkage mismatch would cause rustc to throw a
consufing missing crate error. We instead add logic to catch this in
Soong and provide a more useful error message.

Bug: 383552450
Test: m rust
Test: m blueprint_tests
Change-Id: I611ca46934059735d06229952cfd8e0ab7050486
diff --git a/cc/cc.go b/cc/cc.go
index 04b66d4..812d1c3 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1197,11 +1197,6 @@
 	return false
 }
 
-func (c *Module) IsRustFFI() bool {
-	// cc modules are not Rust modules
-	return false
-}
-
 func (c *Module) Module() android.Module {
 	return c
 }
diff --git a/cc/library.go b/cc/library.go
index ebc65ef..ad8128e 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -2112,7 +2112,7 @@
 		} else {
 			// Header only
 		}
-	} else if library, ok := ctx.Module().(LinkableInterface); ok && (library.CcLibraryInterface() || library.RustLibraryInterface()) {
+	} else if library, ok := ctx.Module().(LinkableInterface); ok && (library.CcLibraryInterface()) {
 		// Non-cc.Modules may need an empty variant for their mutators.
 		variations := []string{}
 		if library.NonCcVariants() {
@@ -2167,7 +2167,7 @@
 		}
 		buildStatic := library.BuildStaticVariant() && !isLLNDK
 		buildShared := library.BuildSharedVariant()
-		if library.BuildRlibVariant() && library.IsRustFFI() && !buildStatic && (incomingVariation == "static" || incomingVariation == "") {
+		if library.BuildRlibVariant() && !buildStatic && (incomingVariation == "static" || incomingVariation == "") {
 			// Rust modules do not build static libs, but rlibs are used as if they
 			// were via `static_libs`. Thus we need to alias the BuildRlibVariant
 			// to "static" for Rust FFI libraries.
diff --git a/cc/linkable.go b/cc/linkable.go
index 1fade71..d0f03c5 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -102,9 +102,6 @@
 	IsPrebuilt() bool
 	Toc() android.OptionalPath
 
-	// IsRustFFI returns true if this is a Rust FFI library.
-	IsRustFFI() bool
-
 	// IsFuzzModule returns true if this a *_fuzz module.
 	IsFuzzModule() bool
 
diff --git a/rust/benchmark.go b/rust/benchmark.go
index 8c3e515..eaa2176 100644
--- a/rust/benchmark.go
+++ b/rust/benchmark.go
@@ -89,7 +89,7 @@
 	return rlibAutoDep
 }
 
-func (benchmark *benchmarkDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+func (benchmark *benchmarkDecorator) stdLinkage(device bool) RustLinkage {
 	return RlibLinkage
 }
 
diff --git a/rust/binary.go b/rust/binary.go
index cba29a0..d22041b 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -165,11 +165,11 @@
 	}
 }
 
-func (binary *binaryDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+func (binary *binaryDecorator) stdLinkage(device bool) RustLinkage {
 	if binary.preferRlib() {
 		return RlibLinkage
 	}
-	return binary.baseCompiler.stdLinkage(ctx)
+	return binary.baseCompiler.stdLinkage(device)
 }
 
 func (binary *binaryDecorator) binary() bool {
diff --git a/rust/compiler.go b/rust/compiler.go
index fd86917..b93019b 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -30,9 +30,8 @@
 type RustLinkage int
 
 const (
-	DefaultLinkage RustLinkage = iota
+	DylibLinkage RustLinkage = iota
 	RlibLinkage
-	DylibLinkage
 )
 
 type compiler interface {
@@ -69,7 +68,7 @@
 	Disabled() bool
 	SetDisabled()
 
-	stdLinkage(ctx *depsContext) RustLinkage
+	stdLinkage(device bool) RustLinkage
 	noStdlibs() bool
 
 	unstrippedOutputFilePath() android.Path
@@ -316,11 +315,11 @@
 	return aliases
 }
 
-func (compiler *baseCompiler) stdLinkage(ctx *depsContext) RustLinkage {
+func (compiler *baseCompiler) stdLinkage(device bool) RustLinkage {
 	// For devices, we always link stdlibs in as dylibs by default.
 	if compiler.preferRlib() {
 		return RlibLinkage
-	} else if ctx.Device() {
+	} else if device {
 		return DylibLinkage
 	} else {
 		return RlibLinkage
diff --git a/rust/fuzz.go b/rust/fuzz.go
index 1770d2e..68becb5 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -121,7 +121,7 @@
 	return out
 }
 
-func (fuzzer *fuzzDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+func (fuzzer *fuzzDecorator) stdLinkage(device bool) RustLinkage {
 	return RlibLinkage
 }
 
diff --git a/rust/library.go b/rust/library.go
index bd3359b..93a9a3d 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -40,15 +40,15 @@
 	android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
 	android.RegisterModuleType("rust_ffi", RustFFIFactory)
 	android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
-	android.RegisterModuleType("rust_ffi_rlib", RustFFIRlibFactory)
+	android.RegisterModuleType("rust_ffi_rlib", RustLibraryRlibFactory)
 	android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
 	android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
-	android.RegisterModuleType("rust_ffi_host_rlib", RustFFIRlibHostFactory)
+	android.RegisterModuleType("rust_ffi_host_rlib", RustLibraryRlibHostFactory)
 
 	// TODO: Remove when all instances of rust_ffi_static have been switched to rust_ffi_rlib
 	// Alias rust_ffi_static to the rust_ffi_rlib factory
-	android.RegisterModuleType("rust_ffi_static", RustFFIRlibFactory)
-	android.RegisterModuleType("rust_ffi_host_static", RustFFIRlibHostFactory)
+	android.RegisterModuleType("rust_ffi_static", RustLibraryRlibFactory)
+	android.RegisterModuleType("rust_ffi_host_static", RustLibraryRlibHostFactory)
 }
 
 type VariantLibraryProperties struct {
@@ -114,8 +114,6 @@
 	includeDirs       android.Paths
 	sourceProvider    SourceProvider
 
-	isFFI bool
-
 	// table-of-contents file for cdylib crates to optimize out relinking when possible
 	tocFile android.OptionalPath
 }
@@ -156,8 +154,6 @@
 	BuildOnlyShared()
 
 	toc() android.OptionalPath
-
-	isFFILibrary() bool
 }
 
 func (library *libraryDecorator) nativeCoverage() bool {
@@ -262,13 +258,13 @@
 	}
 }
 
-func (library *libraryDecorator) stdLinkage(ctx *depsContext) RustLinkage {
-	if library.static() || library.MutatedProperties.VariantIsStaticStd || (library.rlib() && library.isFFILibrary()) {
+func (library *libraryDecorator) stdLinkage(device bool) RustLinkage {
+	if library.static() || library.MutatedProperties.VariantIsStaticStd {
 		return RlibLinkage
 	} else if library.baseCompiler.preferRlib() {
 		return RlibLinkage
 	}
-	return DefaultLinkage
+	return DylibLinkage
 }
 
 var _ compiler = (*libraryDecorator)(nil)
@@ -298,7 +294,7 @@
 	return module.Init()
 }
 
-// rust_library_rlib produces an rlib (Rust crate type "rlib").
+// rust_library_rlib and rust_ffi_static produces an rlib (Rust crate type "rlib").
 func RustLibraryRlibFactory() android.Module {
 	module, library := NewRustLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyRlib()
@@ -337,8 +333,8 @@
 	return module.Init()
 }
 
-// rust_library_rlib_host produces an rlib for the host (Rust crate
-// type "rlib").
+// rust_library_rlib_host and rust_ffi_static_host produces an rlib for the host
+// (Rust crate type "rlib").
 func RustLibraryRlibHostFactory() android.Module {
 	module, library := NewRustLibrary(android.HostSupported)
 	library.BuildOnlyRlib()
@@ -353,33 +349,12 @@
 	return module.Init()
 }
 
-// rust_ffi_rlib_host produces an rlib for the host (Rust crate
-// type "rlib").
-func RustFFIRlibHostFactory() android.Module {
-	module, library := NewRustLibrary(android.HostSupported)
-	library.BuildOnlyRlib()
-
-	library.isFFI = true
-	return module.Init()
-}
-
-// rust_ffi_rlib produces an rlib (Rust crate type "rlib").
-func RustFFIRlibFactory() android.Module {
-	module, library := NewRustLibrary(android.HostAndDeviceSupported)
-	library.BuildOnlyRlib()
-
-	library.isFFI = true
-	return module.Init()
-}
-
 func (library *libraryDecorator) BuildOnlyFFI() {
 	library.MutatedProperties.BuildDylib = false
 	// we build rlibs for later static ffi linkage.
 	library.MutatedProperties.BuildRlib = true
 	library.MutatedProperties.BuildShared = true
 	library.MutatedProperties.BuildStatic = false
-
-	library.isFFI = true
 }
 
 func (library *libraryDecorator) BuildOnlyRust() {
@@ -408,8 +383,6 @@
 	library.MutatedProperties.BuildDylib = false
 	library.MutatedProperties.BuildShared = false
 	library.MutatedProperties.BuildStatic = true
-
-	library.isFFI = true
 }
 
 func (library *libraryDecorator) BuildOnlyShared() {
@@ -417,12 +390,6 @@
 	library.MutatedProperties.BuildDylib = false
 	library.MutatedProperties.BuildStatic = false
 	library.MutatedProperties.BuildShared = true
-
-	library.isFFI = true
-}
-
-func (library *libraryDecorator) isFFILibrary() bool {
-	return library.isFFI
 }
 
 func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
@@ -511,7 +478,9 @@
 
 	flags = CommonLibraryCompilerFlags(ctx, flags)
 
-	if library.isFFI {
+	if library.rlib() || library.shared() {
+		// rlibs collect include dirs as well since they are used to
+		// produce staticlibs in the final C linkages
 		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
 		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Export_include_dirs)...)
 	}
@@ -821,11 +790,7 @@
 		// Only create a variant if a library is actually being built.
 		if library, ok := m.compiler.(libraryInterface); ok {
 			if library.rlib() && !library.sysroot() {
-				if library.isFFILibrary() {
-					return []string{"rlib-std"}
-				} else {
-					return []string{"rlib-std", "dylib-std"}
-				}
+				return []string{"rlib-std", "dylib-std"}
 			}
 		}
 	}
diff --git a/rust/rust.go b/rust/rust.go
index 64cfa40..cd4bd43 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -594,7 +594,7 @@
 	if mod.compiler != nil {
 		// use build{Static,Shared}() instead of {static,shared}() here because this might be called before
 		// VariantIs{Static,Shared} is set.
-		if lib, ok := mod.compiler.(libraryInterface); ok && (lib.buildShared() || lib.buildStatic()) {
+		if lib, ok := mod.compiler.(libraryInterface); ok && (lib.buildShared() || lib.buildStatic() || lib.buildRlib()) {
 			return true
 		}
 	}
@@ -680,15 +680,6 @@
 	panic(fmt.Errorf("BuildRlibVariant called on non-library module: %q", mod.BaseModuleName()))
 }
 
-func (mod *Module) IsRustFFI() bool {
-	if mod.compiler != nil {
-		if library, ok := mod.compiler.(libraryInterface); ok {
-			return library.isFFILibrary()
-		}
-	}
-	return false
-}
-
 func (mod *Module) BuildSharedVariant() bool {
 	if mod.compiler != nil {
 		if library, ok := mod.compiler.(libraryInterface); ok {
@@ -1236,6 +1227,8 @@
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
+		modStdLinkage := mod.compiler.stdLinkage(ctx.Device())
+
 		if _, exists := skipModuleList[depName]; exists {
 			return
 		}
@@ -1264,6 +1257,14 @@
 					depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
 				}
 
+				if !rustDep.compiler.noStdlibs() {
+					rustDepStdLinkage := rustDep.compiler.stdLinkage(ctx.Device())
+					if rustDepStdLinkage != modStdLinkage {
+						ctx.ModuleErrorf("Rust dependency %q has the wrong StdLinkage; expected %#v, got %#v", depName, modStdLinkage, rustDepStdLinkage)
+						return
+					}
+				}
+
 			case depTag == rlibDepTag:
 				rlib, ok := rustDep.compiler.(libraryInterface)
 				if !ok || !rlib.rlib() {
@@ -1284,6 +1285,14 @@
 					depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
 				}
 
+				if !rustDep.compiler.noStdlibs() {
+					rustDepStdLinkage := rustDep.compiler.stdLinkage(ctx.Device())
+					if rustDepStdLinkage != modStdLinkage {
+						ctx.ModuleErrorf("Rust dependency %q has the wrong StdLinkage; expected %#v, got %#v", depName, modStdLinkage, rustDepStdLinkage)
+						return
+					}
+				}
+
 			case depTag == procMacroDepTag:
 				directProcMacroDeps = append(directProcMacroDeps, rustDep)
 				mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName)
@@ -1602,7 +1611,7 @@
 	}
 
 	stdLinkage := "dylib-std"
-	if mod.compiler.stdLinkage(ctx) == RlibLinkage {
+	if mod.compiler.stdLinkage(ctx.Device()) == RlibLinkage {
 		stdLinkage = "rlib-std"
 	}
 
@@ -1669,7 +1678,7 @@
 
 	// stdlibs
 	if deps.Stdlibs != nil {
-		if mod.compiler.stdLinkage(ctx) == RlibLinkage {
+		if mod.compiler.stdLinkage(ctx.Device()) == RlibLinkage {
 			for _, lib := range deps.Stdlibs {
 				actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...),
 					rlibDepTag, lib)
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 767508d..7e64c0a 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -547,3 +547,31 @@
 		t.Errorf("expected %q got %q", expected, got)
 	}
 }
+
+func TestStdLinkMismatch(t *testing.T) {
+	// Test that we catch cases where the std linkage mismatches. This leads to
+	// a confusing rustc error where a crate is declared missing despite being
+	// passed in as a rustlib dependency / via the --extern flag. Thus, we want
+	// to make sure we detect it in Soong.
+
+	// libfoo depends on libbar as an rlib, but does not link libstd as an rlib.
+	// libbar only links libstd as an rlib (prefer_rlib).
+	testRustError(t, "wrong StdLinkage", `
+		rust_library {
+			name: "libfoo",
+			crate_name: "foo",
+			srcs: [
+				"foo.rs",
+			],
+			rlibs: ["libbar"],
+		}
+		rust_library {
+			name: "libbar",
+			crate_name: "bar",
+			srcs: [
+				"bar.rs",
+			],
+			prefer_rlib: true,
+		}
+	`)
+}
diff --git a/rust/test.go b/rust/test.go
index 20ccfb3..dce5e03 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -238,7 +238,7 @@
 	return module.Init()
 }
 
-func (test *testDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+func (test *testDecorator) stdLinkage(device bool) RustLinkage {
 	return RlibLinkage
 }
 
diff --git a/rust/testing.go b/rust/testing.go
index 32cc823..2e50e1e 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -188,12 +188,12 @@
 	ctx.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory)
 	ctx.RegisterModuleType("rust_ffi", RustFFIFactory)
 	ctx.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
-	ctx.RegisterModuleType("rust_ffi_rlib", RustFFIRlibFactory)
-	ctx.RegisterModuleType("rust_ffi_static", RustFFIRlibFactory)
+	ctx.RegisterModuleType("rust_ffi_rlib", RustLibraryRlibFactory)
+	ctx.RegisterModuleType("rust_ffi_static", RustLibraryRlibFactory)
 	ctx.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
 	ctx.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
-	ctx.RegisterModuleType("rust_ffi_host_rlib", RustFFIRlibHostFactory)
-	ctx.RegisterModuleType("rust_ffi_host_static", RustFFIRlibHostFactory)
+	ctx.RegisterModuleType("rust_ffi_host_rlib", RustLibraryRlibHostFactory)
+	ctx.RegisterModuleType("rust_ffi_host_static", RustLibraryRlibHostFactory)
 	ctx.RegisterModuleType("rust_proc_macro", ProcMacroFactory)
 	ctx.RegisterModuleType("rust_protobuf", RustProtobufFactory)
 	ctx.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)