From 99644e92c86e400fb78595edf02184139574c2ca Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Tue, 17 Nov 2020 22:21:02 +0900 Subject: [PATCH] rust modules can be included in apex We will have some APEXes having rust binaries and libraries. So, adding the support for the types of modules. rust.Module now inherits from android.ApexModuleBase and implements the android.ApexModule interface. Bug: 172414324 Test: m Exempt-From-Owner-Approval: rebased after +2 from the owner Change-Id: I356ef4c45f782a6460f001e83af96d1710642d80 --- Android.bp | 4 +++ apex/Android.bp | 1 + apex/apex.go | 52 ++++++++++++++++++++++++++++++++-- apex/apex_test.go | 35 ++++++++++++++++++++++- cc/testing.go | 4 +++ rust/androidmk.go | 2 +- rust/clippy_test.go | 2 ++ rust/compiler_test.go | 2 ++ rust/rust.go | 66 +++++++++++++++++++++++++++++++++++++++++++ rust/rust_test.go | 1 + rust/testing.go | 19 +++++++++---- 11 files changed, 177 insertions(+), 11 deletions(-) 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 a645b06d0..fceb307f1 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 @@ -513,13 +517,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 @@ -529,6 +535,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) { @@ -1264,6 +1271,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() @@ -1501,8 +1537,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) { @@ -1663,6 +1702,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 }