diff --git a/rust/testing.go b/rust/testing.go index 0b34c9732..d9cacdc27 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -75,6 +75,7 @@ func GatherRequiredDepsForTest() string { apex_available: ["//apex_available:platform", "//apex_available:anyapex"], min_sdk_version: "29", vendor_available: true, + host_supported: true, recovery_available: true, llndk: { symbol_file: "liblog.map.txt", diff --git a/sysprop/Android.bp b/sysprop/Android.bp index 1d5eb3130..a00a5e42c 100644 --- a/sysprop/Android.bp +++ b/sysprop/Android.bp @@ -11,6 +11,7 @@ bootstrap_go_package { "soong-android", "soong-cc", "soong-java", + "soong-rust", ], srcs: [ "sysprop_library.go", diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index 766f3e7dc..22582327e 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -21,6 +21,7 @@ import ( "io" "os" "path" + "strings" "sync" "github.com/google/blueprint" @@ -29,6 +30,7 @@ import ( "android/soong/android" "android/soong/cc" "android/soong/java" + "android/soong/rust" ) type dependencyTag struct { @@ -51,7 +53,16 @@ type syspropJavaGenRule struct { genSrcjars android.Paths } +type syspropRustGenRule struct { + android.ModuleBase + + properties syspropGenProperties + + genSrcs android.Paths +} + var _ android.OutputFileProducer = (*syspropJavaGenRule)(nil) +var _ android.OutputFileProducer = (*syspropRustGenRule)(nil) var ( syspropJava = pctx.AndroidStaticRule("syspropJava", @@ -64,11 +75,20 @@ var ( "$soongZipCmd", }, }, "scope") + syspropRust = pctx.AndroidStaticRule("syspropRust", + blueprint.RuleParams{ + Command: `rm -rf $out_dir && mkdir -p $out_dir && ` + + `$syspropRustCmd --scope $scope --rust-output-dir $out_dir $in`, + CommandDeps: []string{ + "$syspropRustCmd", + }, + }, "scope", "out_dir") ) func init() { pctx.HostBinToolVariable("soongZipCmd", "soong_zip") pctx.HostBinToolVariable("syspropJavaCmd", "sysprop_java") + pctx.HostBinToolVariable("syspropRustCmd", "sysprop_rust") } // syspropJavaGenRule module generates srcjar containing generated java APIs. @@ -122,6 +142,56 @@ func syspropJavaGenFactory() android.Module { return g } +// syspropRustGenRule module generates rust source files containing generated rust APIs. +// It also depends on check api rule, so api check has to pass to use sysprop_library. +func (g *syspropRustGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + var checkApiFileTimeStamp android.WritablePath + + ctx.VisitDirectDeps(func(dep android.Module) { + if m, ok := dep.(*syspropLibrary); ok { + checkApiFileTimeStamp = m.checkApiFileTimeStamp + } + }) + + for _, syspropFile := range android.PathsForModuleSrc(ctx, g.properties.Srcs) { + syspropDir := strings.TrimSuffix(syspropFile.String(), syspropFile.Ext()) + outputDir := android.PathForModuleGen(ctx, syspropDir, "src") + libPath := android.PathForModuleGen(ctx, syspropDir, "src", "lib.rs") + parsersPath := android.PathForModuleGen(ctx, syspropDir, "src", "gen_parsers_and_formatters.rs") + + ctx.Build(pctx, android.BuildParams{ + Rule: syspropRust, + Description: "sysprop_rust " + syspropFile.Rel(), + Outputs: android.WritablePaths{libPath, parsersPath}, + Input: syspropFile, + Implicit: checkApiFileTimeStamp, + Args: map[string]string{ + "scope": g.properties.Scope, + "out_dir": outputDir.String(), + }, + }) + + g.genSrcs = append(g.genSrcs, libPath, parsersPath) + } +} + +func (g *syspropRustGenRule) DepsMutator(ctx android.BottomUpMutatorContext) { + // Add a dependency from the stubs to sysprop library so that the generator rule can depend on + // the check API rule of the sysprop library. + ctx.AddFarVariationDependencies(nil, nil, proptools.String(g.properties.Check_api)) +} + +func (g *syspropRustGenRule) OutputFiles(_ string) (android.Paths, error) { + return g.genSrcs, nil +} + +func syspropRustGenFactory() android.Module { + g := &syspropRustGenRule{} + g.AddProperties(&g.properties) + android.InitAndroidModule(g) + return g +} + type syspropLibrary struct { android.ModuleBase android.ApexModuleBase @@ -180,6 +250,12 @@ type syspropLibraryProperties struct { // Forwarded to java_library.min_sdk_version Min_sdk_version *string } + + Rust struct { + // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX). + // Forwarded to rust_library.min_sdk_version + Min_sdk_version *string + } } var ( @@ -233,6 +309,21 @@ func (m *syspropLibrary) javaGenPublicStubName() string { return m.BaseModuleName() + "_java_gen_public" } +func (m *syspropLibrary) rustGenModuleName() string { + return m.rustCrateName() + "_rust_gen" +} + +func (m *syspropLibrary) rustGenStubName() string { + return "lib" + m.rustCrateName() + "_rust" +} + +func (m *syspropLibrary) rustCrateName() string { + moduleName := strings.ToLower(m.BaseModuleName()) + moduleName = strings.ReplaceAll(moduleName, "-", "_") + moduleName = strings.ReplaceAll(moduleName, ".", "_") + return moduleName +} + func (m *syspropLibrary) BaseModuleName() string { return m.ModuleBase.Name() } @@ -436,6 +527,18 @@ type javaLibraryProperties struct { Min_sdk_version *string } +type rustLibraryProperties struct { + Name *string + Srcs []string + Installable *bool + Crate_name string + Rustlibs []string + Vendor_available *bool + Product_available *bool + Apex_available []string + Min_sdk_version *string +} + func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { if len(m.properties.Srcs) == 0 { ctx.PropertyErrorf("srcs", "sysprop_library must specify srcs") @@ -564,6 +667,28 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { }) } + // Generate a Rust implementation library. + ctx.CreateModule(syspropRustGenFactory, &syspropGenProperties{ + Srcs: m.properties.Srcs, + Scope: scope, + Name: proptools.StringPtr(m.rustGenModuleName()), + Check_api: proptools.StringPtr(ctx.ModuleName()), + }) + rustProps := rustLibraryProperties{ + Name: proptools.StringPtr(m.rustGenStubName()), + Srcs: []string{":" + m.rustGenModuleName()}, + Installable: proptools.BoolPtr(false), + Crate_name: m.rustCrateName(), + Rustlibs: []string{ + "librustutils", + }, + Vendor_available: m.properties.Vendor_available, + Product_available: m.properties.Product_available, + Apex_available: m.ApexProperties.Apex_available, + Min_sdk_version: proptools.StringPtr("29"), + } + ctx.CreateModule(rust.RustLibraryFactory, &rustProps) + // syspropLibraries will be used by property_contexts to check types. // Record absolute paths of sysprop_library to prevent soong_namespace problem. if m.ExportedToMake() { diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go index e5b3dea05..9dd696f75 100644 --- a/sysprop/sysprop_test.go +++ b/sysprop/sysprop_test.go @@ -22,6 +22,7 @@ import ( "android/soong/android" "android/soong/cc" "android/soong/java" + "android/soong/rust" "github.com/google/blueprint/proptools" ) @@ -46,18 +47,6 @@ func test(t *testing.T, bp string) *android.TestResult { recovery_available: true, } - cc_library { - name: "liblog", - no_libcrt: true, - nocrt: true, - system_shared_libs: [], - recovery_available: true, - host_supported: true, - llndk: { - symbol_file: "liblog.map.txt", - } - } - java_library { name: "sysprop-library-stub-platform", sdk_version: "core_current", @@ -74,6 +63,15 @@ func test(t *testing.T, bp string) *android.TestResult { product_specific: true, sdk_version: "core_current", } + + rust_library { + name: "librustutils", + crate_name: "rustutils", + srcs: ["librustutils/lib.rs"], + product_available: true, + vendor_available: true, + min_sdk_version: "29", + } ` mockFS := android.MockFS{ @@ -115,11 +113,14 @@ func test(t *testing.T, bp string) *android.TestResult { "android/sysprop/PlatformProperties.sysprop": nil, "com/android/VendorProperties.sysprop": nil, "com/android2/OdmProperties.sysprop": nil, + + "librustutils/lib.rs": nil, } result := android.GroupFixturePreparers( cc.PrepareForTestWithCcDefaultModules, java.PrepareForTestWithJavaDefaultModules, + rust.PrepareForTestWithRustDefaultModules, PrepareForTestWithSyspropBuildComponents, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.DeviceSystemSdkVersions = []string{"28"} @@ -356,6 +357,10 @@ func TestApexAvailabilityIsForwarded(t *testing.T) { javaModule := result.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library) propFromJava := javaModule.ApexProperties.Apex_available android.AssertDeepEquals(t, "apex_available forwarding to java module", expected, propFromJava) + + rustModule := result.ModuleForTests("libsysprop_platform_rust", "android_arm64_armv8-a_rlib_rlib-std").Module().(*rust.Module) + propFromRust := rustModule.ApexProperties.Apex_available + android.AssertDeepEquals(t, "apex_available forwarding to rust module", expected, propFromRust) } func TestMinSdkVersionIsForwarded(t *testing.T) { @@ -371,6 +376,9 @@ func TestMinSdkVersionIsForwarded(t *testing.T) { java: { min_sdk_version: "30", }, + rust: { + min_sdk_version: "29", + } } `) @@ -381,4 +389,8 @@ func TestMinSdkVersionIsForwarded(t *testing.T) { javaModule := result.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library) propFromJava := javaModule.MinSdkVersionString() android.AssertStringEquals(t, "min_sdk_version forwarding to java module", "30", propFromJava) + + rustModule := result.ModuleForTests("libsysprop_platform_rust", "android_arm64_armv8-a_rlib_rlib-std").Module().(*rust.Module) + propFromRust := proptools.String(rustModule.Properties.Min_sdk_version) + android.AssertStringEquals(t, "min_sdk_version forwarding to rust module", "29", propFromRust) }