diff --git a/Android.bp b/Android.bp index e7a5de21e..866ed2534 100644 --- a/Android.bp +++ b/Android.bp @@ -75,6 +75,10 @@ toolchain_library { product_available: true, recovery_available: true, native_bridge_supported: true, + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], arch: { arm: { diff --git a/apex/Android.bp b/apex/Android.bp index 1a5f6837e..9e8c30d26 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -9,6 +9,7 @@ bootstrap_go_package { "soong-cc", "soong-java", "soong-python", + "soong-rust", "soong-sh", ], srcs: [ diff --git a/apex/apex.go b/apex/apex.go index df639328e..f127757b3 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -32,6 +32,7 @@ import ( prebuilt_etc "android/soong/etc" "android/soong/java" "android/soong/python" + "android/soong/rust" "android/soong/sh" ) @@ -179,6 +180,9 @@ type ApexNativeDependencies struct { // List of JNI libraries that are embedded inside this APEX. Jni_libs []string + // List of rust dyn libraries + Rust_dyn_libs []string + // List of native executables that are embedded inside this APEX. Binaries []string @@ -511,13 +515,15 @@ var ( func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeModules ApexNativeDependencies, target android.Target, imageVariation string) { binVariations := target.Variations() libVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"}) + rustLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"}) if ctx.Device() { binVariations = append(binVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation}) libVariations = append(libVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation}, - blueprint.Variation{Mutator: "version", Variation: ""}, // "" is the non-stub variant - ) + blueprint.Variation{Mutator: "version", Variation: ""}) // "" is the non-stub variant + rustLibVariations = append(rustLibVariations, + blueprint.Variation{Mutator: "image", Variation: imageVariation}) } // Use *FarVariation* to be able to depend on modules having conflicting variations with @@ -527,6 +533,7 @@ func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeM ctx.AddFarVariationDependencies(binVariations, testTag, nativeModules.Tests...) ctx.AddFarVariationDependencies(libVariations, jniLibTag, nativeModules.Jni_libs...) ctx.AddFarVariationDependencies(libVariations, sharedLibTag, nativeModules.Native_shared_libs...) + ctx.AddFarVariationDependencies(rustLibVariations, sharedLibTag, nativeModules.Rust_dyn_libs...) } func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) { @@ -1263,6 +1270,35 @@ func apexFileForExecutable(ctx android.BaseModuleContext, cc *cc.Module) apexFil return af } +func apexFileForRustExecutable(ctx android.BaseModuleContext, rustm *rust.Module) apexFile { + dirInApex := "bin" + if rustm.Target().NativeBridge == android.NativeBridgeEnabled { + dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath) + } + fileToCopy := rustm.OutputFile().Path() + androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName + af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, rustm) + return af +} + +func apexFileForRustLibrary(ctx android.BaseModuleContext, rustm *rust.Module) apexFile { + // Decide the APEX-local directory by the multilib of the library + // In the future, we may query this to the module. + var dirInApex string + switch rustm.Arch().ArchType.Multilib { + case "lib32": + dirInApex = "lib" + case "lib64": + dirInApex = "lib64" + } + if rustm.Target().NativeBridge == android.NativeBridgeEnabled { + dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath) + } + fileToCopy := rustm.OutputFile().Path() + androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName + return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, rustm) +} + func apexFileForPyBinary(ctx android.BaseModuleContext, py *python.Module) apexFile { dirInApex := "bin" fileToCopy := py.HostToolPath().Path() @@ -1500,8 +1536,11 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesInfo = append(filesInfo, apexFileForPyBinary(ctx, py)) } else if gb, ok := child.(bootstrap.GoBinaryTool); ok && a.Host() { filesInfo = append(filesInfo, apexFileForGoBinary(ctx, depName, gb)) + } else if rust, ok := child.(*rust.Module); ok { + filesInfo = append(filesInfo, apexFileForRustExecutable(ctx, rust)) + return true // track transitive dependencies } else { - ctx.PropertyErrorf("binaries", "%q is neither cc_binary, (embedded) py_binary, (host) blueprint_go_binary, (host) bootstrap_go_binary, nor sh_binary", depName) + ctx.PropertyErrorf("binaries", "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, (host) bootstrap_go_binary, nor sh_binary", depName) } case javaLibTag: switch child.(type) { @@ -1662,6 +1701,13 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok { filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName)) } + } else if rust.IsDylibDepTag(depTag) { + if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() { + af := apexFileForRustLibrary(ctx, rustm) + af.transitiveDep = true + filesInfo = append(filesInfo, af) + return true // track transitive dependencies + } } else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok { // nothing } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { diff --git a/apex/apex_test.go b/apex/apex_test.go index 33e50770a..a94e3b4a7 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -32,6 +32,7 @@ import ( "android/soong/dexpreopt" prebuilt_etc "android/soong/etc" "android/soong/java" + "android/soong/rust" "android/soong/sh" ) @@ -136,6 +137,8 @@ func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*andr bp = bp + cc.GatherRequiredDepsForTest(android.Android) + bp = bp + rust.GatherRequiredDepsForTest() + bp = bp + java.GatherRequiredDepsForTest() fs := map[string][]byte{ @@ -185,6 +188,7 @@ func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*andr "bar/baz": nil, "testdata/baz": nil, "AppSet.apks": nil, + "foo.rs": nil, } cc.GatherRequiredFilesForTest(fs) @@ -241,6 +245,7 @@ func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*andr ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer) cc.RegisterRequiredBuildComponentsForTest(ctx) + rust.RegisterRequiredBuildComponentsForTest(ctx) ctx.RegisterModuleType("cc_test", cc.TestFactory) ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory) @@ -349,10 +354,12 @@ func TestBasicApex(t *testing.T) { manifest: ":myapex.manifest", androidManifest: ":myapex.androidmanifest", key: "myapex.key", + binaries: ["foo.rust"], native_shared_libs: ["mylib"], + rust_dyn_libs: ["libfoo.dylib.rust"], multilib: { both: { - binaries: ["foo",], + binaries: ["foo"], } }, java_libs: [ @@ -415,6 +422,28 @@ func TestBasicApex(t *testing.T) { apex_available: [ "myapex", "com.android.gki.*" ], } + rust_binary { + name: "foo.rust", + srcs: ["foo.rs"], + rlibs: ["libfoo.rlib.rust"], + dylibs: ["libfoo.dylib.rust"], + apex_available: ["myapex"], + } + + rust_library_rlib { + name: "libfoo.rlib.rust", + srcs: ["foo.rs"], + crate_name: "foo", + apex_available: ["myapex"], + } + + rust_library_dylib { + name: "libfoo.dylib.rust", + srcs: ["foo.rs"], + crate_name: "foo", + apex_available: ["myapex"], + } + apex { name: "com.android.gki.fake", binaries: ["foo"], @@ -529,16 +558,20 @@ func TestBasicApex(t *testing.T) { ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_apex10000") ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("foo.rust"), "android_arm64_armv8-a_apex10000") // Ensure that apex variant is created for the indirect dep ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000") ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.rlib.rust"), "android_arm64_armv8-a_rlib_dylib-std_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.dylib.rust"), "android_arm64_armv8-a_dylib_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") ensureContains(t, copyCmds, "image.apex/lib64/mylib2.so") ensureContains(t, copyCmds, "image.apex/javalib/myjar_stem.jar") ensureContains(t, copyCmds, "image.apex/javalib/myjar_dex.jar") + ensureContains(t, copyCmds, "image.apex/lib64/libfoo.dylib.rust.dylib.so") // .. but not for java libs ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar") ensureNotContains(t, copyCmds, "image.apex/javalib/msharedjar.jar") diff --git a/cc/testing.go b/cc/testing.go index 198764bfc..95a93a0ed 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -166,6 +166,10 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { product_available: true, recovery_available: true, src: "", + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], } toolchain_library { diff --git a/rust/androidmk.go b/rust/androidmk.go index 74cd9bfa6..4e8b14d05 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -43,7 +43,7 @@ func (mod *Module) SubAndroidMk(data *android.AndroidMkEntries, obj interface{}) } func (mod *Module) AndroidMkEntries() []android.AndroidMkEntries { - if mod.Properties.HideFromMake { + if mod.Properties.HideFromMake || mod.hideApexVariantFromMake { return []android.AndroidMkEntries{android.AndroidMkEntries{Disabled: true}} } diff --git a/rust/clippy_test.go b/rust/clippy_test.go index 132b7b8fa..e24f666df 100644 --- a/rust/clippy_test.go +++ b/rust/clippy_test.go @@ -18,6 +18,7 @@ import ( "testing" "android/soong/android" + "android/soong/cc" ) func TestClippy(t *testing.T) { @@ -45,6 +46,7 @@ func TestClippy(t *testing.T) { }` bp = bp + GatherRequiredDepsForTest() + bp = bp + cc.GatherRequiredDepsForTest(android.NoOsType) fs := map[string][]byte{ // Reuse the same blueprint file for subdirectories. diff --git a/rust/compiler_test.go b/rust/compiler_test.go index a6dba9eec..2b40727e7 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -19,6 +19,7 @@ import ( "testing" "android/soong/android" + "android/soong/cc" ) // Test that feature flags are being correctly generated. @@ -132,6 +133,7 @@ func TestLints(t *testing.T) { }` bp = bp + GatherRequiredDepsForTest() + bp = bp + cc.GatherRequiredDepsForTest(android.NoOsType) fs := map[string][]byte{ // Reuse the same blueprint file for subdirectories. diff --git a/rust/rust.go b/rust/rust.go index 5b9404504..b277afce5 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -74,6 +74,7 @@ type BaseProperties struct { type Module struct { android.ModuleBase android.DefaultableModuleBase + android.ApexModuleBase Properties BaseProperties @@ -88,6 +89,8 @@ type Module struct { subAndroidMkOnce map[SubAndroidMkProvider]bool outputFile android.OptionalPath + + hideApexVariantFromMake bool } func (mod *Module) OutputFiles(tag string) (android.Paths, error) { @@ -508,6 +511,7 @@ func (mod *Module) Init() android.Module { } android.InitAndroidArchModule(mod, mod.hod, mod.multilib) + android.InitApexModule(mod) android.InitDefaultableModule(mod) return mod @@ -605,6 +609,11 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { ModuleContext: actx, } + apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo) + if !apexInfo.IsForPlatform() { + mod.hideApexVariantFromMake = true + } + toolchain := mod.toolchain(ctx) if !toolchain.Supported() { @@ -694,6 +703,11 @@ var ( sourceDepTag = dependencyTag{name: "source"} ) +func IsDylibDepTag(depTag blueprint.DependencyTag) bool { + tag, ok := depTag.(dependencyTag) + return ok && tag == dylibDepTag +} + type autoDep struct { variation string depTag dependencyTag @@ -1052,6 +1066,58 @@ func (mod *Module) HostToolPath() android.OptionalPath { return android.OptionalPath{} } +var _ android.ApexModule = (*Module)(nil) + +func (mod *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { + return nil +} + +func (mod *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { + depTag := ctx.OtherModuleDependencyTag(dep) + + if ccm, ok := dep.(*cc.Module); ok { + if ccm.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 + } + } + if mod.Static() && cc.IsSharedDepTag(depTag) { + // shared_lib dependency from a static lib is considered as crossing + // the APEX boundary because the dependency doesn't actually is + // linked; the dependency is used only during the compilation phase. + return false + } + } + + if depTag == procMacroDepTag { + return false + } + + return true +} + +// Overrides ApexModule.IsInstallabeToApex() +func (mod *Module) IsInstallableToApex() bool { + if mod.compiler != nil { + if lib, ok := mod.compiler.(*libraryDecorator); ok && (lib.shared() || lib.dylib()) { + return true + } + if _, ok := mod.compiler.(*binaryDecorator); ok { + return true + } + } + return false +} + var Bool = proptools.Bool var BoolDefault = proptools.BoolDefault var String = proptools.String diff --git a/rust/rust_test.go b/rust/rust_test.go index 187f0b699..646b25217 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -120,6 +120,7 @@ func (tctx *testRustCtx) useMockedFs() { // attributes of the testRustCtx. func (tctx *testRustCtx) generateConfig() { tctx.bp = tctx.bp + GatherRequiredDepsForTest() + tctx.bp = tctx.bp + cc.GatherRequiredDepsForTest(android.NoOsType) cc.GatherRequiredFilesForTest(tctx.fs) config := android.TestArchConfig(buildDir, tctx.env, tctx.bp, tctx.fs) tctx.config = &config diff --git a/rust/testing.go b/rust/testing.go index 001f322d8..a8496d983 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -77,6 +77,7 @@ func GatherRequiredDepsForTest() string { no_libcrt: true, nocrt: true, system_shared_libs: [], + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], } cc_library { name: "libprotobuf-cpp-full", @@ -93,6 +94,7 @@ func GatherRequiredDepsForTest() string { host_supported: true, native_coverage: false, sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], } rust_library { name: "libtest", @@ -102,6 +104,7 @@ func GatherRequiredDepsForTest() string { host_supported: true, native_coverage: false, sysroot: true, + apex_available: ["//apex_available:platform", "//apex_available:anyapex"], } rust_library { name: "libprotobuf", @@ -122,15 +125,11 @@ func GatherRequiredDepsForTest() string { host_supported: true, } -` + cc.GatherRequiredDepsForTest(android.NoOsType) +` return bp } -func CreateTestContext(config android.Config) *android.TestContext { - ctx := android.NewTestArchContext(config) - android.RegisterPrebuiltMutators(ctx) - ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) - cc.RegisterRequiredBuildComponentsForTest(ctx) +func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { ctx.RegisterModuleType("rust_binary", RustBinaryFactory) ctx.RegisterModuleType("rust_binary_host", RustBinaryHostFactory) ctx.RegisterModuleType("rust_bindgen", RustBindgenFactory) @@ -164,6 +163,14 @@ func CreateTestContext(config android.Config) *android.TestContext { ctx.BottomUp("rust_begin", BeginMutator).Parallel() }) ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton) +} + +func CreateTestContext(config android.Config) *android.TestContext { + ctx := android.NewTestArchContext(config) + android.RegisterPrebuiltMutators(ctx) + ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) + cc.RegisterRequiredBuildComponentsForTest(ctx) + RegisterRequiredBuildComponentsForTest(ctx) return ctx }