rust: Add stub support for rust_ffi modules
This adds stubs support for rust_ffi and rust_ffi_shared modules. Usage
should match current cc usage. The stubs generator leveraged is the cc
stubs generator.
Bug: 203478530
Test: m blueprint_tests
Change-Id: I043b9714a357cd5fe17c183ccdf86900f5172e0e
diff --git a/apex/apex_test.go b/apex/apex_test.go
index e1a9582..6796fca 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -897,7 +897,11 @@
apex {
name: "myapex",
key: "myapex.key",
- native_shared_libs: ["mylib", "mylib3"],
+ native_shared_libs: [
+ "mylib",
+ "mylib3",
+ "libmylib3_rs",
+ ],
binaries: ["foo.rust"],
updatable: false,
}
@@ -911,7 +915,14 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["mylib2", "mylib3#impl", "my_prebuilt_platform_lib", "my_prebuilt_platform_stub_only_lib"],
+ shared_libs: [
+ "mylib2",
+ "mylib3#impl",
+ "libmylib2_rs",
+ "libmylib3_rs#impl",
+ "my_prebuilt_platform_lib",
+ "my_prebuilt_platform_stub_only_lib",
+ ],
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
@@ -929,6 +940,16 @@
},
}
+ rust_ffi {
+ name: "libmylib2_rs",
+ crate_name: "mylib2",
+ srcs: ["mylib.rs"],
+ stubs: {
+ symbol_file: "mylib2.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ }
+
cc_library {
name: "mylib3",
srcs: ["mylib.cpp"],
@@ -942,6 +963,18 @@
apex_available: [ "myapex" ],
}
+ rust_ffi {
+ name: "libmylib3_rs",
+ crate_name: "mylib3",
+ srcs: ["mylib.rs"],
+ shared_libs: ["mylib4.from_rust"],
+ stubs: {
+ symbol_file: "mylib3.map.txt",
+ versions: ["10", "11", "12"],
+ },
+ apex_available: [ "myapex" ],
+ }
+
cc_library {
name: "mylib4",
srcs: ["mylib.cpp"],
@@ -950,6 +983,14 @@
apex_available: [ "myapex" ],
}
+ cc_library {
+ name: "mylib4.from_rust",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
cc_prebuilt_library_shared {
name: "my_prebuilt_platform_lib",
stubs: {
@@ -971,7 +1012,10 @@
rust_binary {
name: "foo.rust",
srcs: ["foo.rs"],
- shared_libs: ["libfoo.shared_from_rust"],
+ shared_libs: [
+ "libfoo.shared_from_rust",
+ "libfoo_rs.shared_from_rust",
+ ],
prefer_rlib: true,
apex_available: ["myapex"],
}
@@ -986,6 +1030,15 @@
},
}
+ rust_ffi {
+ name: "libfoo_rs.shared_from_rust",
+ crate_name: "foo_rs",
+ srcs: ["mylib.rs"],
+ stubs: {
+ versions: ["10", "11", "12"],
+ },
+ }
+
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
@@ -996,21 +1049,27 @@
// Ensure that indirect stubs dep is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libmylib2_rs.so")
// Ensure that direct stubs dep is included
ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libmylib3_rs.so")
mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
// Ensure that mylib is linking with the latest version of stubs for mylib2
ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
+ ensureContains(t, mylibLdFlags, "libmylib2_rs/android_arm64_armv8-a_shared_current/unstripped/libmylib2_rs.so")
// ... and not linking to the non-stub (impl) variant of mylib2
ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
+ ensureNotContains(t, mylibLdFlags, "libmylib2_rs/android_arm64_armv8-a_shared/unstripped/libmylib2_rs.so")
// Ensure that mylib is linking with the non-stub (impl) of mylib3 (because the dependency is added with mylib3#impl)
ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex10000/mylib3.so")
+ ensureContains(t, mylibLdFlags, "libmylib3_rs/android_arm64_armv8-a_shared_apex10000/unstripped/libmylib3_rs.so")
// .. and not linking to the stubs variant of mylib3
ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12/mylib3.so")
+ ensureNotContains(t, mylibLdFlags, "libmylib3_rs/android_arm64_armv8-a_shared_12/unstripped/mylib3.so")
// Comment out this test. Now it fails after the optimization of sharing "cflags" in cc/cc.go
// is replaced by sharing of "cFlags" in cc/builder.go.
@@ -1026,27 +1085,35 @@
// Ensure that genstub for platform-provided lib is invoked with --systemapi
ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi")
+ ensureContains(t, ctx.ModuleForTests("libmylib2_rs", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi")
// Ensure that genstub for apex-provided lib is invoked with --apex
ensureContains(t, ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex")
+ ensureContains(t, ctx.ModuleForTests("libmylib3_rs", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex")
ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
"lib64/mylib.so",
"lib64/mylib3.so",
+ "lib64/libmylib3_rs.so",
"lib64/mylib4.so",
+ "lib64/mylib4.from_rust.so",
"bin/foo.rust",
- "lib64/libc++.so", // by the implicit dependency from foo.rust
- "lib64/liblog.so", // by the implicit dependency from foo.rust
+
+ "lib64/libstd.dylib.so", // implicit rust ffi dep
})
// Ensure that stub dependency from a rust module is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo_rs.shared_from_rust.so")
// The rust module is linked to the stub cc library
rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
+ ensureContains(t, rustDeps, "libfoo_rs.shared_from_rust/android_arm64_armv8-a_shared_current/unstripped/libfoo_rs.shared_from_rust.so")
ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
+ ensureNotContains(t, rustDeps, "libfoo_rs.shared_from_rust/android_arm64_armv8-a_shared/unstripped/libfoo_rs.shared_from_rust.so")
apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.shared_from_rust.so")
+ ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo_rs.shared_from_rust.so")
// Ensure that mylib is linking with the latest version of stubs for my_prebuilt_platform_lib
ensureContains(t, mylibLdFlags, "my_prebuilt_platform_lib/android_arm64_armv8-a_shared_current/my_prebuilt_platform_lib.so")
@@ -1111,7 +1178,10 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["mylib2"],
+ shared_libs: [
+ "mylib2",
+ "libmylib2_rust"
+ ],
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
@@ -1128,10 +1198,22 @@
},
}
+ rust_ffi {
+ name: "libmylib2_rust",
+ crate_name: "mylib2_rust",
+ srcs: ["mylib.rs"],
+ stubs: {
+ versions: ["1", "2", "3"],
+ },
+ }
+
rust_binary {
name: "foo.rust",
srcs: ["foo.rs"],
- shared_libs: ["libfoo.shared_from_rust"],
+ shared_libs: [
+ "libfoo.shared_from_rust",
+ "libmylib_rust.shared_from_rust"
+ ],
prefer_rlib: true,
apex_available: ["myapex"],
}
@@ -1145,6 +1227,15 @@
versions: ["10", "11", "12"],
},
}
+ rust_ffi {
+ name: "libmylib_rust.shared_from_rust",
+ crate_name: "mylib_rust",
+ srcs: ["mylib.rs"],
+ stubs: {
+ versions: ["1", "2", "3"],
+ },
+ }
+
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
@@ -1152,6 +1243,8 @@
// Ensure that indirect stubs dep is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libmylib_rust.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libmylib_rust.shared_from_rust.so")
ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
// Ensure that we are using non-stub variants of mylib2 and libfoo.shared_from_rust (because
@@ -1159,9 +1252,13 @@
mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
+ ensureNotContains(t, mylibLdFlags, "libmylib2_rust/android_arm64_armv8-a_shared_current/unstripped/libmylib2_rust.so")
+ ensureContains(t, mylibLdFlags, "libmylib2_rust/android_arm64_armv8-a_shared/unstripped/libmylib2_rust.so")
rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
+ ensureNotContains(t, rustDeps, "libmylib_rust.shared_from_rust/android_arm64_armv8-a_shared_current/unstripped/libmylib_rust.shared_from_rust.so")
+ ensureContains(t, rustDeps, "libmylib_rust.shared_from_rust/android_arm64_armv8-a_shared/unstripped/libmylib_rust.shared_from_rust.so")
}
func TestApexWithStubsWithMinSdkVersion(t *testing.T) {
@@ -1170,7 +1267,11 @@
apex {
name: "myapex",
key: "myapex.key",
- native_shared_libs: ["mylib", "mylib3"],
+ native_shared_libs: [
+ "mylib",
+ "mylib3",
+ "libmylib3_rust",
+ ],
min_sdk_version: "29",
}
@@ -1183,7 +1284,12 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["mylib2", "mylib3#impl"],
+ shared_libs: [
+ "mylib2",
+ "mylib3#impl",
+ "libmylib2_rust",
+ "libmylib3_rust#impl",
+ ],
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
@@ -1203,6 +1309,17 @@
min_sdk_version: "28",
}
+ rust_ffi {
+ name: "libmylib2_rust",
+ crate_name: "mylib2_rust",
+ srcs: ["mylib.rs"],
+ stubs: {
+ symbol_file: "mylib2.map.txt",
+ versions: ["28", "29", "30", "current"],
+ },
+ min_sdk_version: "28",
+ }
+
cc_library {
name: "mylib3",
srcs: ["mylib.cpp"],
@@ -1217,6 +1334,19 @@
min_sdk_version: "28",
}
+ rust_ffi {
+ name: "libmylib3_rust",
+ crate_name: "mylib3_rust",
+ srcs: ["mylib.rs"],
+ shared_libs: ["libmylib4.from_rust"],
+ stubs: {
+ symbol_file: "mylib3.map.txt",
+ versions: ["28", "29", "30", "current"],
+ },
+ apex_available: [ "myapex" ],
+ min_sdk_version: "28",
+ }
+
cc_library {
name: "mylib4",
srcs: ["mylib.cpp"],
@@ -1225,6 +1355,14 @@
apex_available: [ "myapex" ],
min_sdk_version: "28",
}
+
+ rust_ffi {
+ name: "libmylib4.from_rust",
+ crate_name: "mylib4",
+ srcs: ["mylib.rs"],
+ apex_available: [ "myapex" ],
+ min_sdk_version: "28",
+ }
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
@@ -1232,9 +1370,12 @@
// Ensure that direct non-stubs dep is always included
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libmylib3_rust.so")
// Ensure that indirect stubs dep is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libmylib2_rust.so")
// Ensure that direct stubs dep is included
ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so")
@@ -1243,13 +1384,17 @@
// Ensure that mylib is linking with the latest version of stub for mylib2
ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
+ ensureContains(t, mylibLdFlags, "libmylib2_rust/android_arm64_armv8-a_shared_current/unstripped/libmylib2_rust.so")
// ... and not linking to the non-stub (impl) variant of mylib2
ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
+ ensureNotContains(t, mylibLdFlags, "libmylib2_rust/android_arm64_armv8-a_shared/unstripped/libmylib2_rust.so")
// Ensure that mylib is linking with the non-stub (impl) of mylib3 (because the dependency is added with mylib3#impl)
ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex29/mylib3.so")
+ ensureContains(t, mylibLdFlags, "libmylib3_rust/android_arm64_armv8-a_shared_apex29/unstripped/libmylib3_rust.so")
// .. and not linking to the stubs variant of mylib3
ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_29/mylib3.so")
+ ensureNotContains(t, mylibLdFlags, "libmylib3_rust/android_arm64_armv8-a_shared_29/unstripped/libmylib3_rust.so")
// Ensure that stubs libs are built without -include flags
mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("cc").Args["cFlags"]
@@ -1257,11 +1402,16 @@
// Ensure that genstub is invoked with --systemapi
ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"], "--systemapi")
+ ensureContains(t, ctx.ModuleForTests("libmylib2_rust", "android_arm64_armv8-a_shared_29").Rule("cc.genStubSrc").Args["flags"], "--systemapi")
ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
"lib64/mylib.so",
"lib64/mylib3.so",
+ "lib64/libmylib3_rust.so",
"lib64/mylib4.so",
+ "lib64/libmylib4.from_rust.so",
+
+ "lib64/libstd.dylib.so", // by the implicit dependency from foo.rust
})
}
@@ -1286,7 +1436,10 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["libstub"],
+ shared_libs: [
+ "libstub",
+ "libstub_rust",
+ ],
apex_available: ["myapex"],
min_sdk_version: "Z",
}
@@ -1300,7 +1453,10 @@
apex {
name: "otherapex",
key: "myapex.key",
- native_shared_libs: ["libstub"],
+ native_shared_libs: [
+ "libstub",
+ "libstub_rust",
+ ],
min_sdk_version: "29",
}
@@ -1314,11 +1470,25 @@
min_sdk_version: "29",
}
+ rust_ffi {
+ name: "libstub_rust",
+ crate_name: "stub_rust",
+ srcs: ["mylib.rs"],
+ stubs: {
+ versions: ["29", "Z", "current"],
+ },
+ apex_available: ["otherapex"],
+ min_sdk_version: "29",
+ }
+
// platform module depending on libstub from otherapex should use the latest stub("current")
cc_library {
name: "libplatform",
srcs: ["mylib.cpp"],
- shared_libs: ["libstub"],
+ shared_libs: [
+ "libstub",
+ "libstub_rust",
+ ],
}
`,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -1331,14 +1501,20 @@
// Ensure that mylib from myapex is built against the latest stub (current)
mylibCflags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCflags, "-D__LIBSTUB_API__=10000 ")
+ // rust stubs do not emit -D__LIBFOO_API__ flags as this is deprecated behavior for cc stubs
+
mylibLdflags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
ensureContains(t, mylibLdflags, "libstub/android_arm64_armv8-a_shared_current/libstub.so ")
+ ensureContains(t, mylibLdflags, "libstub_rust/android_arm64_armv8-a_shared_current/unstripped/libstub_rust.so ")
// Ensure that libplatform is built against latest stub ("current") of mylib3 from the apex
libplatformCflags := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
ensureContains(t, libplatformCflags, "-D__LIBSTUB_API__=10000 ") // "current" maps to 10000
+ // rust stubs do not emit -D__LIBFOO_API__ flags as this is deprecated behavior for cc stubs
+
libplatformLdflags := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"]
ensureContains(t, libplatformLdflags, "libstub/android_arm64_armv8-a_shared_current/libstub.so ")
+ ensureContains(t, libplatformLdflags, "libstub_rust/android_arm64_armv8-a_shared_current/unstripped/libstub_rust.so ")
}
func TestApexWithExplicitStubsDependency(t *testing.T) {
@@ -1360,7 +1536,10 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["libfoo#10"],
+ shared_libs: [
+ "libfoo#10",
+ "libfoo_rust#10"
+ ],
static_libs: ["libbaz"],
system_shared_libs: [],
stl: "none",
@@ -1378,6 +1557,16 @@
},
}
+ rust_ffi {
+ name: "libfoo_rust",
+ crate_name: "foo_rust",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["libbar.from_rust"],
+ stubs: {
+ versions: ["10", "20", "30"],
+ },
+ }
+
cc_library {
name: "libbar",
srcs: ["mylib.cpp"],
@@ -1385,6 +1574,13 @@
stl: "none",
}
+ cc_library {
+ name: "libbar.from_rust",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
cc_library_static {
name: "libbaz",
srcs: ["mylib.cpp"],
@@ -1403,21 +1599,27 @@
// Ensure that indirect stubs dep is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo_rust.so")
// Ensure that dependency of stubs is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.from_rust.so")
mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
// Ensure that mylib is linking with version 10 of libfoo
ensureContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_10/libfoo.so")
+ ensureContains(t, mylibLdFlags, "libfoo_rust/android_arm64_armv8-a_shared_10/unstripped/libfoo_rust.so")
// ... and not linking to the non-stub (impl) variant of libfoo
ensureNotContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared/libfoo.so")
+ ensureNotContains(t, mylibLdFlags, "libfoo_rust/android_arm64_armv8-a_shared/unstripped/libfoo_rust.so")
libFooStubsLdFlags := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_10").Rule("ld").Args["libFlags"]
+ libFooRustStubsLdFlags := ctx.ModuleForTests("libfoo_rust", "android_arm64_armv8-a_shared_10").Rule("ld").Args["libFlags"]
// Ensure that libfoo stubs is not linking to libbar (since it is a stubs)
ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
+ ensureNotContains(t, libFooRustStubsLdFlags, "libbar.from_rust.so")
fullDepsInfo := strings.Split(android.ContentFromFileRuleForTests(t, ctx,
ctx.ModuleForTests("myapex2", "android_common_myapex2").Output("depsinfo/fulllist.txt")), "\n")
@@ -1457,7 +1659,11 @@
srcs: ["mylib.cpp"],
static_libs: ["libstatic"],
shared_libs: ["libshared"],
- runtime_libs: ["libfoo", "libbar"],
+ runtime_libs: [
+ "libfoo",
+ "libbar",
+ "libfoo_rs",
+ ],
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
@@ -1473,6 +1679,15 @@
},
}
+ rust_ffi {
+ name: "libfoo_rs",
+ crate_name: "foo_rs",
+ srcs: ["mylib.rs"],
+ stubs: {
+ versions: ["10", "20", "30"],
+ },
+ }
+
cc_library {
name: "libbar",
srcs: ["mylib.cpp"],
@@ -1524,6 +1739,7 @@
// Ensure that indirect stubs dep is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo_rs.so")
// Ensure that runtime_libs dep in included
ensureContains(t, copyCmds, "image.apex/lib64/libbar.so")
@@ -1535,6 +1751,7 @@
apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so")
+ ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo_rs.so")
}
var prepareForTestOfRuntimeApexWithHwasan = android.GroupFixturePreparers(
@@ -1766,7 +1983,7 @@
apex {
name: "myapex",
key: "myapex.key",
- native_shared_libs: ["mylib", "mylib_shared", "libdl", "libm"],
+ native_shared_libs: ["mylib", "mylib_shared", "libdl", "libm", "libmylib_rs"],
updatable: false,
}
@@ -1785,6 +2002,14 @@
apex_available: [ "myapex" ],
}
+ rust_ffi {
+ name: "libmylib_rs",
+ crate_name: "mylib_rs",
+ shared_libs: ["libvers#27", "libm#impl"],
+ srcs: ["mylib.rs"],
+ apex_available: [ "myapex" ],
+ }
+
cc_library_shared {
name: "mylib_shared",
srcs: ["mylib.cpp"],
@@ -1799,20 +2024,38 @@
stl: "none",
bootstrap: true,
}
+
+ rust_ffi {
+ name: "libbootstrap_rs",
+ srcs: ["mylib.cpp"],
+ crate_name: "bootstrap_rs",
+ bootstrap: true,
+ }
+
+ cc_library {
+ name: "libvers",
+ srcs: ["mylib.cpp"],
+ stl: "none",
+ stubs: { versions: ["27","30"] },
+ }
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
copyCmds := apexRule.Args["copy_commands"]
- // Ensure that mylib, libm, libdl are included.
+ // Ensure that mylib, libmylib_rs, libm, libdl, libstd.dylib.so (from Rust) are included.
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libmylib_rs.so")
ensureContains(t, copyCmds, "image.apex/lib64/bionic/libm.so")
ensureContains(t, copyCmds, "image.apex/lib64/bionic/libdl.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libstd.dylib.so")
- // Ensure that libc is not included (since it has stubs and not listed in native_shared_libs)
+ // Ensure that libc and liblog (from Rust) is not included (since it has stubs and not listed in native_shared_libs)
ensureNotContains(t, copyCmds, "image.apex/lib64/bionic/libc.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/liblog.so")
mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
+ mylibRsFlags := ctx.ModuleForTests("libmylib_rs", "android_arm64_armv8-a_shared_apex10000").Rule("rustc").Args["linkFlags"]
mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"]
mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_apex10000").Rule("cc").Args["cFlags"]
@@ -1846,11 +2089,42 @@
ensureContains(t, mylibCFlags, "__LIBDL_API__=27")
ensureContains(t, mylibSharedCFlags, "__LIBDL_API__=27")
+ // Rust checks
+ // For dependency to libc, liblog
+ // Ensure that libmylib_rs is linking with the latest versions of stubs
+ ensureContains(t, mylibRsFlags, "libc/android_arm64_armv8-a_shared_current/libc.so")
+ ensureContains(t, mylibRsFlags, "liblog/android_arm64_armv8-a_shared_current/liblog.so")
+ // ... and not linking to the non-stub (impl) variants
+ ensureNotContains(t, mylibRsFlags, "libc/android_arm64_armv8-a_shared/libc.so")
+ ensureNotContains(t, mylibRsFlags, "liblog/android_arm64_armv8-a_shared/liblog.so")
+
+ // For libm dependency (explicit)
+ // Ensure that mylib is linking with the non-stub (impl) variant
+ ensureContains(t, mylibRsFlags, "libm/android_arm64_armv8-a_shared_apex10000/libm.so")
+ // ... and not linking to the stub variant
+ ensureNotContains(t, mylibRsFlags, "libm/android_arm64_armv8-a_shared_29/libm.so")
+
+ // For dependency to libvers
+ // (We do not use libdl#27 as Rust links the system libs implicitly and does
+ // not currently have a system_shared_libs equivalent to prevent this)
+ // Ensure that mylib is linking with the specified version of stubs
+ ensureContains(t, mylibRsFlags, "libvers/android_arm64_armv8-a_shared_27/libvers.so")
+ // ... and not linking to the other versions of stubs
+ ensureNotContains(t, mylibRsFlags, "libvers/android_arm64_armv8-a_shared_30/libvers.so")
+ // ... and not linking to the non-stub (impl) variant
+ ensureNotContains(t, mylibRsFlags, "libvers/android_arm64_armv8-a_shared_apex10000/libvers.so")
+
// Ensure that libBootstrap is depending on the platform variant of bionic libs
libFlags := ctx.ModuleForTests("libBootstrap", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"]
ensureContains(t, libFlags, "libc/android_arm64_armv8-a_shared/libc.so")
ensureContains(t, libFlags, "libm/android_arm64_armv8-a_shared/libm.so")
ensureContains(t, libFlags, "libdl/android_arm64_armv8-a_shared/libdl.so")
+
+ // Ensure that libbootstrap_rs is depending on the platform variant of bionic libs
+ libRsFlags := ctx.ModuleForTests("libbootstrap_rs", "android_arm64_armv8-a_shared").Rule("rustc").Args["linkFlags"]
+ ensureContains(t, libRsFlags, "libc/android_arm64_armv8-a_shared/libc.so")
+ ensureContains(t, libRsFlags, "libm/android_arm64_armv8-a_shared/libm.so")
+ ensureContains(t, libRsFlags, "libdl/android_arm64_armv8-a_shared/libdl.so")
}
func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) {
@@ -1900,7 +2174,7 @@
cc_library {
name: "liba",
- shared_libs: ["libz"],
+ shared_libs: ["libz", "libz_rs"],
system_shared_libs: [],
stl: "none",
apex_available: [
@@ -1918,6 +2192,15 @@
versions: ["28", "30"],
},
}
+
+ rust_ffi {
+ name: "libz_rs",
+ crate_name: "z_rs",
+ srcs: ["foo.rs"],
+ stubs: {
+ versions: ["28", "30"],
+ },
+ }
`)
expectLink := func(from, from_variant, to, to_variant string) {
@@ -1930,16 +2213,25 @@
}
// platform liba is linked to non-stub version
expectLink("liba", "shared", "libz", "shared")
+ expectLink("liba", "shared", "unstripped/libz_rs", "shared")
// liba in myapex is linked to current
expectLink("liba", "shared_apex29", "libz", "shared_current")
expectNoLink("liba", "shared_apex29", "libz", "shared_30")
expectNoLink("liba", "shared_apex29", "libz", "shared_28")
expectNoLink("liba", "shared_apex29", "libz", "shared")
+ expectLink("liba", "shared_apex29", "unstripped/libz_rs", "shared_current")
+ expectNoLink("liba", "shared_apex29", "unstripped/libz_rs", "shared_30")
+ expectNoLink("liba", "shared_apex29", "unstripped/libz_rs", "shared_28")
+ expectNoLink("liba", "shared_apex29", "unstripped/libz_rs", "shared")
// liba in otherapex is linked to current
expectLink("liba", "shared_apex30", "libz", "shared_current")
expectNoLink("liba", "shared_apex30", "libz", "shared_30")
expectNoLink("liba", "shared_apex30", "libz", "shared_28")
expectNoLink("liba", "shared_apex30", "libz", "shared")
+ expectLink("liba", "shared_apex30", "unstripped/libz_rs", "shared_current")
+ expectNoLink("liba", "shared_apex30", "unstripped/libz_rs", "shared_30")
+ expectNoLink("liba", "shared_apex30", "unstripped/libz_rs", "shared_28")
+ expectNoLink("liba", "shared_apex30", "unstripped/libz_rs", "shared")
}
func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) {
@@ -2159,7 +2451,7 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["libbar"],
+ shared_libs: ["libbar", "libbar_rs"],
min_sdk_version: "29",
apex_available: ["myapex"],
}
@@ -2169,6 +2461,13 @@
stubs: { versions: ["29", "30"] },
}
+ rust_ffi {
+ name: "libbar_rs",
+ crate_name: "bar_rs",
+ srcs: ["bar.rs"],
+ stubs: { versions: ["29", "30"] },
+ }
+
cc_library {
name: "yourlib",
srcs: ["mylib.cpp"],
@@ -2191,6 +2490,8 @@
myapex.Output("depsinfo/flatlist.txt")), "\n")
android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
flatlist, "libbar(minSdkVersion:(no version)) (external)")
+ android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
+ flatlist, "libbar_rs(minSdkVersion:(no version)) (external)")
android.AssertStringListDoesNotContain(t, "do not track if not available for platform",
flatlist, "mylib:(minSdkVersion:29)")
android.AssertStringListContains(t, "track platform-available lib",
@@ -2227,7 +2528,7 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["libbar"],
+ shared_libs: ["libbar", "libbar_rs",],
min_sdk_version: "29",
apex_available: ["myapex"],
}
@@ -2237,6 +2538,13 @@
stubs: { versions: ["29", "30"] },
}
+ rust_ffi {
+ name: "libbar_rs",
+ crate_name: "bar_rs",
+ srcs: ["bar.rs"],
+ stubs: { versions: ["29", "30"] },
+ }
+
cc_library {
name: "yourlib",
srcs: ["mylib.cpp"],
@@ -2264,6 +2572,8 @@
myapex.Output("depsinfo/flatlist.txt")), "\n")
android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
flatlist, "libbar(minSdkVersion:(no version)) (external)")
+ android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
+ flatlist, "libbar_rs(minSdkVersion:(no version)) (external)")
android.AssertStringListDoesNotContain(t, "do not track if not available for platform",
flatlist, "mylib:(minSdkVersion:29)")
android.AssertStringListContains(t, "track platform-available lib",
@@ -2300,7 +2610,7 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["libbar"],
+ shared_libs: ["libbar", "libbar_rs"],
min_sdk_version: "29",
apex_available: ["myapex"],
}
@@ -2310,6 +2620,13 @@
stubs: { versions: ["29", "30"] },
}
+ rust_ffi {
+ name: "libbar_rs",
+ crate_name: "bar_rs",
+ srcs: ["bar.rs"],
+ stubs: { versions: ["29", "30"] },
+ }
+
cc_library {
name: "yourlib",
srcs: ["mylib.cpp"],
@@ -2338,6 +2655,8 @@
myapex.Output("depsinfo/flatlist.txt")), "\n")
android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
flatlist, "libbar(minSdkVersion:(no version)) (external)")
+ android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
+ flatlist, "libbar_rs(minSdkVersion:(no version)) (external)")
android.AssertStringListDoesNotContain(t, "do not track if not available for platform",
flatlist, "mylib:(minSdkVersion:29)")
android.AssertStringListContains(t, "track platform-available lib",
@@ -2372,7 +2691,7 @@
apex {
name: "myapex",
key: "myapex.key",
- native_shared_libs: ["libx"],
+ native_shared_libs: ["libx", "libx_rs"],
updatable: false,
}
@@ -2392,9 +2711,19 @@
},
}
+ rust_ffi {
+ name: "libx_rs",
+ crate_name: "x_rs",
+ srcs: ["x.rs"],
+ apex_available: [ "myapex" ],
+ stubs: {
+ versions: ["1", "2"],
+ },
+ }
+
cc_library {
name: "libz",
- shared_libs: ["libx"],
+ shared_libs: ["libx", "libx_rs",],
system_shared_libs: [],
stl: "none",
}
@@ -2412,6 +2741,8 @@
}
expectLink("libz", "shared", "libx", "shared_current")
expectNoLink("libz", "shared", "libx", "shared_2")
+ expectLink("libz", "shared", "unstripped/libx_rs", "shared_current")
+ expectNoLink("libz", "shared", "unstripped/libx_rs", "shared_2")
expectNoLink("libz", "shared", "libz", "shared_1")
expectNoLink("libz", "shared", "libz", "shared")
}
@@ -2440,11 +2771,18 @@
cc_library {
name: "libx",
- shared_libs: ["libbar"],
+ shared_libs: ["libbar", "libbar_rs"],
apex_available: [ "myapex" ],
min_sdk_version: "29",
}
+ rust_ffi {
+ name: "libbar_rs",
+ crate_name: "bar_rs",
+ srcs: ["bar.rs"],
+ stubs: { versions: ["29", "30"] },
+ }
+
cc_library {
name: "libbar",
stubs: {
@@ -2460,6 +2798,7 @@
ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
}
expectLink("libx", "shared_hwasan_apex29", "libbar", "shared_current")
+ expectLink("libx", "shared_hwasan_apex29", "unstripped/libbar_rs", "shared_current")
}
func TestQTargetApexUsesStaticUnwinder(t *testing.T) {
@@ -3404,10 +3743,20 @@
apex_available: ["myapex"],
}
+ rust_ffi {
+ name: "libmylib_rs",
+ crate_name: "mylib_rs",
+ srcs: ["mylib.rs"],
+ stubs: {
+ versions: ["1", "2", "3"],
+ },
+ apex_available: ["myapex"],
+ }
+
cc_binary {
name: "not_in_apex",
srcs: ["mylib.cpp"],
- static_libs: ["mylib"],
+ static_libs: ["mylib", "libmylib_rs"],
static_executable: true,
system_shared_libs: [],
stl: "none",
@@ -3418,6 +3767,7 @@
// Ensure that not_in_apex is linking with the static variant of mylib
ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_static/mylib.a")
+ ensureContains(t, ldFlags, "generated_rust_staticlib/librustlibs.a")
}
func TestKeys(t *testing.T) {
@@ -8217,8 +8567,6 @@
"lib64/mylib2.so",
"lib64/mylib3.so",
"lib64/libfoo.rust.so",
- "lib64/libc++.so", // auto-added to libfoo.rust by Soong
- "lib64/liblog.so", // auto-added to libfoo.rust by Soong
})
// b/220397949
@@ -10676,8 +11024,8 @@
mod := ctx.ModuleForTests("myapex", "android_common_myapex")
s := mod.Rule("apexRule").Args["copy_commands"]
copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
- if len(copyCmds) != 38 {
- t.Fatalf("Expected 38 commands, got %d in:\n%s", len(copyCmds), s)
+ if len(copyCmds) != 34 {
+ t.Fatalf("Expected 34 commands, got %d in:\n%s", len(copyCmds), s)
}
ensureListContainsMatch(t, copyCmds, "^cp -f .*/aconfig_flags.pb .*/image.apex/etc/aconfig_flags.pb")
diff --git a/cc/builder.go b/cc/builder.go
index 56b7139..5325116 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -851,6 +851,25 @@
return strings.Join(lines, "\n")
}
+func BuildRustStubs(ctx android.ModuleContext, outputFile android.ModuleOutPath,
+ crtBegin, crtEnd android.Paths, stubObjs Objects, ccFlags Flags) {
+
+ // Instantiate paths
+ sharedLibs := android.Paths{}
+ staticLibs := android.Paths{}
+ lateStaticLibs := android.Paths{}
+ wholeStaticLibs := android.Paths{}
+ deps := android.Paths{}
+ implicitOutputs := android.WritablePaths{}
+ validations := android.Paths{}
+ groupLate := false
+
+ builderFlags := flagsToBuilderFlags(ccFlags)
+ transformObjToDynamicBinary(ctx, stubObjs.objFiles, sharedLibs, staticLibs,
+ lateStaticLibs, wholeStaticLibs, deps, crtBegin, crtEnd,
+ groupLate, builderFlags, outputFile, implicitOutputs, validations)
+}
+
// 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,
diff --git a/cc/cc.go b/cc/cc.go
index 0db5c40..57b5e3c 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -160,6 +160,8 @@
Installable *bool
// RelativeInstallPath returns the relative install path for this module.
RelativeInstallPath string
+ // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs.
+ RustApexExclude bool
}
var LinkableInfoProvider = blueprint.NewProvider[*LinkableInfo]()
@@ -943,6 +945,11 @@
return depTag == runtimeDepTag
}
+func ExcludeInApexDepTag(depTag blueprint.DependencyTag) bool {
+ ccLibDepTag, ok := depTag.(libraryDependencyTag)
+ return ok && ccLibDepTag.excludeInApex
+}
+
// Module contains the properties and members used by all C/C++ module types, and implements
// the blueprint.Module interface. It delegates to compiler, linker, and installer interfaces
// to construct the output file. Behavior can be customized with a Customizer, or "decorator",
@@ -1529,6 +1536,10 @@
return false
}
+func (c *Module) RustApexExclude() bool {
+ return false
+}
+
func (c *Module) IsStubsImplementationRequired() bool {
if lib := c.library; lib != nil {
return lib.IsStubsImplementationRequired()
@@ -2360,6 +2371,8 @@
OnlyInRecovery: mod.OnlyInRecovery(),
Installable: mod.Installable(),
RelativeInstallPath: mod.RelativeInstallPath(),
+ // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs.
+ RustApexExclude: mod.RustApexExclude(),
}
}
@@ -3354,9 +3367,12 @@
depFile = sharedLibraryInfo.TableOfContents
if !sharedLibraryInfo.IsStubs {
- depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, ""))
- if info, ok := android.OtherModuleProvider(ctx, dep, ImplementationDepInfoProvider); ok {
- depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
+ // TODO(b/362509506): remove this additional check once all apex_exclude uses are switched to stubs.
+ if !linkableInfo.RustApexExclude {
+ depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, ""))
+ if info, ok := android.OtherModuleProvider(ctx, dep, ImplementationDepInfoProvider); ok {
+ depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
+ }
}
}
diff --git a/cc/compiler.go b/cc/compiler.go
index 1899f59..3730bbe 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -360,7 +360,7 @@
}
}
-func addTargetFlags(ctx android.ModuleContext, flags Flags, tc config.Toolchain, version string, bpf bool) Flags {
+func AddTargetFlags(ctx android.ModuleContext, flags Flags, tc config.Toolchain, version string, bpf bool) Flags {
target := "-target " + tc.ClangTriple()
if ctx.Os().Class == android.Device {
if version == "" || version == "current" {
@@ -536,7 +536,7 @@
flags.Local.ConlyFlags = config.ClangFilterUnknownCflags(flags.Local.ConlyFlags)
flags.Local.LdFlags = config.ClangFilterUnknownCflags(flags.Local.LdFlags)
- flags = addTargetFlags(ctx, flags, tc, ctx.minSdkVersion(), Bool(compiler.Properties.Bpf_target))
+ flags = AddTargetFlags(ctx, flags, tc, ctx.minSdkVersion(), Bool(compiler.Properties.Bpf_target))
hod := "Host"
if ctx.Os().Class == android.Device {
diff --git a/cc/coverage.go b/cc/coverage.go
index 4e058bd..c8ff82b 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -354,7 +354,7 @@
}
}
-func parseSymbolFileForAPICoverage(ctx android.ModuleContext, symbolFile string) android.ModuleOutPath {
+func ParseSymbolFileForAPICoverage(ctx android.ModuleContext, symbolFile string) android.ModuleOutPath {
apiLevelsJson := android.GetApiLevelsJson(ctx)
symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
outputFile := ctx.Module().(LinkableInterface).BaseModuleName() + ".xml"
diff --git a/cc/library.go b/cc/library.go
index 7b225ec..950ea91 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -460,7 +460,7 @@
return props
}
-func commonLibraryLinkerFlags(ctx android.ModuleContext, flags Flags,
+func CommonLibraryLinkerFlags(ctx android.ModuleContext, flags Flags,
toolchain config.Toolchain, libName string) Flags {
mod, ok := ctx.Module().(LinkableInterface)
@@ -511,7 +511,7 @@
// shared library).
func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
flags = library.baseLinker.linkerFlags(ctx, flags)
- flags = commonLibraryLinkerFlags(ctx, flags, ctx.toolchain(), library.getLibName(ctx))
+ flags = CommonLibraryLinkerFlags(ctx, flags, ctx.toolchain(), library.getLibName(ctx))
if library.static() {
flags.Local.CFlags = append(flags.Local.CFlags, library.StaticProperties.Static.Cflags.GetOrDefault(ctx, nil)...)
} else if library.shared() {
@@ -558,7 +558,7 @@
flags.Local.CommonFlags = removeInclude(flags.Local.CommonFlags)
flags.Local.CFlags = removeInclude(flags.Local.CFlags)
- flags = addStubLibraryCompilerFlags(flags)
+ flags = AddStubLibraryCompilerFlags(flags)
}
return flags
}
@@ -735,7 +735,7 @@
nativeAbiResult.VersionScript)
// Parse symbol file to get API list for coverage
if library.StubsVersion() == "current" && ctx.PrimaryArch() && !ctx.inRecovery() && !ctx.inProduct() && !ctx.inVendor() {
- library.apiListCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile)
+ library.apiListCoverageXmlPath = ParseSymbolFileForAPICoverage(ctx, symbolFile)
}
return objs
@@ -2360,10 +2360,6 @@
// setStubsVersions normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions.
func setStubsVersions(mctx android.BaseModuleContext, module VersionedLinkableInterface) {
- // TODO(ivanlozano) remove this when Rust supports stubs
- if module.RustLibraryInterface() {
- return
- }
if !module.BuildSharedVariant() || !canBeVersionVariant(module) {
return
}
@@ -2385,10 +2381,6 @@
return []string{""}
}
if m, ok := ctx.Module().(VersionedLinkableInterface); ok {
- // TODO(ivanlozano) remove this when Rust supports stubs
- if m.RustLibraryInterface() {
- return []string{""}
- }
if m.CcLibraryInterface() && canBeVersionVariant(m) {
setStubsVersions(ctx, m)
return append(slices.Clone(m.VersionedInterface().AllStubsVersions()), "")
@@ -2439,11 +2431,6 @@
m, ok := ctx.Module().(VersionedLinkableInterface)
if library := moduleVersionedInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
- // TODO(ivanlozano) remove this when Rust supports stubs
- if m.RustLibraryInterface() {
- return
- }
-
isLLNDK := m.IsLlndk()
isVendorPublicLibrary := m.IsVendorPublicLibrary()
diff --git a/cc/linkable.go b/cc/linkable.go
index d0fda64..337b459 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -84,6 +84,10 @@
SetMinSdkVersion(version string)
ApexSdkVersion() android.ApiLevel
ImplementationModuleNameForMake(ctx android.BaseModuleContext) string
+
+ // RustApexExclude returns ApexExclude() for Rust modules; always returns false for all non-Rust modules.
+ // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs.
+ RustApexExclude() bool
}
// LinkableInterface is an interface for a type of module that is linkable in a C++ library.
diff --git a/cc/linker.go b/cc/linker.go
index 20c2f4a..f854937 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -471,7 +471,7 @@
// ModuleContext extends BaseModuleContext
// BaseModuleContext should know if LLD is used?
-func commonLinkerFlags(ctx android.ModuleContext, flags Flags, useClangLld bool,
+func CommonLinkerFlags(ctx android.ModuleContext, flags Flags, useClangLld bool,
toolchain config.Toolchain, allow_undefined_symbols bool) Flags {
hod := "Host"
if ctx.Os().Class == android.Device {
@@ -480,7 +480,7 @@
mod, ok := ctx.Module().(LinkableInterface)
if !ok {
- ctx.ModuleErrorf("trying to add commonLinkerFlags to non-LinkableInterface module.")
+ ctx.ModuleErrorf("trying to add CommonLinkerFlags to non-LinkableInterface module.")
return flags
}
if useClangLld {
@@ -531,7 +531,7 @@
toolchain := ctx.toolchain()
allow_undefined_symbols := Bool(linker.Properties.Allow_undefined_symbols)
- flags = commonLinkerFlags(ctx, flags, linker.useClangLld(ctx), toolchain,
+ flags = CommonLinkerFlags(ctx, flags, linker.useClangLld(ctx), toolchain,
allow_undefined_symbols)
if !toolchain.Bionic() && ctx.Os() != android.LinuxMusl {
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 4321beb..1f0fc07 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -236,7 +236,7 @@
pctx.StaticVariable("StubLibraryCompilerFlags", strings.Join(stubLibraryCompilerFlags, " "))
}
-func addStubLibraryCompilerFlags(flags Flags) Flags {
+func AddStubLibraryCompilerFlags(flags Flags) Flags {
flags.Global.CFlags = append(flags.Global.CFlags, stubLibraryCompilerFlags...)
// All symbols in the stubs library should be visible.
if inList("-fvisibility=hidden", flags.Local.CFlags) {
@@ -247,7 +247,7 @@
func (stub *stubDecorator) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
flags = stub.baseCompiler.compilerFlags(ctx, flags, deps)
- return addStubLibraryCompilerFlags(flags)
+ return AddStubLibraryCompilerFlags(flags)
}
type NdkApiOutputs struct {
@@ -510,7 +510,7 @@
}
}
if c.apiLevel.IsCurrent() && ctx.PrimaryArch() {
- c.parsedCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile)
+ c.parsedCoverageXmlPath = ParseSymbolFileForAPICoverage(ctx, symbolFile)
}
return objs
}
diff --git a/cc/stub_library.go b/cc/stub_library.go
index 2291153..9d7b5bc 100644
--- a/cc/stub_library.go
+++ b/cc/stub_library.go
@@ -59,10 +59,6 @@
vendorStubLibraryMap := make(map[string]bool)
ctx.VisitAllModules(func(module android.Module) {
if m, ok := module.(VersionedLinkableInterface); ok {
- // TODO(ivanlozano) remove this when Rust supports stubs
- if m.RustLibraryInterface() {
- return
- }
if IsStubTarget(android.OtherModuleProviderOrDefault(ctx, m, LinkableInfoProvider)) {
if name := getInstalledFileName(ctx, m); name != "" {
stubLibraryMap[name] = true
diff --git a/rust/library.go b/rust/library.go
index 9912c94..49169ac 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -25,6 +25,7 @@
"android/soong/android"
"android/soong/cc"
+ cc_config "android/soong/cc/config"
)
var (
@@ -79,9 +80,13 @@
// Whether this library is part of the Rust toolchain sysroot.
Sysroot *bool
- // Exclude this rust_ffi target from being included in APEXes.
- // TODO(b/362509506): remove this once stubs are properly supported by rust_ffi targets.
+ // Deprecated - exclude this rust_ffi target from being included in APEXes.
+ // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs.
Apex_exclude *bool
+
+ // Generate stubs to make this library accessible to APEXes.
+ // Can only be set for modules producing shared libraries.
+ Stubs cc.StubsProperties `android:"arch_variant"`
}
type LibraryMutatedProperties struct {
@@ -109,6 +114,15 @@
// Whether this library variant should be link libstd via rlibs
VariantIsStaticStd bool `blueprint:"mutated"`
+
+ // This variant is a stubs lib
+ BuildStubs bool `blueprint:"mutated"`
+ // This variant is the latest version
+ IsLatestVersion bool `blueprint:"mutated"`
+ // Version of the stubs lib
+ StubsVersion string `blueprint:"mutated"`
+ // List of all stubs versions associated with an implementation lib
+ AllStubsVersions []string `blueprint:"mutated"`
}
type libraryDecorator struct {
@@ -123,9 +137,28 @@
// table-of-contents file for cdylib crates to optimize out relinking when possible
tocFile android.OptionalPath
+
+ // Path to the file containing the APIs exported by this library
+ stubsSymbolFilePath android.Path
+ apiListCoverageXmlPath android.ModuleOutPath
+ versionScriptPath android.OptionalPath
+}
+
+func (library *libraryDecorator) stubs() bool {
+ return library.MutatedProperties.BuildStubs
+}
+
+func (library *libraryDecorator) setAPIListCoverageXMLPath(xml android.ModuleOutPath) {
+ library.apiListCoverageXmlPath = xml
+}
+
+func (library *libraryDecorator) libraryProperties() LibraryCompilerProperties {
+ return library.Properties
}
type libraryInterface interface {
+ cc.VersionedInterface
+
rlib() bool
dylib() bool
static() bool
@@ -161,6 +194,11 @@
BuildOnlyShared()
toc() android.OptionalPath
+
+ IsStubsImplementationRequired() bool
+ setAPIListCoverageXMLPath(out android.ModuleOutPath)
+
+ libraryProperties() LibraryCompilerProperties
}
func (library *libraryDecorator) nativeCoverage() bool {
@@ -276,58 +314,63 @@
var _ compiler = (*libraryDecorator)(nil)
var _ libraryInterface = (*libraryDecorator)(nil)
+var _ cc.VersionedInterface = (*libraryDecorator)(nil)
var _ exportedFlagsProducer = (*libraryDecorator)(nil)
var _ cc.VersionedInterface = (*libraryDecorator)(nil)
func (library *libraryDecorator) HasLLNDKStubs() bool {
- // Rust does not support LLNDK yet.
+ // Rust LLNDK is currently unsupported
return false
}
func (library *libraryDecorator) HasVendorPublicLibrary() bool {
- // Rust does not support vendor public library.
+ // Rust does not support vendor_public_library yet.
return false
}
func (library *libraryDecorator) HasLLNDKHeaders() bool {
- // Rust does not support LLNDK yet.
+ // Rust LLNDK is currently unsupported
return false
}
func (library *libraryDecorator) HasStubsVariants() bool {
- return false
+ // Just having stubs.symbol_file is enough to create a stub variant. In that case
+ // the stub for the future API level is created.
+ return library.Properties.Stubs.Symbol_file != nil ||
+ len(library.Properties.Stubs.Versions) > 0
}
func (library *libraryDecorator) IsStubsImplementationRequired() bool {
- return false
+ return BoolDefault(library.Properties.Stubs.Implementation_installable, true)
}
func (library *libraryDecorator) GetAPIListCoverageXMLPath() android.ModuleOutPath {
- panic(fmt.Errorf("GetAPIListCoverageXMLPath called on unsupported Rust module"))
+ return library.apiListCoverageXmlPath
}
func (library *libraryDecorator) AllStubsVersions() []string {
- panic(fmt.Errorf("AllStubsVersions called on unsupported Rust module"))
+ return library.MutatedProperties.AllStubsVersions
}
func (library *libraryDecorator) SetAllStubsVersions(versions []string) {
- panic(fmt.Errorf("ApexSdkVersion called on unsupported Rust module"))
+ library.MutatedProperties.AllStubsVersions = versions
}
func (library *libraryDecorator) SetStubsVersion(version string) {
- panic(fmt.Errorf("SetStubsVersion called on unsupported Rust module"))
+ library.MutatedProperties.StubsVersion = version
}
func (library *libraryDecorator) SetBuildStubs(isLatest bool) {
- panic(fmt.Errorf("SetBuildStubs called on unsupported Rust module"))
+ library.MutatedProperties.BuildStubs = true
+ library.MutatedProperties.IsLatestVersion = isLatest
}
func (library *libraryDecorator) BuildStubs() bool {
- return false
+ return library.MutatedProperties.BuildStubs
}
func (library *libraryDecorator) ImplementationModuleName(name string) string {
- panic(fmt.Errorf("ImplementationModuleName called on unsupported Rust module"))
+ return name
}
func (library *libraryDecorator) IsLLNDKMovedToApex() bool {
@@ -335,12 +378,20 @@
return false
}
-func (library *libraryDecorator) StubsVersions(ctx android.BaseModuleContext) []string {
- panic(fmt.Errorf("StubsVersions called on unsupported Rust module"))
+func (library *libraryDecorator) StubsVersion() string {
+ return library.MutatedProperties.StubsVersion
}
-func (library *libraryDecorator) StubsVersion() string {
- panic(fmt.Errorf("StubsVersions called on unsupported Rust module"))
+// stubsVersions implements cc.VersionedInterface.
+func (library *libraryDecorator) StubsVersions(ctx android.BaseModuleContext) []string {
+ if !library.HasStubsVariants() {
+ return nil
+ }
+
+ // Future API level is implicitly added if there isn't
+ versions := cc.AddCurrentVersionIfNotPresent(library.Properties.Stubs.Versions)
+ cc.NormalizeVersions(ctx, versions)
+ return versions
}
// rust_library produces all Rust variants (rust_library_dylib and
@@ -420,6 +471,18 @@
return module.Init()
}
+func CheckRustLibraryProperties(mctx android.DefaultableHookContext) {
+ lib := mctx.Module().(*Module).compiler.(libraryInterface)
+ if !lib.buildShared() {
+ if lib.libraryProperties().Stubs.Symbol_file != nil ||
+ lib.libraryProperties().Stubs.Implementation_installable != nil ||
+ len(lib.libraryProperties().Stubs.Versions) > 0 {
+
+ mctx.PropertyErrorf("stubs", "stubs properties can only be set for rust_ffi or rust_ffi_shared modules")
+ }
+ }
+}
+
func (library *libraryDecorator) BuildOnlyFFI() {
library.MutatedProperties.BuildDylib = false
// we build rlibs for later static ffi linkage.
@@ -479,6 +542,7 @@
module.compiler = library
+ module.SetDefaultableHook(CheckRustLibraryProperties)
return module, library
}
@@ -641,7 +705,11 @@
}
// Call the appropriate builder for this library type
- if library.rlib() {
+ if library.stubs() {
+ ccFlags := library.getApiStubsCcFlags(ctx)
+ stubObjs := library.compileModuleLibApiStubs(ctx, ccFlags)
+ cc.BuildRustStubs(ctx, outputFile, deps.CrtBegin, deps.CrtEnd, stubObjs, ccFlags)
+ } else if library.rlib() {
ret.kytheFile = TransformSrctoRlib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
} else if library.dylib() {
ret.kytheFile = TransformSrctoDylib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
@@ -657,13 +725,13 @@
}
// Since we have FFI rlibs, we need to collect their includes as well
- if library.static() || library.shared() || library.rlib() {
+ if library.static() || library.shared() || library.rlib() || library.stubs() {
android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
IncludeDirs: android.FirstUniquePaths(library.includeDirs),
})
}
- if library.shared() {
+ if library.shared() || library.stubs() {
// Optimize out relinking against shared libraries whose interface hasn't changed by
// depending on a table of contents file instead of the library itself.
tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.SharedLibSuffix()[1:]+".toc")
@@ -674,9 +742,7 @@
TableOfContents: android.OptionalPathForPath(tocFile),
SharedLibrary: outputFile,
Target: ctx.Target(),
- // TODO: when rust supports stubs uses the stubs state rather than inferring it from
- // apex_exclude.
- IsStubs: Bool(library.Properties.Apex_exclude),
+ IsStubs: library.BuildStubs(),
})
}
@@ -688,6 +754,7 @@
TransitiveStaticLibrariesForOrdering: depSet,
})
}
+ cc.AddStubDependencyProviders(ctx)
library.flagExporter.setProvider(ctx)
@@ -707,6 +774,53 @@
}
}
+func (library *libraryDecorator) getApiStubsCcFlags(ctx ModuleContext) cc.Flags {
+ ccFlags := cc.Flags{}
+ toolchain := cc_config.FindToolchain(ctx.Os(), ctx.Arch())
+
+ platformSdkVersion := ""
+ if ctx.Device() {
+ platformSdkVersion = ctx.Config().PlatformSdkVersion().String()
+ }
+ minSdkVersion := cc.MinSdkVersion(ctx.RustModule(), cc.CtxIsForPlatform(ctx), ctx.Device(), platformSdkVersion)
+
+ // Collect common CC compilation flags
+ ccFlags = cc.CommonLinkerFlags(ctx, ccFlags, true, toolchain, false)
+ ccFlags = cc.CommonLibraryLinkerFlags(ctx, ccFlags, toolchain, library.getStem(ctx))
+ ccFlags = cc.AddStubLibraryCompilerFlags(ccFlags)
+ ccFlags = cc.AddTargetFlags(ctx, ccFlags, toolchain, minSdkVersion, false)
+
+ return ccFlags
+}
+
+func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, ccFlags cc.Flags) cc.Objects {
+ mod := ctx.RustModule()
+
+ symbolFile := String(library.Properties.Stubs.Symbol_file)
+ library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile)
+
+ apiParams := cc.ApiStubsParams{
+ NotInPlatform: mod.NotInPlatform(),
+ IsNdk: mod.IsNdk(ctx.Config()),
+ BaseModuleName: mod.BaseModuleName(),
+ ModuleName: ctx.ModuleName(),
+ }
+ flag := cc.GetApiStubsFlags(apiParams)
+
+ nativeAbiResult := cc.ParseNativeAbiDefinition(ctx, symbolFile,
+ android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag)
+ objs := cc.CompileStubLibrary(ctx, ccFlags, nativeAbiResult.StubSrc, mod.getSharedFlags())
+
+ library.versionScriptPath = android.OptionalPathForPath(nativeAbiResult.VersionScript)
+
+ // Parse symbol file to get API list for coverage
+ if library.StubsVersion() == "current" && ctx.PrimaryArch() && !mod.InRecovery() && !mod.InProduct() && !mod.InVendor() {
+ library.apiListCoverageXmlPath = cc.ParseSymbolFileForAPICoverage(ctx, symbolFile)
+ }
+
+ return objs
+}
+
func (library *libraryDecorator) rustdoc(ctx ModuleContext, flags Flags,
deps PathDeps) android.OptionalPath {
// rustdoc has builtin support for documenting config specific information
diff --git a/rust/library_test.go b/rust/library_test.go
index e5fd5e0..1198fcc 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -482,3 +482,289 @@
extra_exported_symbols: "libbar.map.txt",
}`)
}
+
+func TestStubsVersions(t *testing.T) {
+ t.Parallel()
+ bp := `
+ rust_ffi {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ stubs: {
+ versions: ["29", "R", "current"],
+ },
+ }
+ `
+ ctx := android.GroupFixturePreparers(
+ prepareForRustTest,
+ android.PrepareForTestWithVisibility,
+ rustMockedFiles.AddToFixture(),
+ android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) {
+ config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
+ })).RunTestWithBp(t, bp)
+
+ variants := ctx.ModuleVariantsForTests("libfoo")
+ for _, expectedVer := range []string{"29", "R", "current"} {
+ expectedVariant := "android_arm_armv7-a-neon_shared_" + expectedVer
+ if !android.InList(expectedVariant, variants) {
+ t.Errorf("missing expected variant: %q", expectedVariant)
+ }
+ }
+}
+
+func TestStubsVersions_NotSorted(t *testing.T) {
+ t.Parallel()
+ bp := `
+ rust_ffi_shared {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ stubs: {
+ versions: ["29", "current", "R"],
+ },
+ }
+ `
+ fixture := android.GroupFixturePreparers(
+ prepareForRustTest,
+ android.PrepareForTestWithVisibility,
+ rustMockedFiles.AddToFixture(),
+
+ android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) {
+ config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
+ }))
+
+ fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`"libfoo" .*: versions: not sorted`)).RunTestWithBp(t, bp)
+}
+
+func TestStubsVersions_ParseError(t *testing.T) {
+ t.Parallel()
+ bp := `
+ rust_ffi_shared {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ stubs: {
+ versions: ["29", "current", "X"],
+ },
+ }
+ `
+ fixture := android.GroupFixturePreparers(
+ prepareForRustTest,
+ android.PrepareForTestWithVisibility,
+ rustMockedFiles.AddToFixture(),
+
+ android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) {
+ config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
+ }))
+
+ fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`"libfoo" .*: versions: "X" could not be parsed as an integer and is not a recognized codename`)).RunTestWithBp(t, bp)
+}
+
+func TestVersionedStubs(t *testing.T) {
+ t.Parallel()
+ bp := `
+ rust_ffi_shared {
+ name: "libFoo",
+ crate_name: "Foo",
+ srcs: ["foo.rs"],
+ stubs: {
+ symbol_file: "foo.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ }
+
+ cc_library_shared {
+ name: "libBar",
+ srcs: ["bar.c"],
+ shared_libs: ["libFoo#1"],
+ }
+
+ rust_library {
+ name: "libbar_rs",
+ crate_name: "bar_rs",
+ srcs: ["bar.rs"],
+ shared_libs: ["libFoo#1"],
+ }
+ rust_ffi {
+ name: "libbar_ffi_rs",
+ crate_name: "bar_ffi_rs",
+ srcs: ["bar.rs"],
+ shared_libs: ["libFoo#1"],
+ }
+ `
+
+ ctx := android.GroupFixturePreparers(
+ prepareForRustTest,
+ android.PrepareForTestWithVisibility,
+ rustMockedFiles.AddToFixture()).RunTestWithBp(t, bp)
+
+ variants := ctx.ModuleVariantsForTests("libFoo")
+ expectedVariants := []string{
+ "android_arm64_armv8-a_shared",
+ "android_arm64_armv8-a_shared_1",
+ "android_arm64_armv8-a_shared_2",
+ "android_arm64_armv8-a_shared_3",
+ "android_arm64_armv8-a_shared_current",
+ "android_arm_armv7-a-neon_shared",
+ "android_arm_armv7-a-neon_shared_1",
+ "android_arm_armv7-a-neon_shared_2",
+ "android_arm_armv7-a-neon_shared_3",
+ "android_arm_armv7-a-neon_shared_current",
+ }
+ variantsMismatch := false
+ if len(variants) != len(expectedVariants) {
+ variantsMismatch = true
+ } else {
+ for _, v := range expectedVariants {
+ if !android.InList(v, variants) {
+ variantsMismatch = false
+ }
+ }
+ }
+ if variantsMismatch {
+ t.Errorf("variants of libFoo expected:\n")
+ for _, v := range expectedVariants {
+ t.Errorf("%q\n", v)
+ }
+ t.Errorf(", but got:\n")
+ for _, v := range variants {
+ t.Errorf("%q\n", v)
+ }
+ }
+
+ libBarLinkRule := ctx.ModuleForTests("libBar", "android_arm64_armv8-a_shared").Rule("ld")
+ libBarFlags := libBarLinkRule.Args["libFlags"]
+
+ libBarRsRustcRule := ctx.ModuleForTests("libbar_rs", "android_arm64_armv8-a_dylib").Rule("rustc")
+ libBarRsFlags := libBarRsRustcRule.Args["linkFlags"]
+
+ libBarFfiRsRustcRule := ctx.ModuleForTests("libbar_ffi_rs", "android_arm64_armv8-a_shared").Rule("rustc")
+ libBarFfiRsFlags := libBarFfiRsRustcRule.Args["linkFlags"]
+
+ libFoo1StubPath := "libFoo/android_arm64_armv8-a_shared_1/unstripped/libFoo.so"
+ if !strings.Contains(libBarFlags, libFoo1StubPath) {
+ t.Errorf("%q is not found in %q", libFoo1StubPath, libBarFlags)
+ }
+ if !strings.Contains(libBarRsFlags, libFoo1StubPath) {
+ t.Errorf("%q is not found in %q", libFoo1StubPath, libBarRsFlags)
+ }
+ if !strings.Contains(libBarFfiRsFlags, libFoo1StubPath) {
+ t.Errorf("%q is not found in %q", libFoo1StubPath, libBarFfiRsFlags)
+ }
+}
+
+func TestCheckConflictingExplicitVersions(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "libbar",
+ srcs: ["bar.c"],
+ shared_libs: ["libfoo", "libfoo#impl"],
+ }
+
+ rust_ffi_shared {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ stubs: {
+ versions: ["29", "current"],
+ },
+ }
+ `
+ fixture := android.GroupFixturePreparers(
+ prepareForRustTest,
+ android.PrepareForTestWithVisibility,
+ rustMockedFiles.AddToFixture())
+
+ fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`duplicate shared libraries with different explicit versions`)).RunTestWithBp(t, bp)
+}
+
+func TestAddnoOverride64GlobalCflags(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "libclient",
+ srcs: ["foo.c"],
+ shared_libs: ["libfoo#1"],
+ }
+
+ rust_ffi_shared {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.c"],
+ shared_libs: ["libbar"],
+ stubs: {
+ symbol_file: "foo.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ }
+
+ cc_library_shared {
+ name: "libbar",
+ export_include_dirs: ["include/libbar"],
+ srcs: ["foo.c"],
+ }`
+ ctx := android.GroupFixturePreparers(
+ prepareForRustTest,
+ android.PrepareForTestWithVisibility,
+ rustMockedFiles.AddToFixture()).RunTestWithBp(t, bp)
+
+ cFlags := ctx.ModuleForTests("libclient", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"]
+
+ if !strings.Contains(cFlags, "${config.NoOverride64GlobalCflags}") {
+ t.Errorf("expected %q in cflags, got %q", "${config.NoOverride64GlobalCflags}", cFlags)
+ }
+}
+
+// Make sure the stubs properties can only be used in modules producing shared libs
+func TestRustStubsFFIOnly(t *testing.T) {
+ testRustError(t, "stubs properties", `
+ rust_library {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.c"],
+ shared_libs: ["libbar"],
+ stubs: {
+ symbol_file: "foo.map.txt",
+ },
+ }
+ `)
+
+ testRustError(t, "stubs properties", `
+ rust_library {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.c"],
+ shared_libs: ["libbar"],
+ stubs: {
+ versions: ["1"],
+ },
+ }
+ `)
+
+ testRustError(t, "stubs properties", `
+ rust_ffi_static {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.c"],
+ shared_libs: ["libbar"],
+ stubs: {
+ symbol_file: "foo.map.txt",
+ },
+ }
+ `)
+ testRustError(t, "stubs properties", `
+ rust_ffi_static {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.c"],
+ shared_libs: ["libbar"],
+ stubs: {
+ versions: ["1"],
+ },
+ }
+ `)
+}
+
+// TODO: When rust_ffi libraries support export_*_lib_headers,
+// add a test similar to cc.TestStubsLibReexportsHeaders
diff --git a/rust/rust.go b/rust/rust.go
index 2332b52..557bdc3 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -162,9 +162,36 @@
// Make this module available when building for recovery
Recovery_available *bool
- // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+ // The API level that this module is built against. The APIs of this API level will be
+ // visible at build time, but use of any APIs newer than min_sdk_version will render the
+ // module unloadable on older devices. In the future it will be possible to weakly-link new
+ // APIs, making the behavior match Java: such modules will load on older devices, but
+ // calling new APIs on devices that do not support them will result in a crash.
+ //
+ // This property has the same behavior as sdk_version does for Java modules. For those
+ // familiar with Android Gradle, the property behaves similarly to how compileSdkVersion
+ // does for Java code.
+ //
+ // In addition, setting this property causes two variants to be built, one for the platform
+ // and one for apps.
+ Sdk_version *string
+
+ // Minimum OS API level supported by this C or C++ module. This property becomes the value
+ // of the __ANDROID_API__ macro. When the C or C++ module is included in an APEX or an APK,
+ // this property is also used to ensure that the min_sdk_version of the containing module is
+ // not older (i.e. less) than this module's min_sdk_version. When not set, this property
+ // defaults to the value of sdk_version. When this is set to "apex_inherit", this tracks
+ // min_sdk_version of the containing APEX. When the module
+ // is not built for an APEX, "apex_inherit" defaults to sdk_version.
Min_sdk_version *string
+ // Variant is an SDK variant created by sdkMutator
+ IsSdkVariant bool `blueprint:"mutated"`
+
+ // Set by factories of module types that can only be referenced from variants compiled against
+ // the SDK.
+ AlwaysSdk bool `blueprint:"mutated"`
+
HideFromMake bool `blueprint:"mutated"`
PreventInstall bool `blueprint:"mutated"`
@@ -209,6 +236,9 @@
apexSdkVersion android.ApiLevel
transitiveAndroidMkSharedLibs depset.DepSet[string]
+
+ // Shared flags among stubs build rules of this module
+ sharedFlags cc.SharedFlags
}
func (mod *Module) Header() bool {
@@ -374,7 +404,8 @@
}
func (mod *Module) IsVendorPublicLibrary() bool {
- return mod.VendorProperties.IsVendorPublicLibrary
+ // Rust modules do not currently support vendor_public_library
+ return false
}
func (mod *Module) SdkAndPlatformVariantVisibleToMake() bool {
@@ -383,10 +414,12 @@
}
func (c *Module) IsVndkPrivate() bool {
+ // Rust modules do not currently support VNDK variants
return false
}
func (c *Module) IsLlndk() bool {
+ // Rust modules do not currently support LLNDK variants
return false
}
@@ -395,31 +428,34 @@
}
func (m *Module) NeedsLlndkVariants() bool {
+ // Rust modules do not currently support LLNDK variants
return false
}
func (m *Module) NeedsVendorPublicLibraryVariants() bool {
+ // Rust modules do not currently support vendor_public_library
return false
}
func (mod *Module) HasLlndkStubs() bool {
+ // Rust modules do not currently support LLNDK stubs
return false
}
func (mod *Module) SdkVersion() string {
- return ""
+ return String(mod.Properties.Sdk_version)
}
func (mod *Module) AlwaysSdk() bool {
- return false
+ return mod.Properties.AlwaysSdk
}
func (mod *Module) IsSdkVariant() bool {
- return false
+ return mod.Properties.IsSdkVariant
}
func (mod *Module) SplitPerApiLevel() bool {
- return false
+ return cc.CanUseSdk(mod) && mod.IsCrt()
}
func (mod *Module) XrefRustFiles() android.Paths {
@@ -743,19 +779,42 @@
}
func (mod *Module) IsStubs() bool {
+ if lib, ok := mod.compiler.(libraryInterface); ok {
+ return lib.BuildStubs()
+ }
return false
}
func (mod *Module) HasStubsVariants() bool {
+ if lib, ok := mod.compiler.(libraryInterface); ok {
+ return lib.HasStubsVariants()
+ }
return false
}
func (mod *Module) ApexSdkVersion() android.ApiLevel {
- panic(fmt.Errorf("ApexSdkVersion called on unsupported Rust module: %q", mod.BaseModuleName()))
+ return mod.apexSdkVersion
+}
+
+func (mod *Module) RustApexExclude() bool {
+ return mod.ApexExclude()
+}
+
+func (mod *Module) getSharedFlags() *cc.SharedFlags {
+ shared := &mod.sharedFlags
+ if shared.FlagsMap == nil {
+ shared.NumSharedFlags = 0
+ shared.FlagsMap = make(map[string]string)
+ }
+ return shared
}
func (mod *Module) ImplementationModuleNameForMake(ctx android.BaseModuleContext) string {
- return mod.Name()
+ name := mod.BaseModuleName()
+ if versioned, ok := mod.compiler.(cc.VersionedInterface); ok {
+ name = versioned.ImplementationModuleName(name)
+ }
+ return name
}
func (mod *Module) Multilib() string {
@@ -903,7 +962,7 @@
}
func (mod *Module) SetSdkVersion(s string) {
- panic(fmt.Errorf("SetSdkVersion called on unsupported Rust module: %q", mod.BaseModuleName()))
+ mod.Properties.Sdk_version = StringPtr(s)
}
func (mod *Module) SetMinSdkVersion(s string) {
@@ -1066,6 +1125,10 @@
linkableInfo.Shared = mod.Shared()
linkableInfo.CrateName = mod.CrateName()
linkableInfo.ExportedCrateLinkDirs = mod.ExportedCrateLinkDirs()
+ if lib, ok := mod.compiler.(cc.VersionedInterface); ok {
+ linkableInfo.StubsVersion = lib.StubsVersion()
+ }
+
android.SetProvider(ctx, cc.LinkableInfoProvider, linkableInfo)
rustInfo := &RustInfo{
@@ -1108,10 +1171,9 @@
// does compilation and linking in one step. If this changes in the future,
// move this as appropriate.
ccInfo.LinkerInfo = &cc.LinkerInfo{
- WholeStaticLibs: mod.compiler.baseCompilerProps().Whole_static_libs,
- StaticLibs: mod.compiler.baseCompilerProps().Static_libs,
- SharedLibs: mod.compiler.baseCompilerProps().Shared_libs,
- UnstrippedOutputFile: mod.UnstrippedOutputFile(),
+ WholeStaticLibs: mod.compiler.baseCompilerProps().Whole_static_libs,
+ StaticLibs: mod.compiler.baseCompilerProps().Static_libs,
+ SharedLibs: mod.compiler.baseCompilerProps().Shared_libs,
}
android.SetProvider(ctx, cc.CcInfoProvider, ccInfo)
@@ -1277,6 +1339,21 @@
if mod.sanitize != nil {
mod.sanitize.begin(ctx)
}
+
+ if mod.UseSdk() && mod.IsSdkVariant() {
+ sdkVersion := ""
+ if ctx.Device() {
+ sdkVersion = mod.SdkVersion()
+ }
+ version, err := cc.NativeApiLevelFromUser(ctx, sdkVersion)
+ if err != nil {
+ ctx.PropertyErrorf("sdk_version", err.Error())
+ mod.Properties.Sdk_version = nil
+ } else {
+ mod.Properties.Sdk_version = StringPtr(version.String())
+ }
+ }
+
}
func (mod *Module) Prebuilt() *android.Prebuilt {
@@ -1552,9 +1629,12 @@
sharedLibraryInfo, exportedInfo := cc.ChooseStubOrImpl(ctx, dep)
if !sharedLibraryInfo.IsStubs {
- depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, ""))
- if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
- depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
+ // TODO(b/362509506): remove this additional check once all apex_exclude uses are switched to stubs.
+ if !linkableInfo.RustApexExclude {
+ depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, ""))
+ if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+ depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps)
+ }
}
}
@@ -1922,7 +2002,7 @@
var _ android.ApexModule = (*Module)(nil)
// If a module is marked for exclusion from apexes, don't provide apex variants.
-// TODO(b/362509506): remove this once stubs are properly supported by rust_ffi targets.
+// TODO(b/362509506): remove this once all apex_exclude usages are removed.
func (m *Module) CanHaveApexVariants() bool {
if m.ApexExclude() {
return false
@@ -1959,6 +2039,13 @@
}
// Implements android.ApexModule
+func (mod *Module) AlwaysRequiresPlatformApexVariant() bool {
+ // stub libraries and native bridge libraries are always available to platform
+ // TODO(b/362509506): remove the ApexExclude() check once all apex_exclude uses are switched to stubs.
+ return mod.IsStubs() || mod.Target().NativeBridge == android.NativeBridgeEnabled || mod.ApexExclude()
+}
+
+// Implements android.ApexModule
func (mod *Module) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
if depTag == procMacroDepTag || depTag == customBindgenDepTag {
return false
@@ -1971,18 +2058,55 @@
return false
}
+ if depTag == cc.StubImplDepTag {
+ // We don't track from an implementation library to its stubs.
+ return false
+ }
+
+ if cc.ExcludeInApexDepTag(depTag) {
+ return false
+ }
+
+ // TODO(b/362509506): remove once all apex_exclude uses are switched to stubs.
+ if mod.ApexExclude() {
+ return false
+ }
+
return true
}
func (mod *Module) IncomingDepIsInSameApex(depTag blueprint.DependencyTag) bool {
- return !mod.ApexExclude()
+ // TODO(b/362509506): remove once all apex_exclude uses are switched to stubs.
+ if mod.ApexExclude() {
+ return false
+ }
+
+ if mod.HasStubsVariants() {
+ if cc.IsSharedDepTag(depTag) {
+ // dynamic dep to a stubs lib crosses APEX boundary
+ return false
+ }
+ if cc.IsRuntimeDepTag(depTag) {
+ // runtime dep to a stubs lib also crosses APEX boundary
+ return false
+ }
+ if cc.IsHeaderDepTag(depTag) {
+ return false
+ }
+ }
+ return true
}
// Overrides ApexModule.IsInstallabeToApex()
func (mod *Module) IsInstallableToApex() bool {
+ // TODO(b/362509506): remove once all apex_exclude uses are switched to stubs.
+ if mod.ApexExclude() {
+ return false
+ }
+
if mod.compiler != nil {
- if lib, ok := mod.compiler.(libraryInterface); ok && (lib.shared() || lib.dylib()) {
- return true
+ if lib, ok := mod.compiler.(libraryInterface); ok {
+ return (lib.shared() || lib.dylib()) && !lib.BuildStubs()
}
if _, ok := mod.compiler.(*binaryDecorator); ok {
return true
diff --git a/rust/testing.go b/rust/testing.go
index 0ce1b66..2082b52 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -80,7 +80,6 @@
no_libcrt: true,
nocrt: true,
system_shared_libs: [],
- apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
vendor_available: true,
host_supported: true,
@@ -88,6 +87,13 @@
llndk: {
symbol_file: "liblog.map.txt",
},
+ stubs: {
+ symbol_file: "liblog.map.txt",
+ versions: [
+ "29",
+ "30",
+ ],
+ },
}
cc_library {
name: "libprotobuf-cpp-full",