From 457ddef28eafeb79765c058a7f710d0e60567f94 Mon Sep 17 00:00:00 2001 From: Vinh Tran Date: Wed, 2 Aug 2023 13:50:26 -0400 Subject: [PATCH] Implement rust_aconfig_library rust_aconfig_library generates src/lib.rs and uses it to build library variants (dylib, rlib-rlib_std, and rlib-dylib_std) as of what `rust_library` produces Test: go test Change-Id: I6c4603691d4306c463c2e9521f5c11c30765b1e3 --- aconfig/Android.bp | 2 + aconfig/aconfig_declarations.go | 3 +- aconfig/init.go | 16 ++++++ aconfig/rust_aconfig_library.go | 83 ++++++++++++++++++++++++++++ aconfig/rust_aconfig_library_test.go | 60 ++++++++++++++++++++ 5 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 aconfig/rust_aconfig_library.go create mode 100644 aconfig/rust_aconfig_library_test.go diff --git a/aconfig/Android.bp b/aconfig/Android.bp index 6927765a8..d2ddfdfc6 100644 --- a/aconfig/Android.bp +++ b/aconfig/Android.bp @@ -14,6 +14,7 @@ bootstrap_go_package { "soong-bazel", "soong-android", "soong-java", + "soong-rust", ], srcs: [ "aconfig_declarations.go", @@ -24,6 +25,7 @@ bootstrap_go_package { "init.go", "java_aconfig_library.go", "testing.go", + "rust_aconfig_library.go", ], testSrcs: [ "aconfig_declarations_test.go", diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go index 565d18534..d1d1578f6 100644 --- a/aconfig/aconfig_declarations.go +++ b/aconfig/aconfig_declarations.go @@ -17,8 +17,9 @@ package aconfig import ( "android/soong/android" "fmt" - "github.com/google/blueprint" "strings" + + "github.com/google/blueprint" ) type DeclarationsModule struct { diff --git a/aconfig/init.go b/aconfig/init.go index 7e283ea47..58b6b8ba8 100644 --- a/aconfig/init.go +++ b/aconfig/init.go @@ -16,6 +16,7 @@ package aconfig import ( "android/soong/android" + "github.com/google/blueprint" ) @@ -70,6 +71,20 @@ var ( }, }, "gendir") + rustRule = pctx.AndroidStaticRule("rust_aconfig_library", + blueprint.RuleParams{ + Command: `rm -rf ${gendir}` + + ` && mkdir -p ${gendir}` + + ` && ${aconfig} create-rust-lib` + + ` --mode ${mode}` + + ` --cache ${in}` + + ` --out ${gendir}`, + CommandDeps: []string{ + "$aconfig", + "$soong_zip", + }, + }, "gendir", "mode") + // For all_aconfig_declarations allDeclarationsRule = pctx.AndroidStaticRule("all_aconfig_declarations_dump", blueprint.RuleParams{ @@ -92,5 +107,6 @@ func registerBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("aconfig_value_set", ValueSetFactory) ctx.RegisterModuleType("cc_aconfig_library", CcAconfigLibraryFactory) ctx.RegisterModuleType("java_aconfig_library", JavaDeclarationsLibraryFactory) + ctx.RegisterModuleType("rust_aconfig_library", RustAconfigLibraryFactory) ctx.RegisterParallelSingletonType("all_aconfig_declarations", AllAconfigDeclarationsFactory) } diff --git a/aconfig/rust_aconfig_library.go b/aconfig/rust_aconfig_library.go new file mode 100644 index 000000000..8b1637273 --- /dev/null +++ b/aconfig/rust_aconfig_library.go @@ -0,0 +1,83 @@ +package aconfig + +import ( + "android/soong/android" + "android/soong/rust" + "fmt" + + "github.com/google/blueprint" +) + +type rustDeclarationsTagType struct { + blueprint.BaseDependencyTag +} + +var rustDeclarationsTag = rustDeclarationsTagType{} + +type RustAconfigLibraryProperties struct { + // name of the aconfig_declarations module to generate a library for + Aconfig_declarations string +} + +type aconfigDecorator struct { + *rust.BaseSourceProvider + + Properties RustAconfigLibraryProperties +} + +func NewRustAconfigLibrary(hod android.HostOrDeviceSupported) (*rust.Module, *aconfigDecorator) { + aconfig := &aconfigDecorator{ + BaseSourceProvider: rust.NewSourceProvider(), + Properties: RustAconfigLibraryProperties{}, + } + + module := rust.NewSourceProviderModule(android.HostAndDeviceSupported, aconfig, false, false) + return module, aconfig +} + +// rust_aconfig_library generates aconfig rust code from the provided aconfig declaration. This module type will +// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs +// properties of other modules. +func RustAconfigLibraryFactory() android.Module { + module, _ := NewRustAconfigLibrary(android.HostAndDeviceSupported) + return module.Init() +} + +func (a *aconfigDecorator) SourceProviderProps() []interface{} { + return append(a.BaseSourceProvider.SourceProviderProps(), &a.Properties) +} + +func (a *aconfigDecorator) GenerateSource(ctx rust.ModuleContext, deps rust.PathDeps) android.Path { + generatedDir := android.PathForModuleGen(ctx) + generatedSource := android.PathForModuleGen(ctx, "src", "lib.rs") + + declarationsModules := ctx.GetDirectDepsWithTag(rustDeclarationsTag) + + if len(declarationsModules) != 1 { + panic(fmt.Errorf("Exactly one aconfig_declarations property required")) + } + declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData) + + ctx.Build(pctx, android.BuildParams{ + Rule: rustRule, + Input: declarations.IntermediatePath, + Outputs: []android.WritablePath{ + generatedSource, + }, + Description: "rust_aconfig_library", + Args: map[string]string{ + "gendir": generatedDir.String(), + // TODO: Add test mode + "mode": "production", + }, + }) + a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource} + return generatedSource +} + +func (a *aconfigDecorator) SourceProviderDeps(ctx rust.DepsContext, deps rust.Deps) rust.Deps { + deps = a.BaseSourceProvider.SourceProviderDeps(ctx, deps) + deps.Rustlibs = append(deps.Rustlibs, "libflags_rust") + ctx.AddDependency(ctx.Module(), rustDeclarationsTag, a.Properties.Aconfig_declarations) + return deps +} diff --git a/aconfig/rust_aconfig_library_test.go b/aconfig/rust_aconfig_library_test.go new file mode 100644 index 000000000..17385c3d1 --- /dev/null +++ b/aconfig/rust_aconfig_library_test.go @@ -0,0 +1,60 @@ +package aconfig + +import ( + "android/soong/android" + "android/soong/rust" + "fmt" + "testing" +) + +func TestRustAconfigLibrary(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithAconfigBuildComponents, + rust.PrepareForTestWithRustIncludeVndk, + android.PrepareForTestWithArchMutator, + android.PrepareForTestWithDefaults, + android.PrepareForTestWithPrebuilts, + ). + ExtendWithErrorHandler(android.FixtureExpectsNoErrors). + RunTestWithBp(t, fmt.Sprintf(` + rust_library { + name: "libflags_rust", // test mock + crate_name: "flags_rust", + srcs: ["lib.rs"], + } + aconfig_declarations { + name: "my_aconfig_declarations", + package: "com.example.package", + srcs: ["foo.aconfig"], + } + + rust_aconfig_library { + name: "libmy_rust_aconfig_library", + crate_name: "my_rust_aconfig_library", + aconfig_declarations: "my_aconfig_declarations", + } + `)) + + sourceVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_source") + rule := sourceVariant.Rule("rust_aconfig_library") + android.AssertStringEquals(t, "rule must contain production mode", rule.Args["mode"], "production") + + dylibVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_dylib") + rlibRlibStdVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_rlib-std") + rlibDylibStdVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_dylib-std") + + variants := []android.TestingModule{ + dylibVariant, + rlibDylibStdVariant, + rlibRlibStdVariant, + } + + for _, variant := range variants { + android.AssertStringEquals( + t, + "dylib variant builds from generated rust code", + "out/soong/.intermediates/libmy_rust_aconfig_library/android_arm64_armv8-a_source/gen/src/lib.rs", + variant.Rule("rustc").Inputs[0].RelativeToTop().String(), + ) + } +}