diff options
30 files changed, 484 insertions, 146 deletions
diff --git a/Android.bp b/Android.bp index 523f55c4b..6c4066160 100644 --- a/Android.bp +++ b/Android.bp @@ -147,16 +147,6 @@ all_apex_contributions { // Framework guests. cc_defaults { name: "cc_baremetal_defaults", - arch: { - arm64: { - cflags: [ - // Prevent the compiler from optimizing code using SVE, as the - // baremetal environment might not have configured the hardware. - "-Xclang -target-feature", - "-Xclang -sve", - ], - }, - }, defaults_visibility: ["//visibility:public"], } diff --git a/aconfig/Android.bp b/aconfig/Android.bp index 6e2964a51..40aeee4b1 100644 --- a/aconfig/Android.bp +++ b/aconfig/Android.bp @@ -17,6 +17,7 @@ bootstrap_go_package { "aconfig_values.go", "aconfig_value_set.go", "all_aconfig_declarations.go", + "all_aconfig_declarations_extension.go", "exported_java_aconfig_library.go", "init.go", "testing.go", @@ -25,6 +26,7 @@ bootstrap_go_package { "aconfig_declarations_test.go", "aconfig_values_test.go", "aconfig_value_set_test.go", + "all_aconfig_declarations_extension_test.go", ], pluginFor: ["soong_build"], } diff --git a/aconfig/all_aconfig_declarations.go b/aconfig/all_aconfig_declarations.go index ec200997e..b17820ea5 100644 --- a/aconfig/all_aconfig_declarations.go +++ b/aconfig/all_aconfig_declarations.go @@ -20,6 +20,7 @@ import ( "android/soong/android" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -37,12 +38,18 @@ func AllAconfigDeclarationsFactory() android.SingletonModule { return module } +type allAconfigDeclarationsInfo struct { + parsedFlagsFile android.Path +} + +var allAconfigDeclarationsInfoProvider = blueprint.NewProvider[allAconfigDeclarationsInfo]() + type allAconfigReleaseDeclarationsSingleton struct { intermediateBinaryProtoPath android.OutputPath intermediateTextProtoPath android.OutputPath } -type allAconfigReleaseDeclarationsProperties struct { +type ApiSurfaceContributorProperties struct { Api_signature_files proptools.Configurable[[]string] `android:"arch_variant,path"` Finalized_flags_file string `android:"arch_variant,path"` } @@ -51,7 +58,9 @@ type allAconfigDeclarationsSingleton struct { android.SingletonModuleBase releaseMap map[string]allAconfigReleaseDeclarationsSingleton - properties allAconfigReleaseDeclarationsProperties + properties ApiSurfaceContributorProperties + + finalizedFlags android.OutputPath } func (this *allAconfigDeclarationsSingleton) sortedConfigNames() []string { @@ -63,29 +72,38 @@ func (this *allAconfigDeclarationsSingleton) sortedConfigNames() []string { return names } -func (this *allAconfigDeclarationsSingleton) GenerateAndroidBuildActions(ctx android.ModuleContext) { +func GenerateFinalizedFlagsForApiSurface(ctx android.ModuleContext, outputPath android.WritablePath, + parsedFlagsFile android.Path, apiSurface ApiSurfaceContributorProperties) { + apiSignatureFiles := android.Paths{} - for _, apiSignatureFile := range this.properties.Api_signature_files.GetOrDefault(ctx, nil) { + for _, apiSignatureFile := range apiSurface.Api_signature_files.GetOrDefault(ctx, nil) { if path := android.PathForModuleSrc(ctx, apiSignatureFile); path != nil { apiSignatureFiles = append(apiSignatureFiles, path) } } - finalizedFlagsFile := android.PathForModuleSrc(ctx, this.properties.Finalized_flags_file) - parsedFlagsFile := android.PathForIntermediates(ctx, "all_aconfig_declarations.pb") - - output := android.PathForIntermediates(ctx, "finalized-flags.txt") + finalizedFlagsFile := android.PathForModuleSrc(ctx, apiSurface.Finalized_flags_file) ctx.Build(pctx, android.BuildParams{ Rule: RecordFinalizedFlagsRule, Inputs: append(apiSignatureFiles, finalizedFlagsFile, parsedFlagsFile), - Output: output, + Output: outputPath, Args: map[string]string{ "api_signature_files": android.JoinPathsWithPrefix(apiSignatureFiles, "--api-signature-file "), "finalized_flags_file": "--finalized-flags-file " + finalizedFlagsFile.String(), "parsed_flags_file": "--parsed-flags-file " + parsedFlagsFile.String(), }, }) - ctx.Phony("all_aconfig_declarations", output) +} + +func (this *allAconfigDeclarationsSingleton) GenerateAndroidBuildActions(ctx android.ModuleContext) { + parsedFlagsFile := android.PathForIntermediates(ctx, "all_aconfig_declarations.pb") + this.finalizedFlags = android.PathForIntermediates(ctx, "finalized-flags.txt") + GenerateFinalizedFlagsForApiSurface(ctx, this.finalizedFlags, parsedFlagsFile, this.properties) + ctx.Phony("all_aconfig_declarations", this.finalizedFlags) + + android.SetProvider(ctx, allAconfigDeclarationsInfoProvider, allAconfigDeclarationsInfo{ + parsedFlagsFile: parsedFlagsFile, + }) } func (this *allAconfigDeclarationsSingleton) GenerateSingletonBuildActions(ctx android.SingletonContext) { @@ -154,5 +172,5 @@ func (this *allAconfigDeclarationsSingleton) MakeVars(ctx android.MakeVarsContex ctx.DistForGoalWithFilename(goal, this.releaseMap[rcName].intermediateTextProtoPath, assembleFileName(rcName, "flags.textproto")) } } - ctx.DistForGoalWithFilename("sdk", android.PathForIntermediates(ctx, "finalized-flags.txt"), "finalized-flags.txt") + ctx.DistForGoalWithFilename("sdk", this.finalizedFlags, "finalized-flags.txt") } diff --git a/aconfig/all_aconfig_declarations_extension.go b/aconfig/all_aconfig_declarations_extension.go new file mode 100644 index 000000000..44992cd2a --- /dev/null +++ b/aconfig/all_aconfig_declarations_extension.go @@ -0,0 +1,90 @@ +// Copyright 2025 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aconfig + +import ( + "android/soong/android" + "path" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +func AllAconfigDeclarationsExtensionFactory() android.Module { + module := &allAconfigDeclarationsExtension{} + module.AddProperties(&module.properties) + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + return module +} + +type allAconfigDeclarationsExtensionProperties struct { + // all_aconfig_declarations module that this module extends. Defaults to + // all_aconfig_declarations. + Base *string + + // Directory where the dist artifact should be placed in. + Dist_dir *string + + ApiSurfaceContributorProperties +} + +type allAconfigDeclarationsExtension struct { + android.ModuleBase + + properties allAconfigDeclarationsExtensionProperties + + finalizedFlags android.ModuleOutPath +} + +type allAconfigDeclarationsDependencyTagStruct struct { + blueprint.BaseDependencyTag +} + +var allAconfigDeclarationsDependencyTag allAconfigDeclarationsDependencyTagStruct + +func (ext *allAconfigDeclarationsExtension) DepsMutator(ctx android.BottomUpMutatorContext) { + ctx.AddDependency(ctx.Module(), allAconfigDeclarationsDependencyTag, proptools.StringDefault(ext.properties.Base, "all_aconfig_declarations")) +} + +func (ext *allAconfigDeclarationsExtension) GenerateAndroidBuildActions(ctx android.ModuleContext) { + + var parsedFlagsFile android.Path + ctx.VisitDirectDepsProxyWithTag(allAconfigDeclarationsDependencyTag, func(proxy android.ModuleProxy) { + if info, ok := android.OtherModuleProvider(ctx, proxy, allAconfigDeclarationsInfoProvider); ok { + parsedFlagsFile = info.parsedFlagsFile + } else { + ctx.PropertyErrorf("base", "base must provide allAconfigDeclarationsInfo") + } + }) + + ext.finalizedFlags = android.PathForModuleOut(ctx, "finalized-flags.txt") + + GenerateFinalizedFlagsForApiSurface(ctx, + ext.finalizedFlags, + parsedFlagsFile, + ext.properties.ApiSurfaceContributorProperties, + ) + + ctx.Phony(ctx.ModuleName(), ext.finalizedFlags) + + // This module must not set any provider or call `ctx.SetOutputFiles`! + // This module is only used to depend on the singleton module all_aconfig_declarations and + // generate the custom finalized-flags.txt file in dist builds, and should not be depended + // by other modules. +} + +func (ext *allAconfigDeclarationsExtension) MakeVars(ctx android.MakeVarsContext) { + ctx.DistForGoalWithFilename("sdk", ext.finalizedFlags, path.Join(proptools.String(ext.properties.Dist_dir), "finalized-flags.txt")) +} diff --git a/aconfig/all_aconfig_declarations_extension_test.go b/aconfig/all_aconfig_declarations_extension_test.go new file mode 100644 index 000000000..120709693 --- /dev/null +++ b/aconfig/all_aconfig_declarations_extension_test.go @@ -0,0 +1,50 @@ +// Copyright 2025 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aconfig + +import ( + "strings" + "testing" + + "android/soong/android" +) + +func TestAllAconfigDeclarationsExtension(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithAconfigBuildComponents, + android.FixtureMergeMockFs( + android.MockFS{ + "a.txt": nil, + "flags.txt": nil, + }, + ), + ).RunTestWithBp(t, ` + all_aconfig_declarations { + name: "all_aconfig_declarations", + } + + all_aconfig_declarations_extension { + name: "custom_aconfig_declarations", + base: "all_aconfig_declarations", + api_signature_files: [ + "a.txt", + ], + finalized_flags_file: "flags.txt", + } + `) + + finalizedFlags := result.ModuleForTests("custom_aconfig_declarations", "").Output("finalized-flags.txt") + android.AssertStringContainsEquals(t, "must depend on all_aconfig_declarations", strings.Join(finalizedFlags.Inputs.Strings(), " "), "all_aconfig_declarations.pb", true) +} diff --git a/aconfig/build_flags/build_flags_singleton.go b/aconfig/build_flags/build_flags_singleton.go index 3b407556f..e76db49d5 100644 --- a/aconfig/build_flags/build_flags_singleton.go +++ b/aconfig/build_flags/build_flags_singleton.go @@ -16,6 +16,7 @@ package build_flags import ( "android/soong/android" + "fmt" ) // A singleton module that collects all of the build flags declared in the @@ -120,4 +121,26 @@ func (this *allBuildFlagDeclarationsSingleton) MakeVars(ctx android.MakeVarsCont ctx.DistForGoalWithFilename(goal, this.configsBinaryProtoPath, "build_flags/all_release_config_contributions.pb") ctx.DistForGoalWithFilename(goal, this.configsTextProtoPath, "build_flags/all_release_config_contributions.textproto") } + + if ctx.Config().HasDeviceProduct() { + flagsDir := android.PathForOutput(ctx, "release-config") + baseAllRelease := fmt.Sprintf("all_release_configs-%s", ctx.Config().DeviceProduct()) + + distAllReleaseConfigsArtifact := func(ext string) { + ctx.DistForGoalWithFilename( + "droid", + flagsDir.Join(ctx, fmt.Sprintf("%s.%s", baseAllRelease, ext)), + fmt.Sprintf("build_flags/all_release_configs.%s", ext), + ) + } + + distAllReleaseConfigsArtifact("pb") + distAllReleaseConfigsArtifact("textproto") + distAllReleaseConfigsArtifact("json") + ctx.DistForGoalWithFilename( + "droid", + flagsDir.Join(ctx, fmt.Sprintf("inheritance_graph-%s.dot", ctx.Config().DeviceProduct())), + fmt.Sprintf("build_flags/inheritance_graph-%s.dot", ctx.Config().DeviceProduct()), + ) + } } diff --git a/aconfig/init.go b/aconfig/init.go index 3dcec5cd8..b2fe5a309 100644 --- a/aconfig/init.go +++ b/aconfig/init.go @@ -104,6 +104,7 @@ var ( ` --mode=exported` + ` --allow-instrumentation ${use_new_storage}` + ` --new-exported ${use_new_exported}` + + ` --single-exported-file true` + ` --check-api-level ${check_api_level}` + ` --out ${out}.tmp; ` + ` fi ` + @@ -131,4 +132,5 @@ func RegisterBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("aconfig_value_set", ValueSetFactory) ctx.RegisterSingletonModuleType("all_aconfig_declarations", AllAconfigDeclarationsFactory) ctx.RegisterParallelSingletonType("exported_java_aconfig_library", ExportedJavaDeclarationsLibraryFactory) + ctx.RegisterModuleType("all_aconfig_declarations_extension", AllAconfigDeclarationsExtensionFactory) } diff --git a/android/module.go b/android/module.go index 80275a309..3295e93be 100644 --- a/android/module.go +++ b/android/module.go @@ -1091,6 +1091,10 @@ var vintfDepTag = struct { InstallAlwaysNeededDependencyTag }{} +func IsVintfDepTag(depTag blueprint.DependencyTag) bool { + return depTag == vintfDepTag +} + func addVintfFragmentDeps(ctx BottomUpMutatorContext) { // Vintf manifests in the recovery partition will be ignored. if !ctx.Device() || ctx.Module().InstallInRecovery() { @@ -1109,7 +1113,7 @@ func addVintfFragmentDeps(ctx BottomUpMutatorContext) { // of nil pointer dereference errors, but we should resolve the missing dependencies. continue } - if vintfModule, ok := vintf.(*vintfFragmentModule); ok { + if vintfModule, ok := vintf.(*VintfFragmentModule); ok { vintfPartition := vintfModule.PartitionTag(deviceConfig) if modPartition != vintfPartition { ctx.ModuleErrorf("Module %q(%q) and Vintf_fragment %q(%q) are installed to different partitions.", diff --git a/android/mutator.go b/android/mutator.go index 76487fbad..d6166d2de 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -67,7 +67,6 @@ type registerMutatorsContext struct { } type RegisterMutatorsContext interface { - TopDown(name string, m TopDownMutator) MutatorHandle BottomUp(name string, m BottomUpMutator) MutatorHandle BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle Transition(name string, m VariationTransitionMutator) TransitionMutatorHandle @@ -195,17 +194,6 @@ func FinalDepsMutators(f RegisterMutatorFunc) { finalDeps = append(finalDeps, f) } -type TopDownMutator func(TopDownMutatorContext) - -type TopDownMutatorContext interface { - BaseModuleContext -} - -type topDownMutatorContext struct { - bp blueprint.TopDownMutatorContext - baseModuleContext -} - type BottomUpMutator func(BottomUpMutatorContext) type BottomUpMutatorContext interface { @@ -281,8 +269,8 @@ type BottomUpMutatorContext interface { } // An outgoingTransitionContextImpl and incomingTransitionContextImpl is created for every dependency of every module -// for each transition mutator. bottomUpMutatorContext and topDownMutatorContext are created once for every module -// for every BottomUp or TopDown mutator. Use a global pool for each to avoid reallocating every time. +// for each transition mutator. bottomUpMutatorContext is created once for every module for every BottomUp mutator. +// Use a global pool for each to avoid reallocating every time. var ( outgoingTransitionContextPool = sync.Pool{ New: func() any { return &outgoingTransitionContextImpl{} }, @@ -293,10 +281,6 @@ var ( bottomUpMutatorContextPool = sync.Pool{ New: func() any { return &bottomUpMutatorContext{} }, } - - topDownMutatorContextPool = sync.Pool{ - New: func() any { return &topDownMutatorContext{} }, - } ) type bottomUpMutatorContext struct { @@ -371,24 +355,6 @@ func (x *registerMutatorsContext) mutatorName(name string) string { return name } -func (x *registerMutatorsContext) TopDown(name string, m TopDownMutator) MutatorHandle { - f := func(ctx blueprint.TopDownMutatorContext) { - if a, ok := ctx.Module().(Module); ok { - moduleContext := a.base().baseModuleContextFactory(ctx) - actx := topDownMutatorContextPool.Get().(*topDownMutatorContext) - defer topDownMutatorContextPool.Put(actx) - *actx = topDownMutatorContext{ - bp: ctx, - baseModuleContext: moduleContext, - } - m(actx) - } - } - mutator := &mutator{name: x.mutatorName(name), topDownMutator: f} - x.mutators = append(x.mutators, mutator) - return mutator -} - func (mutator *mutator) componentName() string { return mutator.name } @@ -398,8 +364,6 @@ func (mutator *mutator) register(ctx *Context) { var handle blueprint.MutatorHandle if mutator.bottomUpMutator != nil { handle = blueprintCtx.RegisterBottomUpMutator(mutator.name, mutator.bottomUpMutator) - } else if mutator.topDownMutator != nil { - handle = blueprintCtx.RegisterTopDownMutator(mutator.name, mutator.topDownMutator) } else if mutator.transitionMutator != nil { handle := blueprintCtx.RegisterTransitionMutator(mutator.name, mutator.transitionMutator) if mutator.neverFar { @@ -529,11 +493,11 @@ func registerDepsMutator(ctx RegisterMutatorsContext) { ctx.BottomUp("deps", depsMutator).UsesReverseDependencies() } -// android.topDownMutatorContext either has to embed blueprint.TopDownMutatorContext, in which case every method that +// android.bottomUpMutatorContext either has to embed blueprint.BottomUpMutatorContext, in which case every method that // has an overridden version in android.BaseModuleContext has to be manually forwarded to BaseModuleContext to avoid -// ambiguous method errors, or it has to store a blueprint.TopDownMutatorContext non-embedded, in which case every +// ambiguous method errors, or it has to store a blueprint.BottomUpMutatorContext non-embedded, in which case every // non-overridden method has to be forwarded. There are fewer non-overridden methods, so use the latter. The following -// methods forward to the identical blueprint versions for topDownMutatorContext and bottomUpMutatorContext. +// methods forward to the identical blueprint versions for bottomUpMutatorContext. func (b *bottomUpMutatorContext) Rename(name string) { b.bp.Rename(name) diff --git a/android/mutator_test.go b/android/mutator_test.go index 60a61199f..123c6b203 100644 --- a/android/mutator_test.go +++ b/android/mutator_test.go @@ -54,7 +54,7 @@ func (m *mutatorTestModule) DepsMutator(ctx BottomUpMutatorContext) { ctx.AddDependency(ctx.Module(), nil, m.props.Deps_missing_deps...) } -func addMissingDependenciesMutator(ctx TopDownMutatorContext) { +func addMissingDependenciesMutator(ctx BottomUpMutatorContext) { ctx.AddMissingDependencies(ctx.Module().(*mutatorTestModule).props.Mutator_missing_deps) } @@ -72,7 +72,7 @@ func TestMutatorAddMissingDependencies(t *testing.T) { FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.RegisterModuleType("test", mutatorTestModuleFactory) ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { - ctx.TopDown("add_missing_dependencies", addMissingDependenciesMutator) + ctx.BottomUp("add_missing_dependencies", addMissingDependenciesMutator) }) }), FixtureWithRootAndroidBp(bp), diff --git a/android/provider.go b/android/provider.go index 81d17a175..b48fd9148 100644 --- a/android/provider.go +++ b/android/provider.go @@ -4,8 +4,8 @@ import ( "github.com/google/blueprint" ) -// OtherModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or -// TopDownMutatorContext for use in OtherModuleProvider. +// OtherModuleProviderContext is a helper interface that is a subset of ModuleContext or BottomUpMutatorContext +// for use in OtherModuleProvider. type OtherModuleProviderContext interface { otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) } @@ -13,7 +13,6 @@ type OtherModuleProviderContext interface { var _ OtherModuleProviderContext = BaseModuleContext(nil) var _ OtherModuleProviderContext = ModuleContext(nil) var _ OtherModuleProviderContext = BottomUpMutatorContext(nil) -var _ OtherModuleProviderContext = TopDownMutatorContext(nil) var _ OtherModuleProviderContext = SingletonContext(nil) var _ OtherModuleProviderContext = (*TestContext)(nil) @@ -21,8 +20,7 @@ var _ OtherModuleProviderContext = (*TestContext)(nil) // returned and the boolean is true. If it has not been set the zero value of the provider's type is returned // and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider. // -// OtherModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or -// TopDownMutatorContext. +// OtherModuleProviderContext is a helper interface that accepts ModuleContext or BottomUpMutatorContext. func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) (K, bool) { value, ok := ctx.otherModuleProvider(getWrappedModule(module), provider) if !ok { @@ -37,8 +35,8 @@ func OtherModuleProviderOrDefault[K any](ctx OtherModuleProviderContext, module return value } -// ModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or -// TopDownMutatorContext for use in ModuleProvider. +// ModuleProviderContext is a helper interface that is a subset of ModuleContext or BottomUpMutatorContext +// for use in ModuleProvider. type ModuleProviderContext interface { provider(provider blueprint.AnyProviderKey) (any, bool) } @@ -46,14 +44,12 @@ type ModuleProviderContext interface { var _ ModuleProviderContext = BaseModuleContext(nil) var _ ModuleProviderContext = ModuleContext(nil) var _ ModuleProviderContext = BottomUpMutatorContext(nil) -var _ ModuleProviderContext = TopDownMutatorContext(nil) // ModuleProvider reads the provider for the current module. If the provider has been set the value is // returned and the boolean is true. If it has not been set the zero value of the provider's type is returned // and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider. // -// ModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or -// TopDownMutatorContext. +// ModuleProviderContext is a helper interface that accepts ModuleContext or BottomUpMutatorContext. func ModuleProvider[K any](ctx ModuleProviderContext, provider blueprint.ProviderKey[K]) (K, bool) { value, ok := ctx.provider(provider) if !ok { @@ -63,8 +59,8 @@ func ModuleProvider[K any](ctx ModuleProviderContext, provider blueprint.Provide return value.(K), ok } -// SetProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or -// TopDownMutatorContext for use in SetProvider. +// SetProviderContext is a helper interface that is a subset of ModuleContext or BottomUpMutatorContext +// for use in SetProvider. type SetProviderContext interface { setProvider(provider blueprint.AnyProviderKey, value any) } @@ -72,15 +68,13 @@ type SetProviderContext interface { var _ SetProviderContext = BaseModuleContext(nil) var _ SetProviderContext = ModuleContext(nil) var _ SetProviderContext = BottomUpMutatorContext(nil) -var _ SetProviderContext = TopDownMutatorContext(nil) // SetProvider sets the value for a provider for the current module. It panics if not called // during the appropriate mutator or GenerateBuildActions pass for the provider, if the value // is not of the appropriate type, or if the value has already been set. The value should not // be modified after being passed to SetProvider. // -// SetProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or -// TopDownMutatorContext. +// SetProviderContext is a helper interface that accepts ModuleContext or BottomUpMutatorContext. func SetProvider[K any](ctx SetProviderContext, provider blueprint.ProviderKey[K], value K) { ctx.setProvider(provider, value) } diff --git a/android/register.go b/android/register.go index 332ec271c..10c9114f5 100644 --- a/android/register.go +++ b/android/register.go @@ -89,7 +89,6 @@ var singletons sortableComponents type mutator struct { name string bottomUpMutator blueprint.BottomUpMutator - topDownMutator blueprint.TopDownMutator transitionMutator blueprint.TransitionMutator usesRename bool diff --git a/android/util.go b/android/util.go index 30d8ec6b3..e8d9301dd 100644 --- a/android/util.go +++ b/android/util.go @@ -221,13 +221,13 @@ func ListSetDifference[T comparable](l1, l2 []T) (bool, []T, []T) { diff2 := []T{} m1 := setFromList(l1) m2 := setFromList(l2) - for t := range m1 { + for _, t := range l1 { if _, ok := m2[t]; !ok { diff1 = append(diff1, t) listsDiffer = true } } - for t := range m2 { + for _, t := range l2 { if _, ok := m1[t]; !ok { diff2 = append(diff2, t) listsDiffer = true diff --git a/android/vintf_fragment.go b/android/vintf_fragment.go index a3343fd5a..85beb725c 100644 --- a/android/vintf_fragment.go +++ b/android/vintf_fragment.go @@ -19,8 +19,9 @@ type vintfFragmentProperties struct { Src string `android:"path"` } -type vintfFragmentModule struct { +type VintfFragmentModule struct { ModuleBase + ApexModuleBase properties vintfFragmentProperties @@ -40,7 +41,7 @@ func registerVintfFragmentComponents(ctx RegistrationContext) { // Vintf fragment files formerly listed in vintf_fragment property would be transformed into // this module type. func vintfLibraryFactory() Module { - m := &vintfFragmentModule{} + m := &VintfFragmentModule{} m.AddProperties( &m.properties, ) @@ -49,7 +50,7 @@ func vintfLibraryFactory() Module { return m } -func (m *vintfFragmentModule) GenerateAndroidBuildActions(ctx ModuleContext) { +func (m *VintfFragmentModule) GenerateAndroidBuildActions(ctx ModuleContext) { builder := NewRuleBuilder(pctx, ctx) srcVintfFragment := PathForModuleSrc(ctx, m.properties.Src) processedVintfFragment := PathForModuleOut(ctx, srcVintfFragment.Base()) @@ -69,8 +70,12 @@ func (m *vintfFragmentModule) GenerateAndroidBuildActions(ctx ModuleContext) { ctx.InstallFile(m.installDirPath, processedVintfFragment.Base(), processedVintfFragment) } +func (m *VintfFragmentModule) OutputFile() Path { + return m.outputFilePath +} + // Make this module visible to AndroidMK so it can be referenced from modules defined from Android.mk files -func (m *vintfFragmentModule) AndroidMkEntries() []AndroidMkEntries { +func (m *VintfFragmentModule) AndroidMkEntries() []AndroidMkEntries { return []AndroidMkEntries{{ Class: "ETC", OutputFile: OptionalPathForPath(m.outputFilePath), @@ -82,3 +87,11 @@ func (m *vintfFragmentModule) AndroidMkEntries() []AndroidMkEntries { }, }} } + +var _ ApexModule = (*VintfFragmentModule)(nil) + +// Implements android.ApexModule +func (m *VintfFragmentModule) ShouldSupportSdkVersion(ctx BaseModuleContext, sdkVersion ApiLevel) error { + // VintfFragmetModule is independent from the SDK version. + return nil +} diff --git a/apex/apex.go b/apex/apex.go index 33538fb13..04816580d 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -1475,6 +1475,12 @@ func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.Platform return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, config) } +func apexFileForVintfFragment(ctx android.BaseModuleContext, vintfFragment *android.VintfFragmentModule) apexFile { + dirInApex := filepath.Join("etc", "vintf") + + return newApexFile(ctx, vintfFragment.OutputFile(), vintfFragment.BaseModuleName(), dirInApex, etc, vintfFragment) +} + // javaModule is an interface to handle all Java modules (java_library, dex_import, etc) in the same // way. type javaModule interface { @@ -2160,7 +2166,13 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, // nothing } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName) + } else if android.IsVintfDepTag(depTag) { + if vf, ok := child.(*android.VintfFragmentModule); ok { + apexFile := apexFileForVintfFragment(ctx, vf) + vctx.filesInfo = append(vctx.filesInfo, apexFile) + } } + return false } diff --git a/apex/apex_test.go b/apex/apex_test.go index f88c09ebd..6c1a2d66b 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -12184,3 +12184,35 @@ func TestFilesystemWithApexDeps(t *testing.T) { fileList := android.ContentFromFileRuleForTests(t, result, partition.Output("fileList")) android.AssertDeepEquals(t, "filesystem with apex", "apex/myapex.apex\n", fileList) } + +func TestVintfFragmentInApex(t *testing.T) { + t.Parallel() + ctx := testApex(t, apex_default_bp+` + apex { + name: "myapex", + manifest: ":myapex.manifest", + androidManifest: ":myapex.androidmanifest", + key: "myapex.key", + binaries: [ "mybin" ], + updatable: false, + } + + cc_binary { + name: "mybin", + srcs: ["mybin.cpp"], + vintf_fragment_modules: ["my_vintf_fragment.xml"], + apex_available: [ "myapex" ], + } + + vintf_fragment { + name: "my_vintf_fragment.xml", + src: "my_vintf_fragment.xml", + } + `) + + generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("generateFsConfig") + cmd := generateFsRule.RuleParams.Command + + // Ensure that vintf fragment file is being installed + ensureContains(t, cmd, "/etc/vintf/my_vintf_fragment.xml ") +} diff --git a/apex/builder.go b/apex/builder.go index b34dc84a6..03a0bb902 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -528,9 +528,10 @@ func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android }) } -func isVintfFragment(fi apexFile) bool { +func shouldApplyAssembleVintf(fi apexFile) bool { isVintfFragment, _ := path.Match("etc/vintf/*", fi.path()) - return isVintfFragment + _, fromVintfFragmentModule := fi.module.(*android.VintfFragmentModule) + return isVintfFragment && !fromVintfFragmentModule } func runAssembleVintf(ctx android.ModuleContext, vintfFragment android.Path) android.Path { @@ -639,7 +640,7 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath) } else { // Copy the file into APEX - if !a.testApex && isVintfFragment(fi) { + if !a.testApex && shouldApplyAssembleVintf(fi) { // copy the output of assemble_vintf instead of the original vintfFragment := runAssembleVintf(ctx, fi.builtFile) copyCommands = append(copyCommands, "cp -f "+vintfFragment.String()+" "+destPath) diff --git a/cc/binary.go b/cc/binary.go index 4b77bea64..c4791c519 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -426,7 +426,7 @@ func (binary *binaryDecorator) link(ctx ModuleContext, validations = append(validations, objs.tidyDepFiles...) linkerDeps = append(linkerDeps, flags.LdFlagsDeps...) - if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil { + if generatedLib := GenerateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil { deps.StaticLibs = append(deps.StaticLibs, generatedLib) } diff --git a/cc/builder.go b/cc/builder.go index 16f006d37..f4f85962d 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -817,7 +817,7 @@ func transformObjToStaticLib(ctx android.ModuleContext, } // Generate a Rust staticlib from a list of rlibDeps. Returns nil if TransformRlibstoStaticlib is nil or rlibDeps is empty. -func generateRustStaticlib(ctx android.ModuleContext, rlibDeps []RustRlibDep) android.Path { +func GenerateRustStaticlib(ctx android.ModuleContext, rlibDeps []RustRlibDep) android.Path { if TransformRlibstoStaticlib == nil && len(rlibDeps) > 0 { // This should only be reachable if a module defines Rust deps in static_libs and // soong-rust hasn't been loaded alongside soong-cc (e.g. in soong-cc tests). diff --git a/cc/library.go b/cc/library.go index dce3b9229..532b7e9aa 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1237,7 +1237,7 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, linkerDeps = append(linkerDeps, deps.SharedLibsDeps...) linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...) - if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil && !library.BuildStubs() { + if generatedLib := GenerateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil && !library.BuildStubs() { if ctx.Module().(*Module).WholeRustStaticlib { deps.WholeStaticLibs = append(deps.WholeStaticLibs, generatedLib) } else { diff --git a/filesystem/android_device.go b/filesystem/android_device.go index b783d0f57..960c96acf 100644 --- a/filesystem/android_device.go +++ b/filesystem/android_device.go @@ -153,7 +153,7 @@ func (a *androidDevice) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } - //a.buildTargetFilesZip(ctx) TODO(b/393203512): re-enable target_files.zip + a.buildTargetFilesZip(ctx) var deps []android.Path if proptools.String(a.partitionProps.Super_partition_name) != "" { superImage := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index 9f2b239a0..3f774331d 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -537,14 +537,27 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { f.buildEventLogtagsFile(ctx, builder, rebasedDir, &fullInstallPaths) f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir, &fullInstallPaths) f.filesystemBuilder.BuildLinkerConfigFile(ctx, builder, rebasedDir, &fullInstallPaths) + // Assemeble the staging dir and output a timestamp + builder.Command().Text("touch").Output(f.fileystemStagingDirTimestamp(ctx)) + builder.Build("assemble_filesystem_staging_dir", fmt.Sprintf("Assemble filesystem staging dir %s", f.BaseModuleName())) + // Create a new rule builder for build_image + builder = android.NewRuleBuilder(pctx, ctx) var mapFile android.Path - var outputHermetic android.Path + var outputHermetic android.WritablePath var buildImagePropFile android.Path var buildImagePropFileDeps android.Paths switch f.fsType(ctx) { case ext4Type, erofsType, f2fsType: - f.output, outputHermetic, buildImagePropFile, buildImagePropFileDeps = f.buildImageUsingBuildImage(ctx, builder, rootDir, rebasedDir) + buildImagePropFile, buildImagePropFileDeps = f.buildPropFile(ctx) + output := android.PathForModuleOut(ctx, f.installFileName()) + f.buildImageUsingBuildImage(ctx, builder, buildImageParams{rootDir, buildImagePropFile, buildImagePropFileDeps, output}) + f.output = output + // Create the hermetic img file using a separate rule builder so that it can be built independently + hermeticBuilder := android.NewRuleBuilder(pctx, ctx) + outputHermetic = android.PathForModuleOut(ctx, "for_target_files", f.installFileName()) + propFileHermetic := f.propFileForHermeticImg(ctx, hermeticBuilder, buildImagePropFile) + f.buildImageUsingBuildImage(ctx, hermeticBuilder, buildImageParams{rootDir, propFileHermetic, buildImagePropFileDeps, outputHermetic}) mapFile = f.getMapFile(ctx) case compressedCpioType: f.output = f.buildCpioImage(ctx, builder, rootDir, true) @@ -590,6 +603,10 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { f.setVbmetaPartitionProvider(ctx) } +func (f *filesystem) fileystemStagingDirTimestamp(ctx android.ModuleContext) android.WritablePath { + return android.PathForModuleOut(ctx, "staging_dir.timestamp") +} + func (f *filesystem) setVbmetaPartitionProvider(ctx android.ModuleContext) { var extractedPublicKey android.ModuleOutPath if f.properties.Avb_private_key != nil { @@ -783,21 +800,26 @@ func (f *filesystem) rootDirString() string { return f.partitionName() } +type buildImageParams struct { + // inputs + rootDir android.OutputPath + propFile android.Path + toolDeps android.Paths + // outputs + output android.WritablePath +} + func (f *filesystem) buildImageUsingBuildImage( ctx android.ModuleContext, builder *android.RuleBuilder, - rootDir android.OutputPath, - rebasedDir android.OutputPath, -) (android.Path, android.Path, android.Path, android.Paths) { + params buildImageParams) { // run host_init_verifier // Ideally we should have a concept of pluggable linters that verify the generated image. // While such concept is not implement this will do. // TODO(b/263574231): substitute with pluggable linter. builder.Command(). BuiltTool("host_init_verifier"). - FlagWithArg("--out_system=", rootDir.String()+"/system") - - propFile, toolDeps := f.buildPropFile(ctx) + FlagWithArg("--out_system=", params.rootDir.String()+"/system") // Most of the time, if build_image were to call a host tool, it accepts the path to the // host tool in a field in the prop file. However, it doesn't have that option for fec, which @@ -805,44 +827,32 @@ func (f *filesystem) buildImageUsingBuildImage( fec := ctx.Config().HostToolPath(ctx, "fec") pathToolDirs := []string{filepath.Dir(fec.String())} - output := android.PathForModuleOut(ctx, f.installFileName()) - builder.Command().Text("touch").Output(f.getMapFile(ctx)) builder.Command(). Textf("PATH=%s:$PATH", strings.Join(pathToolDirs, ":")). BuiltTool("build_image"). - Text(rootDir.String()). // input directory - Input(propFile). - Implicits(toolDeps). + Text(params.rootDir.String()). // input directory + Input(params.propFile). + Implicits(params.toolDeps). Implicit(fec). - Output(output). - Text(rootDir.String()) // directory where to find fs_config_files|dirs - - // TODO (b/393203512): Re-enable hermetic img file creation for target_files.zip - // Add an additional cmd to create a hermetic img file. This will contain pinned timestamps e.g. - //propFilePinnedTimestamp := android.PathForModuleOut(ctx, "for_target_files", "prop") - //builder.Command().Textf("cat").Input(propFile).Flag(">").Output(propFilePinnedTimestamp). - // Textf(" && echo use_fixed_timestamp=true >> %s", propFilePinnedTimestamp). - // Textf(" && echo block_list=%s >> %s", f.getMapFile(ctx).String(), propFilePinnedTimestamp) // mapfile will be an implicit output - - //outputHermetic := android.PathForModuleOut(ctx, "for_target_files", f.installFileName()) - //builder.Command(). - // Textf("PATH=%s:$PATH", strings.Join(pathToolDirs, ":")). - // BuiltTool("build_image"). - // Text(rootDir.String()). // input directory - // Flag(propFilePinnedTimestamp.String()). - // Implicits(toolDeps). - // Implicit(fec). - // Output(outputHermetic). - // Text(rootDir.String()) // directory where to find fs_config_files|dirs + Implicit(f.fileystemStagingDirTimestamp(ctx)). // assemble the staging directory + Output(params.output). + Text(params.rootDir.String()) // directory where to find fs_config_files|dirs if f.properties.Partition_size != nil { - assertMaxImageSize(builder, output, *f.properties.Partition_size, false) + assertMaxImageSize(builder, params.output, *f.properties.Partition_size, false) } // rootDir is not deleted. Might be useful for quick inspection. - builder.Build("build_filesystem_image", fmt.Sprintf("Creating filesystem %s", f.BaseModuleName())) + builder.Build("build_"+params.output.String(), fmt.Sprintf("Creating filesystem %s", f.BaseModuleName())) +} - return output, nil, propFile, toolDeps +func (f *filesystem) propFileForHermeticImg(ctx android.ModuleContext, builder *android.RuleBuilder, inputPropFile android.Path) android.Path { + propFilePinnedTimestamp := android.PathForModuleOut(ctx, "for_target_files", "prop") + builder.Command().Textf("cat").Input(inputPropFile).Flag(">").Output(propFilePinnedTimestamp). + Textf(" && echo use_fixed_timestamp=true >> %s", propFilePinnedTimestamp). + Textf(" && echo block_list=%s >> %s", f.getMapFile(ctx).String(), propFilePinnedTimestamp) // mapfile will be an implicit output + builder.Command().Text("touch").Output(f.getMapFile(ctx)) + return propFilePinnedTimestamp } func (f *filesystem) buildFileContexts(ctx android.ModuleContext) android.Path { @@ -1053,6 +1063,7 @@ func (f *filesystem) buildCpioImage( output := android.PathForModuleOut(ctx, f.installFileName()) cmd := builder.Command(). BuiltTool("mkbootfs"). + Implicit(f.fileystemStagingDirTimestamp(ctx)). Text(rootDir.String()) // input directory for i := range len(rootDirs) { @@ -1373,3 +1384,9 @@ func addAutogeneratedRroDeps(ctx android.BottomUpMutatorContext) { return true }) } + +func (f *filesystem) MakeVars(ctx android.MakeVarsModuleContext) { + if f.Name() == ctx.Config().SoongDefinedSystemImage() { + ctx.StrictRaw("SOONG_DEFINED_SYSTEM_IMAGE_PATH", f.output.String()) + } +} diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go index d9bf24299..37260c17d 100644 --- a/filesystem/filesystem_test.go +++ b/filesystem/filesystem_test.go @@ -332,7 +332,7 @@ func TestFileSystemWithCoverageVariants(t *testing.T) { `) filesystem := result.ModuleForTests("myfilesystem", "android_common_cov") - inputs := filesystem.Output("myfilesystem.img").Implicits + inputs := filesystem.Output("staging_dir.timestamp").Implicits android.AssertStringListContains(t, "filesystem should have libfoo(cov)", inputs.Strings(), "out/soong/.intermediates/libfoo/android_arm64_armv8-a_shared_cov/libfoo.so") diff --git a/java/base.go b/java/base.go index d89c324a5..3a435a173 100644 --- a/java/base.go +++ b/java/base.go @@ -2948,14 +2948,18 @@ func (module *Module) collectJarJarRules(ctx android.ModuleContext) *JarJarProvi // Get the jarjar rule text for a given provider for the fully resolved rules. Classes that map // to "" won't be in this list because they shouldn't be renamed yet. func getJarJarRuleText(provider *JarJarProviderData) string { - result := "" + result := strings.Builder{} for _, orig := range android.SortedKeys(provider.Rename) { renamed := provider.Rename[orig] if renamed != "" { - result += "rule " + orig + " " + renamed + "\n" + result.WriteString("rule ") + result.WriteString(orig) + result.WriteString(" ") + result.WriteString(renamed) + result.WriteString("\n") } } - return result + return result.String() } // Repackage the flags if the jarjar rule txt for the flags is generated diff --git a/phony/phony.go b/phony/phony.go index 807b95b32..4f61c4583 100644 --- a/phony/phony.go +++ b/phony/phony.go @@ -38,9 +38,11 @@ var PrepareForTestWithPhony = android.FixtureRegisterWithContext(registerPhonyMo type phony struct { android.ModuleBase + requiredModuleNames []string hostRequiredModuleNames []string targetRequiredModuleNames []string + outputDeps android.Paths } func PhonyFactory() android.Module { @@ -54,6 +56,14 @@ func (p *phony) GenerateAndroidBuildActions(ctx android.ModuleContext) { p.requiredModuleNames = ctx.RequiredModuleNames(ctx) p.hostRequiredModuleNames = ctx.HostRequiredModuleNames() p.targetRequiredModuleNames = ctx.TargetRequiredModuleNames() + + ctx.VisitDirectDepsWithTag(android.RequiredDepTag, func(dep android.Module) { + if o, ok := android.OtherModuleProvider(ctx, dep, android.OutputFilesProvider); ok { + p.outputDeps = append(p.outputDeps, o.DefaultOutputFiles...) + } + }) + + ctx.Phony(p.Name(), p.outputDeps...) } func (p *phony) AndroidMk() android.AndroidMkData { @@ -77,6 +87,10 @@ func (p *phony) AndroidMk() android.AndroidMkData { fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=", strings.Join(p.targetRequiredModuleNames, " ")) } + if len(p.outputDeps) > 0 { + fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES :=", + strings.Join(p.outputDeps.Strings(), " ")) + } // AconfigUpdateAndroidMkData may have added elements to Extra. Process them here. for _, extra := range data.Extra { extra(w, nil) diff --git a/rust/builder.go b/rust/builder.go index 8a869aad8..1b6a6c117 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -171,7 +171,7 @@ func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "rlib")) } -// TransformRlibstoStaticlib is assumed to be called from the cc module, and +// TransformRlibstoStaticlib is assumed to be callable from the cc module, and // thus needs to reconstruct the common set of flags which need to be passed // to the rustc compiler. func TransformRlibstoStaticlib(ctx android.ModuleContext, mainSrc android.Path, deps []cc.RustRlibDep, @@ -185,7 +185,7 @@ func TransformRlibstoStaticlib(ctx android.ModuleContext, mainSrc android.Path, rustPathDeps.linkDirs = append(rustPathDeps.linkDirs, rlibDep.LinkDirs...) } - ccModule := ctx.(cc.ModuleContext).Module().(*cc.Module) + mod := ctx.Module().(cc.LinkableInterface) toolchain := config.FindToolchain(ctx.Os(), ctx.Arch()) t := transformProperties{ // Crate name can be a predefined value as this is a staticlib and @@ -195,10 +195,10 @@ func TransformRlibstoStaticlib(ctx android.ModuleContext, mainSrc android.Path, crateName: "generated_rust_staticlib", is64Bit: toolchain.Is64Bit(), targetTriple: toolchain.RustTriple(), - bootstrap: ccModule.Bootstrap(), - inRecovery: ccModule.InRecovery(), - inRamdisk: ccModule.InRamdisk(), - inVendorRamdisk: ccModule.InVendorRamdisk(), + bootstrap: mod.Bootstrap(), + inRecovery: mod.InRecovery(), + inRamdisk: mod.InRamdisk(), + inVendorRamdisk: mod.InVendorRamdisk(), // crateType indicates what type of crate to build crateType: "staticlib", @@ -402,6 +402,11 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path linkFlags = append(linkFlags, dynamicLinker) } + if generatedLib := cc.GenerateRustStaticlib(ctx, deps.ccRlibDeps); generatedLib != nil { + deps.StaticLibs = append(deps.StaticLibs, generatedLib) + linkFlags = append(linkFlags, generatedLib.String()) + } + libFlags := makeLibFlags(deps) // Collect dependencies diff --git a/rust/library.go b/rust/library.go index 24ae8b046..7f5861fe8 100644 --- a/rust/library.go +++ b/rust/library.go @@ -737,12 +737,15 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa if library.rlib() { library.flagExporter.exportStaticLibs(deps.staticLibObjects...) } - // Since we have FFI rlibs, we need to collect their includes as well if library.static() || library.shared() || library.rlib() || library.stubs() { - android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{ + ccExporter := cc.FlagExporterInfo{ IncludeDirs: android.FirstUniquePaths(library.includeDirs), - }) + } + if library.rlib() { + ccExporter.RustRlibDeps = append(ccExporter.RustRlibDeps, deps.reexportedCcRlibDeps...) + } + android.SetProvider(ctx, cc.FlagExporterInfoProvider, ccExporter) } if library.shared() || library.stubs() { diff --git a/rust/rust.go b/rust/rust.go index ad68d6041..4eec5d254 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -495,6 +495,10 @@ type PathDeps struct { depFlags []string depLinkFlags []string + // track cc static-libs that have Rlib dependencies + reexportedCcRlibDeps []cc.RustRlibDep + ccRlibDeps []cc.RustRlibDep + // linkDirs are link paths passed via -L to rustc. linkObjects are objects passed directly to the linker // Both of these are exported and propagate to dependencies. linkDirs []string @@ -1531,6 +1535,13 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } } + if !mod.Rlib() { + depPaths.ccRlibDeps = append(depPaths.ccRlibDeps, exportedInfo.RustRlibDeps...) + } else { + // rlibs need to reexport these + depPaths.reexportedCcRlibDeps = append(depPaths.reexportedCcRlibDeps, exportedInfo.RustRlibDeps...) + } + case depTag == procMacroDepTag: directProcMacroDeps = append(directProcMacroDeps, linkableInfo) mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName) @@ -1651,8 +1662,8 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } else { // Otherwise add to staticLibObjects, which only propagate through rlibs to their dependents. depPaths.staticLibObjects = append(depPaths.staticLibObjects, ccLibPath.String()) - } + depPaths.linkDirs = append(depPaths.linkDirs, linkPath) exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider) @@ -1660,6 +1671,14 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...) depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...) depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...) + + if !mod.Rlib() { + // rlibs don't need to build the generated static library, so they don't need to track these. + depPaths.ccRlibDeps = append(depPaths.ccRlibDeps, exportedInfo.RustRlibDeps...) + } else { + depPaths.reexportedCcRlibDeps = append(depPaths.reexportedCcRlibDeps, exportedInfo.RustRlibDeps...) + } + directStaticLibDeps = append(directStaticLibDeps, linkableInfo) // Record baseLibName for snapshots. @@ -1815,6 +1834,8 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths) depPaths.depSystemIncludePaths = android.FirstUniquePaths(depPaths.depSystemIncludePaths) depPaths.depLinkFlags = android.FirstUniqueStrings(depPaths.depLinkFlags) + depPaths.reexportedCcRlibDeps = android.FirstUniqueFunc(depPaths.reexportedCcRlibDeps, cc.EqRustRlibDeps) + depPaths.ccRlibDeps = android.FirstUniqueFunc(depPaths.ccRlibDeps, cc.EqRustRlibDeps) return depPaths } diff --git a/rust/rust_test.go b/rust/rust_test.go index 4390f556e..2e016f0c7 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -449,12 +449,26 @@ func TestRustFFIRlibs(t *testing.T) { } rust_ffi_static { + name: "libfoo_from_rlib", + crate_name: "foo_from_rlib", + srcs: ["src/lib.rs"], + export_include_dirs: ["foo_includes"] + } + + rust_ffi_static { name: "libbuzz", crate_name: "buzz", srcs: ["src/lib.rs"], export_include_dirs: ["buzz_includes"] } + rust_ffi_static { + name: "libbuzz_from_rlib", + crate_name: "buzz_from_rlib", + srcs: ["src/lib.rs"], + export_include_dirs: ["buzz_includes"] + } + cc_library_shared { name: "libcc_shared", srcs:["foo.c"], @@ -468,12 +482,34 @@ func TestRustFFIRlibs(t *testing.T) { whole_static_libs: ["libfoo"], } + cc_library_static { + name: "libcc_static_from_rlib", + srcs:["foo.c"], + static_libs: ["libbuzz_from_rlib"], + whole_static_libs: ["libfoo_from_rlib"], + } + cc_binary { name: "ccBin", srcs:["foo.c"], static_libs: ["libcc_static", "libbar"], } - `) + + rust_library { + name: "librs", + srcs:["src/foo.rs"], + crate_name: "rs", + static_libs: ["libcc_static_from_rlib"], + } + + rust_binary { + name: "rsBin", + srcs:["src/foo.rs"], + crate_name: "rsBin", + rlibs: ["librs", "libbar"], + static_libs: ["libcc_static"], + } + `) libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_rlib_rlib-std").Rule("rustc") libcc_shared_rustc := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("rustc") @@ -482,6 +518,9 @@ func TestRustFFIRlibs(t *testing.T) { ccbin_rustc := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("rustc") ccbin_ld := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("ld") ccbin_cc := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("cc") + rustbin_genlib := ctx.ModuleForTests("rsBin", "android_arm64_armv8-a").Output("generated_rust_staticlib/librustlibs.a") + rustbin := ctx.ModuleForTests("rsBin", "android_arm64_armv8-a").Output("unstripped/rsBin") + librs_rlib := ctx.ModuleForTests("librs", "android_arm64_armv8-a_rlib_dylib-std").MaybeOutput("generated_rust_staticlib/librustlibs.a") if !strings.Contains(libbar.Args["rustcFlags"], "crate-type=rlib") { t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", "rlib", libbar.Args["rustcFlags"]) @@ -513,7 +552,7 @@ func TestRustFFIRlibs(t *testing.T) { // Make sure the static lib is included in the cc command if !strings.Contains(ccbin_ld.Args["libFlags"], "generated_rust_staticlib/librustlibs.a") { t.Errorf("missing generated static library in linker step libFlags, expecting %#v, libFlags: %#v", - "ccBin.generated_rust_staticlib.a", ccbin_ld.Args["libFlags"]) + "generated_rust_staticlib/librustlibs.a", ccbin_ld.Args["libFlags"]) } // Make sure the static lib includes are in the ld command @@ -534,11 +573,43 @@ func TestRustFFIRlibs(t *testing.T) { t.Errorf("Missing direct dependency libbar when writing generated Rust staticlib: %#v", ccbin_rustc.Args["libFlags"]) } + // Make sure the static lib is included in the rustc command + if !strings.Contains(rustbin.Args["linkFlags"], "generated_rust_staticlib/librustlibs.a") { + t.Errorf("missing generated static library in linker step libFlags in Rust module, expecting %#v, libFlags: %#v", + "generated_rust_staticlib/librustlibs.a", rustbin.Args["libFlags"]) + } + + // Make sure that direct dependencies and indirect whole static dependencies are + // propagating correctly for the rlib -> cc_library_static -> rust_* generated library example. + if !strings.Contains(rustbin_genlib.Args["libFlags"], "--extern foo=") { + t.Errorf("Missing indirect whole_static_lib dependency libfoo from cc static_lib when writing generated Rust staticlib: %#v", rustbin_genlib.Args["libFlags"]) + } + if strings.Contains(rustbin_genlib.Args["libFlags"], "--extern buzz=") { + t.Errorf("Indirect rlib dependency libbuzz from cc static_lib found when writing generated Rust staticlib: %#v", rustbin_genlib.Args["libFlags"]) + } + if strings.Contains(rustbin_genlib.Args["libFlags"], "--extern bar=") { + t.Errorf("Direct rlib dependency libbar getting included in the generated Rust staticlib: %#v", rustbin_genlib.Args["libFlags"]) + } + if !strings.Contains(rustbin_genlib.Args["libFlags"], "--extern foo_from_rlib=") { + t.Errorf("Missing indirect whole_static_lib dependency libfoo_from_rlib from cc static_lib when writing generated Rust staticlib: %#v", rustbin_genlib.Args["libFlags"]) + } + if strings.Contains(rustbin_genlib.Args["libFlags"], "--extern buzz_from_rlib=") { + // While static-libs propagate for rust modules, this is not the + // expected behavior for cc modules. Thus, libbuzz_from_rlib would + // be expected to have to be re-declared as a direct rlib dependency. + t.Errorf("Indirect rlib dependency libbuzz_from_rlib from cc static_lib found when writing generated Rust staticlib: %#v", rustbin_genlib.Args["libFlags"]) + } + // Test indirect includes propagation if !strings.Contains(ccbin_cc.Args["cFlags"], "-Ifoo_includes") { t.Errorf("missing rlibs includes, expecting %#v, cFlags: %#v", "-Ifoo_includes", ccbin_cc.Args) } + + // Make sure we're not generating superfluous mto staticlibs. + if librs_rlib.Rule != nil { + t.Error("rlibs should not be generating mto staticlibs", "rlib", libbar.Args["rustcFlags"]) + } } func assertString(t *testing.T, got, expected string) { diff --git a/scripts/build-ndk-prebuilts.sh b/scripts/build-ndk-prebuilts.sh index ef0f44a7c..b60044389 100755 --- a/scripts/build-ndk-prebuilts.sh +++ b/scripts/build-ndk-prebuilts.sh @@ -23,9 +23,18 @@ fi # TODO: remove ALLOW_MISSING_DEPENDENCIES=true when all the riscv64 # dependencies exist (currently blocked by http://b/273792258). # TODO: remove BUILD_BROKEN_DISABLE_BAZEL=1 when bazel supports riscv64 (http://b/262192655). +# +# LTO is disabled because the NDK compiler is not necessarily in-sync with the +# compiler used to build the platform sysroot, and the sysroot includes static +# libraries which would be incompatible with mismatched compilers when built +# with LTO. Disabling LTO globally for the NDK sysroot is okay because the only +# compiled code in the sysroot that will end up in apps is those static +# libraries. +# https://github.com/android/ndk/issues/1591 TARGET_RELEASE=trunk_staging \ ALLOW_MISSING_DEPENDENCIES=true \ BUILD_BROKEN_DISABLE_BAZEL=1 \ +DISABLE_LTO=true \ TARGET_PRODUCT=ndk build/soong/soong_ui.bash --make-mode --soong-only ${OUT_DIR}/soong/ndk.timestamp if [ -n "${DIST_DIR}" ]; then |