rust: made-to-order rust staticlibs
Whenever any two Rust static libraries are included
as static libraries anywhere in a CC dependency tree, we sometimes
get duplicate symbol errors. To avoid this, we no longer
directly link multiple rust static libs to CC modules.
Instead, we build rust_ffi_rlib modules and produce the actual
static library that gets linked against the CC module based on
that CC module's full list of Rust rlib dependencies.
This introduces a new static_rlibs property for cc modules to
define the rust_ffi_rlib dependencies, which are then used to
generate the module above.
This CL is intended to deprecate rust_ffi_static. It leaves
rust_ffi_static and rust_ffi static variants in place until
the remaining rust_ffi_static declarations and uses can be
removed. In the meantime, rust_ffi_static produces
rust_ffi_rlib variants as well to make the transition easier.
Bug: 254469782
Test: m # with no changes
Test: m libapexsupport # with static_rlibs
Test: m libunwindstack # with static_rlibs
Test: m netsimd # with static_rlibs, no duplicate symbols
Test: m blueprint_tests # New Soong tests
Change-Id: I47e27ac967ef0cad46d398ebf59d8275929ae28a
diff --git a/cc/cc.go b/cc/cc.go
index e3954d7..6dd2682 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -99,6 +99,7 @@
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.
@@ -144,6 +145,17 @@
LlndkHeaderLibs []string
}
+// A struct which to collect flags for rlib dependencies
+type RustRlibDep struct {
+ LibPath android.Path // path to the rlib
+ LinkDirs []string // flags required for dependency (e.g. -L flags)
+ CrateName string // crateNames associated with rlibDeps
+}
+
+func EqRustRlibDeps(a RustRlibDep, b RustRlibDep) bool {
+ return a.LibPath == b.LibPath
+}
+
// PathDeps is a struct containing file paths to dependencies of a module.
// It's constructed in depsToPath() by traversing the direct dependencies of the current module.
// It's used to construct flags for various build statements (such as for compiling and linking).
@@ -156,6 +168,8 @@
SharedLibsDeps, EarlySharedLibsDeps, LateSharedLibsDeps android.Paths
// Paths to .a files
StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths
+ // Paths and crateNames for RustStaticLib dependencies
+ RustRlibDeps []RustRlibDep
// Transitive static library dependencies of static libraries for use in ordering.
TranstiveStaticLibrariesForOrdering *android.DepSet[android.Path]
@@ -184,6 +198,7 @@
ReexportedFlags []string
ReexportedGeneratedHeaders android.Paths
ReexportedDeps android.Paths
+ ReexportedRustRlibDeps []RustRlibDep
// Paths to crt*.o files
CrtBegin, CrtEnd android.Paths
@@ -297,6 +312,7 @@
AndroidMkSharedLibs []string `blueprint:"mutated"`
AndroidMkStaticLibs []string `blueprint:"mutated"`
+ AndroidMkRlibs []string `blueprint:"mutated"`
AndroidMkRuntimeLibs []string `blueprint:"mutated"`
AndroidMkWholeStaticLibs []string `blueprint:"mutated"`
AndroidMkHeaderLibs []string `blueprint:"mutated"`
@@ -653,6 +669,7 @@
headerLibraryDependency = iota
sharedLibraryDependency
staticLibraryDependency
+ rlibLibraryDependency
)
func (k libraryDependencyKind) String() string {
@@ -663,6 +680,8 @@
return "sharedLibraryDependency"
case staticLibraryDependency:
return "staticLibraryDependency"
+ case rlibLibraryDependency:
+ return "rlibLibraryDependency"
default:
panic(fmt.Errorf("unknown libraryDependencyKind %d", k))
}
@@ -740,6 +759,11 @@
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}
@@ -1108,6 +1132,14 @@
return false
}
+func (c *Module) CrateName() string {
+ panic(fmt.Errorf("CrateName called on non-Rust module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) ExportedCrateLinkDirs() []string {
+ panic(fmt.Errorf("ExportedCrateLinkDirs called on non-Rust module: %q", c.BaseModuleName()))
+}
+
func (c *Module) IsFuzzModule() bool {
if _, ok := c.compiler.(*fuzzBinary); ok {
return true
@@ -2300,6 +2332,7 @@
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)
@@ -2607,6 +2640,15 @@
}, 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
@@ -3216,6 +3258,14 @@
default:
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 {
@@ -3268,6 +3318,12 @@
panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
}
}
+
+ // 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...)
+
if libDepTag.unexportedSymbols {
depPaths.LdFlags = append(depPaths.LdFlags,
"-Wl,--exclude-libs="+staticLibraryInfo.StaticLibrary.Base())
@@ -3320,6 +3376,12 @@
depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, depExporterInfo.SystemIncludeDirs...)
depPaths.GeneratedDeps = append(depPaths.GeneratedDeps, depExporterInfo.Deps...)
depPaths.Flags = append(depPaths.Flags, depExporterInfo.Flags...)
+ depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, depExporterInfo.RustRlibDeps...)
+
+ // Only re-export RustRlibDeps for cc static libs
+ if c.static() {
+ depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, depExporterInfo.RustRlibDeps...)
+ }
if libDepTag.reexportFlags {
reexportExporter(depExporterInfo)
@@ -3392,11 +3454,14 @@
depPaths.IncludeDirs = android.FirstUniquePaths(depPaths.IncludeDirs)
depPaths.SystemIncludeDirs = android.FirstUniquePaths(depPaths.SystemIncludeDirs)
depPaths.GeneratedDeps = android.FirstUniquePaths(depPaths.GeneratedDeps)
+ depPaths.RustRlibDeps = android.FirstUniqueFunc(depPaths.RustRlibDeps, EqRustRlibDeps)
+
depPaths.ReexportedDirs = android.FirstUniquePaths(depPaths.ReexportedDirs)
depPaths.ReexportedSystemDirs = android.FirstUniquePaths(depPaths.ReexportedSystemDirs)
depPaths.ReexportedFlags = android.FirstUniqueStrings(depPaths.ReexportedFlags)
depPaths.ReexportedDeps = android.FirstUniquePaths(depPaths.ReexportedDeps)
depPaths.ReexportedGeneratedHeaders = android.FirstUniquePaths(depPaths.ReexportedGeneratedHeaders)
+ depPaths.ReexportedRustRlibDeps = android.FirstUniqueFunc(depPaths.ReexportedRustRlibDeps, EqRustRlibDeps)
if c.sabi != nil {
c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes)