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/rust/library_test.go b/rust/library_test.go
index 7275b66..1133c28 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -37,9 +37,10 @@
}`)
// Test all variants are being built.
+ libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Rule("rustc")
libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
- libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Rule("rustc")
+ libfooFFIRlib := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Rule("rustc")
rlibCrateType := "rlib"
@@ -62,6 +63,11 @@
t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.Args["rustcFlags"])
}
+ // Test crate type for FFI rlibs is correct
+ if !strings.Contains(libfooFFIRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) {
+ t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooFFIRlib.Args["rustcFlags"])
+ }
+
// Test crate type for C shared libraries is correct.
if !strings.Contains(libfooShared.Args["rustcFlags"], "crate-type="+sharedCrateType) {
t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.Args["rustcFlags"])
@@ -182,15 +188,20 @@
func TestStaticLibraryLinkage(t *testing.T) {
ctx := testRust(t, `
- rust_ffi_static {
+ rust_ffi {
name: "libfoo",
srcs: ["foo.rs"],
crate_name: "foo",
}`)
- libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_rlib-std")
+ libfooStatic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) {
+ t.Errorf("Static libstd rlib expected to be a dependency of Rust rlib libraries. Rlib deps are: %#v",
+ libfoo.Module().(*Module).Properties.AndroidMkDylibs)
+ }
+ if !android.InList("libstd", libfooStatic.Module().(*Module).Properties.AndroidMkRlibs) {
t.Errorf("Static libstd rlib expected to be a dependency of Rust static libraries. Rlib deps are: %#v",
libfoo.Module().(*Module).Properties.AndroidMkDylibs)
}
@@ -198,6 +209,12 @@
func TestNativeDependencyOfRlib(t *testing.T) {
ctx := testRust(t, `
+ rust_ffi_rlib {
+ name: "libffi_rlib",
+ crate_name: "ffi_rlib",
+ rlibs: ["librust_rlib"],
+ srcs: ["foo.rs"],
+ }
rust_ffi_static {
name: "libffi_static",
crate_name: "ffi_static",
@@ -224,10 +241,12 @@
rustRlibRlibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_rlib-std")
rustRlibDylibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_dylib-std")
ffiStatic := ctx.ModuleForTests("libffi_static", "android_arm64_armv8-a_static")
+ ffiRlib := ctx.ModuleForTests("libffi_rlib", "android_arm64_armv8-a_rlib_rlib-std")
modules := []android.TestingModule{
rustRlibRlibStd,
rustRlibDylibStd,
+ ffiRlib,
ffiStatic,
}
@@ -290,27 +309,28 @@
libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std")
libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib")
+ libfooFFIRlib := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_rlib_rlib-std")
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} {
+ for _, static := range []android.TestingModule{libfooRlib, libfooStatic, libfooFFIRlib} {
if !android.InList("libbar.rlib-std", static.Module().(*Module).Properties.AndroidMkRlibs) {
- t.Errorf("libbar not present as rlib dependency in static lib")
+ t.Errorf("libbar not present as rlib dependency in static lib: %s", static.Module().Name())
}
if android.InList("libbar", static.Module().(*Module).Properties.AndroidMkDylibs) {
- t.Errorf("libbar present as dynamic dependency in static lib")
+ t.Errorf("libbar present as dynamic dependency in static lib: %s", static.Module().Name())
}
}
for _, dyn := range []android.TestingModule{libfooDylib, libfooShared} {
if !android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkDylibs) {
- t.Errorf("libbar not present as dynamic dependency in dynamic lib")
+ t.Errorf("libbar not present as dynamic dependency in dynamic lib: %s", dyn.Module().Name())
}
if android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
- t.Errorf("libbar present as rlib dependency in dynamic lib")
+ t.Errorf("libbar present as rlib dependency in dynamic lib: %s", dyn.Module().Name())
}
if !android.InList("librlib_only", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
- t.Errorf("librlib_only should be selected by rustlibs as an rlib.")
+ t.Errorf("librlib_only should be selected by rustlibs as an rlib: %s.", dyn.Module().Name())
}
}
}
@@ -375,6 +395,7 @@
libbarShared := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module().(*Module)
libbarStatic := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module().(*Module)
+ libbarFFIRlib := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module)
// prefer_rlib works the same for both rust_library and rust_ffi, so a single check is sufficient here.
libbarRlibStd := ctx.ModuleForTests("libbar.prefer_rlib", "android_arm64_armv8-a_shared").Module().(*Module)
@@ -398,6 +419,12 @@
if !android.InList("libfoo.rlib-std", libbarStatic.Properties.AndroidMkRlibs) {
t.Errorf("Device rust_ffi_static does not link dependent rustlib rlib-std variant")
}
+ if !android.InList("libstd", libbarFFIRlib.Properties.AndroidMkRlibs) {
+ t.Errorf("Device rust_ffi_rlib does not link libstd as an rlib")
+ }
+ if !android.InList("libfoo.rlib-std", libbarFFIRlib.Properties.AndroidMkRlibs) {
+ t.Errorf("Device rust_ffi_rlib does not link dependent rustlib rlib-std variant")
+ }
if !android.InList("libstd", libbarRlibStd.Properties.AndroidMkRlibs) {
t.Errorf("rust_ffi with prefer_rlib does not link libstd as an rlib")
}