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
This commit is contained in:
Ivan Lozano
2024-05-13 21:03:34 -04:00
parent 28ed8f4f83
commit 0a468a4f3b
22 changed files with 643 additions and 127 deletions

View File

@@ -19,6 +19,7 @@ package cc
// functions.
import (
"fmt"
"path/filepath"
"runtime"
"strconv"
@@ -330,6 +331,15 @@ var (
CommandDeps: []string{"$cxxExtractor", "$kytheVnames"},
},
"cFlags")
// Function pointer for producting staticlibs from rlibs. Corresponds to
// rust.TransformRlibstoStaticlib(), initialized in soong-rust (rust/builder.go init())
//
// This is required since soong-rust depends on soong-cc, so soong-cc cannot depend on soong-rust
// without resulting in a circular dependency. Setting this function pointer in soong-rust allows
// soong-cc to call into this particular function.
TransformRlibstoStaticlib (func(ctx android.ModuleContext, mainSrc android.Path, deps []RustRlibDep,
outputFile android.WritablePath) android.Path) = nil
)
func PwdPrefix() string {
@@ -774,6 +784,47 @@ func transformObjToStaticLib(ctx android.ModuleContext,
}
}
// 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
// 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()))
} else if len(rlibDeps) == 0 {
return nil
}
output := android.PathForModuleOut(ctx, "generated_rust_staticlib", "lib"+ctx.ModuleName()+"_rust_staticlib.a")
stemFile := output.ReplaceExtension(ctx, "rs")
crateNames := []string{}
// Collect crate names
for _, lib := range rlibDeps {
// Exclude libstd so this can support no_std builds.
if lib.CrateName != "libstd" {
crateNames = append(crateNames, lib.CrateName)
}
}
// Deduplicate any crateNames just to be safe
crateNames = android.FirstUniqueStrings(crateNames)
// Write the source file
android.WriteFileRule(ctx, stemFile, genRustStaticlibSrcFile(crateNames))
return TransformRlibstoStaticlib(ctx, stemFile, rlibDeps, output)
}
func genRustStaticlibSrcFile(crateNames []string) string {
lines := []string{
"// @Soong generated Source",
}
for _, crate := range crateNames {
lines = append(lines, fmt.Sprintf("extern crate %s;", crate))
}
return strings.Join(lines, "\n")
}
// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
// and shared libraries, to a shared library (.so) or dynamic executable
func transformObjToDynamicBinary(ctx android.ModuleContext,