cc/rust: Alias ffi rlib variant for static_libs

Alias the rlib variant to "link: static". This allows declaring
rust_ffi_rlib modules in static_libs. This effectively removes any
distinction between rust_ffi_static and rust_ffi_rlib. Removing the
functionality for building Rust staticlib modules will be cleaned up in
a follow-on CL.

This should have the effect of changing the default linkage for all rust
modules in static_libs from linking individual staticlibs to building a
single staticlib that includes all rust_ffi rlib dependencies.

This removes the static_rlibs property, as we're now handling
the choice dynamically. This also makes rlibs only propagate through
cc_library_static modules if the rlib is included in
whole_static_lib. This both mirrors the expected behavior of
cc libraries and helps control which version of a crate ends up in the
final link (e.g. libdoh_ffi vs libdoh_ffi_for_test).

Bug: 254469782
Test: m
Test: m blueprint_tests
Change-Id: I2925f67f6dc9329dae3dcccafb8560900ac8a6fc
diff --git a/cc/builder.go b/cc/builder.go
index 8719d4f..367bda3 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -798,9 +798,12 @@
 // Generate a Rust staticlib from a list of rlibDeps. Returns nil if TransformRlibstoStaticlib is nil or rlibDeps is empty.
 func generateRustStaticlib(ctx android.ModuleContext, rlibDeps []RustRlibDep) android.Path {
 	if TransformRlibstoStaticlib == nil && len(rlibDeps) > 0 {
-		// This should only be reachable if a module defines static_rlibs and
+		// This should only be reachable if a module defines Rust deps in static_libs and
 		// soong-rust hasn't been loaded alongside soong-cc (e.g. in soong-cc tests).
-		panic(fmt.Errorf("TransformRlibstoStaticlib is not set and static_rlibs is defined in %s", ctx.ModuleName()))
+		panic(fmt.Errorf(
+			"TransformRlibstoStaticlib is not set and rust deps are defined in static_libs for %s",
+			ctx.ModuleName()))
+
 	} else if len(rlibDeps) == 0 {
 		return nil
 	}
@@ -829,6 +832,7 @@
 func genRustStaticlibSrcFile(crateNames []string) string {
 	lines := []string{
 		"// @Soong generated Source",
+		"#![no_std]", // pre-emptively set no_std to support both std and no_std.
 	}
 	for _, crate := range crateNames {
 		lines = append(lines, fmt.Sprintf("extern crate %s;", crate))
diff --git a/cc/cc.go b/cc/cc.go
index d8fe319..9a2540d 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -99,7 +99,6 @@
 	StaticLibs, LateStaticLibs, WholeStaticLibs []string
 	HeaderLibs                                  []string
 	RuntimeLibs                                 []string
-	Rlibs                                       []string
 
 	// UnexportedStaticLibs are static libraries that are also passed to -Wl,--exclude-libs= to
 	// prevent automatically exporting symbols.
@@ -746,11 +745,6 @@
 	return d.Kind == staticLibraryDependency
 }
 
-// rlib returns true if the libraryDependencyTag is tagging an rlib dependency.
-func (d libraryDependencyTag) rlib() bool {
-	return d.Kind == rlibLibraryDependency
-}
-
 func (d libraryDependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
 	if d.shared() {
 		return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency}
@@ -917,6 +911,8 @@
 	hideApexVariantFromMake bool
 
 	logtagsPaths android.Paths
+
+	WholeRustStaticlib bool
 }
 
 func (c *Module) AddJSONData(d *map[string]interface{}) {
@@ -1192,6 +1188,16 @@
 	panic(fmt.Errorf("BuildSharedVariant called on non-library module: %q", c.BaseModuleName()))
 }
 
+func (c *Module) BuildRlibVariant() bool {
+	// cc modules can never build rlib variants
+	return false
+}
+
+func (c *Module) IsRustFFI() bool {
+	// cc modules are not Rust modules
+	return false
+}
+
 func (c *Module) Module() android.Module {
 	return c
 }
@@ -2267,7 +2273,6 @@
 
 	deps.WholeStaticLibs = android.LastUniqueStrings(deps.WholeStaticLibs)
 	deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
-	deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
 	deps.LateStaticLibs = android.LastUniqueStrings(deps.LateStaticLibs)
 	deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
 	deps.LateSharedLibs = android.LastUniqueStrings(deps.LateSharedLibs)
@@ -2562,28 +2567,20 @@
 	}
 
 	for _, lib := range deps.StaticLibs {
+		// Some dependencies listed in static_libs might actually be rust_ffi rlib variants.
 		depTag := libraryDependencyTag{Kind: staticLibraryDependency}
+
 		if inList(lib, deps.ReexportStaticLibHeaders) {
 			depTag.reexportFlags = true
 		}
 		if inList(lib, deps.ExcludeLibsForApex) {
 			depTag.excludeInApex = true
 		}
-
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
 		}, depTag, lib)
 	}
 
-	for _, lib := range deps.Rlibs {
-		depTag := libraryDependencyTag{Kind: rlibLibraryDependency}
-		actx.AddVariationDependencies([]blueprint.Variation{
-			{Mutator: "link", Variation: ""},
-			{Mutator: "rust_libraries", Variation: "rlib"},
-			{Mutator: "rust_stdlinkage", Variation: "rlib-std"},
-		}, depTag, lib)
-	}
-
 	// staticUnwinderDep is treated as staticDep for Q apexes
 	// so that native libraries/binaries are linked with static unwinder
 	// because Q libc doesn't have unwinder APIs
@@ -3171,78 +3168,86 @@
 					panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
 				}
 
-			case libDepTag.rlib():
-				rlibDep := RustRlibDep{LibPath: linkFile.Path(), CrateName: ccDep.CrateName(), LinkDirs: ccDep.ExportedCrateLinkDirs()}
-				depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, rlibDep)
-				depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, rlibDep)
-				depPaths.IncludeDirs = append(depPaths.IncludeDirs, depExporterInfo.IncludeDirs...)
-				depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, depExporterInfo.IncludeDirs...)
-
 			case libDepTag.static():
-				staticLibraryInfo, isStaticLib := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider)
-				if !isStaticLib {
-					if !ctx.Config().AllowMissingDependencies() {
-						ctx.ModuleErrorf("module %q is not a static library", depName)
-					} else {
-						ctx.AddMissingDependencies([]string{depName})
-					}
-					return
-				}
+				if ccDep.RustLibraryInterface() {
+					rlibDep := RustRlibDep{LibPath: linkFile.Path(), CrateName: ccDep.CrateName(), LinkDirs: ccDep.ExportedCrateLinkDirs()}
+					depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, rlibDep)
+					depPaths.IncludeDirs = append(depPaths.IncludeDirs, depExporterInfo.IncludeDirs...)
+					if libDepTag.wholeStatic {
+						depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, depExporterInfo.IncludeDirs...)
+						depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, rlibDep)
 
-				// Stubs lib doesn't link to the static lib dependencies. Don't set
-				// linkFile, depFile, and ptr.
-				if c.IsStubs() {
-					break
-				}
-
-				linkFile = android.OptionalPathForPath(staticLibraryInfo.StaticLibrary)
-				if libDepTag.wholeStatic {
-					ptr = &depPaths.WholeStaticLibs
-					if len(staticLibraryInfo.Objects.objFiles) > 0 {
-						depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLibraryInfo.Objects)
-					} else {
-						// This case normally catches prebuilt static
-						// libraries, but it can also occur when
-						// AllowMissingDependencies is on and the
-						// dependencies has no sources of its own
-						// but has a whole_static_libs dependency
-						// on a missing library.  We want to depend
-						// on the .a file so that there is something
-						// in the dependency tree that contains the
-						// error rule for the missing transitive
-						// dependency.
-						depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, linkFile.Path())
+						// If whole_static, track this as we want to make sure that in a final linkage for a shared library,
+						// exported functions from the rust generated staticlib still exported.
+						if c.CcLibrary() && c.Shared() {
+							c.WholeRustStaticlib = true
+						}
 					}
-					depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts,
-						staticLibraryInfo.WholeStaticLibsFromPrebuilts...)
+
 				} else {
-					switch libDepTag.Order {
-					case earlyLibraryDependency:
-						panic(fmt.Errorf("early static libs not suppported"))
-					case normalLibraryDependency:
-						// static dependencies will be handled separately so they can be ordered
-						// using transitive dependencies.
-						ptr = nil
-						directStaticDeps = append(directStaticDeps, staticLibraryInfo)
-					case lateLibraryDependency:
-						ptr = &depPaths.LateStaticLibs
-					default:
-						panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
+					staticLibraryInfo, isStaticLib := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider)
+					if !isStaticLib {
+						if !ctx.Config().AllowMissingDependencies() {
+							ctx.ModuleErrorf("module %q is not a static library", depName)
+						} else {
+							ctx.AddMissingDependencies([]string{depName})
+						}
+						return
 					}
-				}
 
-				// We re-export the Rust static_rlibs so rlib dependencies don't need to be redeclared by cc_library_static dependents.
-				// E.g. libfoo (cc_library_static) depends on libfoo.ffi (a rust_ffi rlib), libbar depending on libfoo shouldn't have to also add libfoo.ffi to static_rlibs.
-				depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, depExporterInfo.RustRlibDeps...)
-				depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, depExporterInfo.RustRlibDeps...)
+					// Stubs lib doesn't link to the static lib dependencies. Don't set
+					// linkFile, depFile, and ptr.
+					if c.IsStubs() {
+						break
+					}
 
-				if libDepTag.unexportedSymbols {
-					depPaths.LdFlags = append(depPaths.LdFlags,
-						"-Wl,--exclude-libs="+staticLibraryInfo.StaticLibrary.Base())
+					linkFile = android.OptionalPathForPath(staticLibraryInfo.StaticLibrary)
+					if libDepTag.wholeStatic {
+						ptr = &depPaths.WholeStaticLibs
+						if len(staticLibraryInfo.Objects.objFiles) > 0 {
+							depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLibraryInfo.Objects)
+						} else {
+							// This case normally catches prebuilt static
+							// libraries, but it can also occur when
+							// AllowMissingDependencies is on and the
+							// dependencies has no sources of its own
+							// but has a whole_static_libs dependency
+							// on a missing library.  We want to depend
+							// on the .a file so that there is something
+							// in the dependency tree that contains the
+							// error rule for the missing transitive
+							// dependency.
+							depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, linkFile.Path())
+						}
+						depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts,
+							staticLibraryInfo.WholeStaticLibsFromPrebuilts...)
+					} else {
+						switch libDepTag.Order {
+						case earlyLibraryDependency:
+							panic(fmt.Errorf("early static libs not supported"))
+						case normalLibraryDependency:
+							// static dependencies will be handled separately so they can be ordered
+							// using transitive dependencies.
+							ptr = nil
+							directStaticDeps = append(directStaticDeps, staticLibraryInfo)
+						case lateLibraryDependency:
+							ptr = &depPaths.LateStaticLibs
+						default:
+							panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
+						}
+					}
+
+					// Collect any exported Rust rlib deps from static libraries which have been included as whole_static_libs
+					depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, depExporterInfo.RustRlibDeps...)
+
+					if libDepTag.unexportedSymbols {
+						depPaths.LdFlags = append(depPaths.LdFlags,
+							"-Wl,--exclude-libs="+staticLibraryInfo.StaticLibrary.Base())
+					}
 				}
 			}
 
-			if libDepTag.static() && !libDepTag.wholeStatic {
+			if libDepTag.static() && !libDepTag.wholeStatic && !ccDep.RustLibraryInterface() {
 				if !ccDep.CcLibraryInterface() || !ccDep.Static() {
 					ctx.ModuleErrorf("module %q not a static library", depName)
 					return
@@ -3329,12 +3334,14 @@
 				c.Properties.AndroidMkSharedLibs = append(
 					c.Properties.AndroidMkSharedLibs, makeLibName)
 			case libDepTag.static():
-				if libDepTag.wholeStatic {
-					c.Properties.AndroidMkWholeStaticLibs = append(
-						c.Properties.AndroidMkWholeStaticLibs, makeLibName)
-				} else {
-					c.Properties.AndroidMkStaticLibs = append(
-						c.Properties.AndroidMkStaticLibs, makeLibName)
+				if !ccDep.RustLibraryInterface() {
+					if libDepTag.wholeStatic {
+						c.Properties.AndroidMkWholeStaticLibs = append(
+							c.Properties.AndroidMkWholeStaticLibs, makeLibName)
+					} else {
+						c.Properties.AndroidMkStaticLibs = append(
+							c.Properties.AndroidMkStaticLibs, makeLibName)
+					}
 				}
 			}
 		} else if !c.IsStubs() {
diff --git a/cc/compiler.go b/cc/compiler.go
index d8446fb..a3347b0 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -796,9 +796,6 @@
 	// be added to the include path using -I
 	Local_include_dirs []string `android:"arch_variant,variant_prepend"`
 
-	// list of Rust static libraries.
-	Static_rlibs []string `android:"arch_variant,variant_prepend"`
-
 	// list of static libraries that provide headers for this binding.
 	Static_libs []string `android:"arch_variant,variant_prepend"`
 
diff --git a/cc/library.go b/cc/library.go
index e49f50c..4373b46 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1135,8 +1135,12 @@
 	linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
 	linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
 
-	if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil {
-		deps.StaticLibs = append(deps.StaticLibs, generatedLib)
+	if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil && !library.buildStubs() {
+		if ctx.Module().(*Module).WholeRustStaticlib {
+			deps.WholeStaticLibs = append(deps.WholeStaticLibs, generatedLib)
+		} else {
+			deps.StaticLibs = append(deps.StaticLibs, generatedLib)
+		}
 	}
 
 	transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
@@ -2149,7 +2153,6 @@
 			modules := mctx.CreateLocalVariations(variations...)
 			static := modules[0].(LinkableInterface)
 			shared := modules[1].(LinkableInterface)
-
 			static.SetStatic()
 			shared.SetShared()
 
@@ -2173,6 +2176,12 @@
 			mctx.CreateLocalVariations(variations...)
 			mctx.AliasVariation(variations[0])
 		}
+		if library.BuildRlibVariant() && library.IsRustFFI() && !buildStatic {
+			// 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.
+			mctx.CreateAliasVariation("static", "")
+		}
 	}
 }
 
diff --git a/cc/linkable.go b/cc/linkable.go
index 2309fe8..1672366 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -94,12 +94,16 @@
 	SelectedStl() string
 
 	BuildStaticVariant() bool
+	BuildRlibVariant() bool
 	BuildSharedVariant() bool
 	SetStatic()
 	SetShared()
 	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/cc/linker.go b/cc/linker.go
index 1675df6..d2974c2 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -39,9 +39,6 @@
 	// the dependency's .a file will be linked into this module using -Wl,--whole-archive.
 	Whole_static_libs []string `android:"arch_variant,variant_prepend"`
 
-	// list of Rust libs that should be statically linked into this module.
-	Static_rlibs []string `android:"arch_variant"`
-
 	// list of modules that should be statically linked into this module.
 	Static_libs []string `android:"arch_variant,variant_prepend"`
 
@@ -127,10 +124,6 @@
 			// variant of the C/C++ module.
 			Header_libs []string
 
-			// list of Rust libs that should be statically linked to build vendor or product
-			// variant.
-			Static_rlibs []string
-
 			// list of shared libs that should not be used to build vendor or
 			// product variant of the C/C++ module.
 			Exclude_shared_libs []string
@@ -159,10 +152,6 @@
 			// variant of the C/C++ module.
 			Static_libs []string
 
-			// list of Rust libs that should be statically linked to build the recovery
-			// variant.
-			Static_rlibs []string
-
 			// list of shared libs that should not be used to build
 			// the recovery variant of the C/C++ module.
 			Exclude_shared_libs []string
@@ -184,10 +173,6 @@
 			// variant of the C/C++ module.
 			Static_libs []string
 
-			// list of Rust libs that should be statically linked to build the ramdisk
-			// variant.
-			Static_rlibs []string
-
 			// list of shared libs that should not be used to build
 			// the ramdisk variant of the C/C++ module.
 			Exclude_shared_libs []string
@@ -205,10 +190,6 @@
 			// the vendor ramdisk variant of the C/C++ module.
 			Exclude_shared_libs []string
 
-			// list of Rust libs that should be statically linked to build the vendor ramdisk
-			// variant.
-			Static_rlibs []string
-
 			// list of static libs that should not be used to build
 			// the vendor ramdisk variant of the C/C++ module.
 			Exclude_static_libs []string
@@ -224,10 +205,6 @@
 			// variants.
 			Shared_libs []string
 
-			// list of Rust libs that should be statically linked to build the vendor ramdisk
-			// variant.
-			Static_rlibs []string
-
 			// list of ehader libs that only should be used to build platform variant of
 			// the C/C++ module.
 			Header_libs []string
@@ -322,7 +299,6 @@
 	deps.WholeStaticLibs = append(deps.WholeStaticLibs, linker.Properties.Whole_static_libs...)
 	deps.HeaderLibs = append(deps.HeaderLibs, linker.Properties.Header_libs...)
 	deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Static_libs...)
-	deps.Rlibs = append(deps.Rlibs, linker.Properties.Static_rlibs...)
 	deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Shared_libs...)
 	deps.RuntimeLibs = append(deps.RuntimeLibs, linker.Properties.Runtime_libs...)
 
@@ -366,7 +342,6 @@
 		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor.Exclude_static_libs)
 		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor.Exclude_static_libs)
 		deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Vendor.Exclude_runtime_libs)
-		deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Vendor.Static_rlibs...)
 	}
 
 	if ctx.inProduct() {
@@ -380,7 +355,6 @@
 		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Product.Exclude_static_libs)
 		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Product.Exclude_static_libs)
 		deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Product.Exclude_runtime_libs)
-		deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Product.Static_rlibs...)
 	}
 
 	if ctx.inRecovery() {
@@ -394,7 +368,6 @@
 		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Recovery.Exclude_static_libs)
 		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
 		deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Recovery.Exclude_runtime_libs)
-		deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Recovery.Static_rlibs...)
 	}
 
 	if ctx.inRamdisk() {
@@ -405,7 +378,6 @@
 		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Ramdisk.Exclude_static_libs)
 		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Ramdisk.Exclude_static_libs)
 		deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Ramdisk.Exclude_runtime_libs)
-		deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Ramdisk.Static_rlibs...)
 	}
 
 	if ctx.inVendorRamdisk() {
@@ -415,7 +387,6 @@
 		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
 		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
 		deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_runtime_libs)
-		deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Vendor_ramdisk.Static_rlibs...)
 	}
 
 	if !ctx.useSdk() {