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/rust_test.go b/rust/rust_test.go
index 6d083f6..8b96df8 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -150,15 +150,11 @@
host_supported: true,
name: "cc_stubs_dep",
}
- rust_ffi_host_static {
+ cc_library_host_static {
name: "libstatic",
- srcs: ["foo.rs"],
- crate_name: "static",
}
- rust_ffi_host_static {
+ cc_library_host_static {
name: "libwholestatic",
- srcs: ["foo.rs"],
- crate_name: "wholestatic",
}
rust_ffi_host_shared {
name: "libshared",
@@ -435,6 +431,105 @@
}
}
+func TestRustRlibs(t *testing.T) {
+ ctx := testRust(t, `
+ rust_ffi_rlib {
+ name: "libbar",
+ crate_name: "bar",
+ srcs: ["src/lib.rs"],
+ export_include_dirs: ["bar_includes"]
+ }
+
+ rust_ffi_rlib {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["src/lib.rs"],
+ export_include_dirs: ["foo_includes"]
+ }
+
+ cc_library_shared {
+ name: "libcc_shared",
+ srcs:["foo.c"],
+ static_rlibs: ["libbar"],
+ }
+
+ cc_library_static {
+ name: "libcc_static",
+ srcs:["foo.c"],
+ static_rlibs: ["libfoo"],
+ }
+
+ cc_binary {
+ name: "ccBin",
+ srcs:["foo.c"],
+ static_rlibs: ["libbar"],
+ static_libs: ["libcc_static"],
+ }
+ `)
+
+ libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_rlib_rlib-std").Rule("rustc")
+ libcc_shared_rustc := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("rustc")
+ libcc_shared_ld := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("ld")
+ libcc_shared_cc := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("cc")
+ ccbin_rustc := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("rustc")
+ ccbin_ld := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("ld")
+ ccbin_cc := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("cc")
+
+ if !strings.Contains(libbar.Args["rustcFlags"], "crate-type=rlib") {
+ t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", "rlib", libbar.Args["rustcFlags"])
+ }
+
+ // Make sure there's a rustc command, and it's producing a staticlib
+ if !strings.Contains(libcc_shared_rustc.Args["rustcFlags"], "crate-type=staticlib") {
+ t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v",
+ "staticlib", libcc_shared_rustc.Args["rustcFlags"])
+ }
+
+ // Make sure the static lib is included in the ld command
+ if !strings.Contains(libcc_shared_ld.Args["libFlags"], "generated_rust_staticlib/liblibcc_shared_rust_staticlib.a") {
+ t.Errorf("missing generated static library in linker step libFlags %#v, libFlags: %#v",
+ "libcc_shared.generated_rust_staticlib.a", libcc_shared_ld.Args["libFlags"])
+ }
+
+ // Make sure the static lib includes are in the cc command
+ if !strings.Contains(libcc_shared_cc.Args["cFlags"], "-Ibar_includes") {
+ t.Errorf("missing rlibs includes, expecting %#v, cFlags: %#v",
+ "-Ibar_includes", libcc_shared_cc.Args["cFlags"])
+ }
+
+ // Make sure there's a rustc command, and it's producing a staticlib
+ if !strings.Contains(ccbin_rustc.Args["rustcFlags"], "crate-type=staticlib") {
+ t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", "staticlib", ccbin_rustc.Args["rustcFlags"])
+ }
+
+ // Make sure the static lib is included in the cc command
+ if !strings.Contains(ccbin_ld.Args["libFlags"], "generated_rust_staticlib/libccBin_rust_staticlib.a") {
+ t.Errorf("missing generated static library in linker step libFlags, expecting %#v, libFlags: %#v",
+ "ccBin.generated_rust_staticlib.a", ccbin_ld.Args["libFlags"])
+ }
+
+ // Make sure the static lib includes are in the ld command
+ if !strings.Contains(ccbin_cc.Args["cFlags"], "-Ibar_includes") {
+ t.Errorf("missing rlibs includes, expecting %#v, cFlags: %#v",
+ "-Ibar_includes", ccbin_cc.Args)
+ }
+
+ // Make sure that direct dependencies and indirect dependencies are
+ // propagating correctly to the generated rlib.
+ if !strings.Contains(ccbin_rustc.Args["libFlags"], "--extern foo=") {
+ t.Errorf("Missing indirect dependency libfoo when writing generated Rust staticlib: %#v", ccbin_rustc.Args["libFlags"])
+ }
+ if !strings.Contains(ccbin_rustc.Args["libFlags"], "--extern bar=") {
+ t.Errorf("Missing direct dependency libbar when writing generated Rust staticlib: %#v", ccbin_rustc.Args["libFlags"])
+ }
+
+ // Test indirect includes propagation
+ if !strings.Contains(ccbin_cc.Args["cFlags"], "-Ifoo_includes") {
+ t.Errorf("missing rlibs includes, expecting %#v, cFlags: %#v",
+ "-Ifoo_includes", ccbin_cc.Args)
+ }
+}
+
func assertString(t *testing.T, got, expected string) {
t.Helper()
if got != expected {