diff options
105 files changed, 2421 insertions, 2412 deletions
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go index 250fd56d1..d9a862c02 100644 --- a/aconfig/aconfig_declarations.go +++ b/aconfig/aconfig_declarations.go @@ -88,6 +88,13 @@ func (module *DeclarationsModule) DepsMutator(ctx android.BottomUpMutatorContext ctx.PropertyErrorf("container", "missing container property") } + // treating system_ext as system partition as we are combining them as one container + // TODO remove this logic once we start enforcing that system_ext cannot be specified as + // container in the container field. + if module.properties.Container == "system_ext" { + module.properties.Container = "system" + } + // Add a dependency on the aconfig_value_sets defined in // RELEASE_ACONFIG_VALUE_SETS, and add any aconfig_values that // match our package. diff --git a/aconfig/aconfig_value_set.go b/aconfig/aconfig_value_set.go index 7ba76c044..d72ec48ff 100644 --- a/aconfig/aconfig_value_set.go +++ b/aconfig/aconfig_value_set.go @@ -16,6 +16,9 @@ package aconfig import ( "android/soong/android" + "fmt" + "strings" + "github.com/google/blueprint" ) @@ -27,6 +30,9 @@ type ValueSetModule struct { properties struct { // aconfig_values modules Values []string + + // Paths to the Android.bp files where the aconfig_values modules are defined. + Srcs []string } } @@ -56,7 +62,35 @@ type valueSetProviderData struct { var valueSetProviderKey = blueprint.NewProvider[valueSetProviderData]() +func (module *ValueSetModule) FindAconfigValuesFromSrc(ctx android.BottomUpMutatorContext) map[string]android.Path { + moduleDir := ctx.ModuleDir() + srcs := android.PathsForModuleSrcExcludes(ctx, module.properties.Srcs, []string{ctx.BlueprintsFile()}) + + aconfigValuesPrefix := strings.Replace(module.Name(), "aconfig_value_set", "aconfig-values", 1) + moduleNamesSrcMap := make(map[string]android.Path) + for _, src := range srcs { + subDir := strings.TrimPrefix(src.String(), moduleDir+"/") + packageName, _, found := strings.Cut(subDir, "/") + if found { + moduleName := fmt.Sprintf("%s-%s-all", aconfigValuesPrefix, packageName) + moduleNamesSrcMap[moduleName] = src + } + } + return moduleNamesSrcMap +} + func (module *ValueSetModule) DepsMutator(ctx android.BottomUpMutatorContext) { + + // TODO: b/366285733 - Replace the file path based solution with more robust solution. + aconfigValuesMap := module.FindAconfigValuesFromSrc(ctx) + for _, moduleName := range android.SortedKeys(aconfigValuesMap) { + if ctx.OtherModuleExists(moduleName) { + ctx.AddDependency(ctx.Module(), valueSetTag, moduleName) + } else { + ctx.ModuleErrorf("module %q not found. Rename the aconfig_values module defined in %q to %q", moduleName, aconfigValuesMap[moduleName], moduleName) + } + } + deps := ctx.AddDependency(ctx.Module(), valueSetTag, module.properties.Values...) for _, dep := range deps { _, ok := dep.(*ValuesModule) diff --git a/aconfig/aconfig_value_set_test.go b/aconfig/aconfig_value_set_test.go index 32c31cb32..3b7281ec9 100644 --- a/aconfig/aconfig_value_set_test.go +++ b/aconfig/aconfig_value_set_test.go @@ -18,6 +18,8 @@ import ( "testing" "android/soong/android" + + "github.com/google/blueprint" ) func TestAconfigValueSet(t *testing.T) { @@ -41,3 +43,112 @@ func TestAconfigValueSet(t *testing.T) { depData, _ := android.OtherModuleProvider(result, module, valueSetProviderKey) android.AssertStringEquals(t, "AvailablePackages", "blah.aconfig_values", depData.AvailablePackages["foo.package"][0].String()) } + +func TestAconfigValueSetBpGlob(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithAconfigBuildComponents, + android.FixtureMergeMockFs( + map[string][]byte{ + // .../some_release/android.foo/ + "some_release/android.foo/Android.bp": []byte(` + aconfig_values { + name: "aconfig-values-platform_build_release-some_release-android.foo-all", + package: "android.foo", + srcs: [ + "*.textproto", + ], + } + `), + "some_release/android.foo/flag.textproto": nil, + + // .../some_release/android.bar/ + "some_release/android.bar/Android.bp": []byte(` + aconfig_values { + name: "aconfig-values-platform_build_release-some_release-android.bar-all", + package: "android.bar", + srcs: [ + "*.textproto", + ], + } + `), + "some_release/android.bar/flag.textproto": nil, + + // .../some_release/ + "some_release/Android.bp": []byte(` + aconfig_value_set { + name: "aconfig_value_set-platform_build_release-some_release", + srcs: [ + "*/Android.bp", + ], + } + `), + }, + ), + ).RunTest(t) + + checkModuleHasDependency := func(name, variant, dep string) bool { + t.Helper() + module := result.ModuleForTests(name, variant).Module() + depFound := false + result.VisitDirectDeps(module, func(m blueprint.Module) { + if m.Name() == dep { + depFound = true + } + }) + return depFound + } + android.AssertBoolEquals(t, + "aconfig_value_set expected to depend on aconfig_value via srcs", + true, + checkModuleHasDependency( + "aconfig_value_set-platform_build_release-some_release", + "", + "aconfig-values-platform_build_release-some_release-android.foo-all", + ), + ) + android.AssertBoolEquals(t, + "aconfig_value_set expected to depend on aconfig_value via srcs", + true, + checkModuleHasDependency( + "aconfig_value_set-platform_build_release-some_release", + "", + "aconfig-values-platform_build_release-some_release-android.bar-all", + ), + ) +} + +func TestAconfigValueSetBpGlobError(t *testing.T) { + android.GroupFixturePreparers( + PrepareForTestWithAconfigBuildComponents, + android.FixtureMergeMockFs( + map[string][]byte{ + // .../some_release/android.bar/ + "some_release/android.bar/Android.bp": []byte(` + aconfig_values { + name: "aconfig-values-platform_build_release-some_release-android_bar-all", + package: "android.bar", + srcs: [ + "*.textproto", + ], + } + `), + "some_release/android.bar/flag.textproto": nil, + + // .../some_release/ + "some_release/Android.bp": []byte(` + aconfig_value_set { + name: "aconfig_value_set-platform_build_release-some_release", + srcs: [ + "*/Android.bp", + ], + } + `), + }, + ), + ).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern( + `module "aconfig_value_set-platform_build_release-some_release": module ` + + `"aconfig-values-platform_build_release-some_release-android.bar-all" not found. ` + + `Rename the aconfig_values module defined in "some_release/android.bar/Android.bp" ` + + `to "aconfig-values-platform_build_release-some_release-android.bar-all"`), + ).RunTest(t) +} diff --git a/aconfig/codegen/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go index 87b54a47f..d8372f3c9 100644 --- a/aconfig/codegen/java_aconfig_library_test.go +++ b/aconfig/codegen/java_aconfig_library_test.go @@ -260,7 +260,7 @@ func TestMkEntriesMatchedContainer(t *testing.T) { aconfig_declarations { name: "my_aconfig_declarations_bar", package: "com.example.package.bar", - container: "system_ext", + container: "vendor", srcs: ["bar.aconfig"], } diff --git a/android/Android.bp b/android/Android.bp index 16a34b7de..9f3400c6e 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -88,6 +88,7 @@ bootstrap_go_package { "prebuilt.go", "prebuilt_build_tool.go", "product_config.go", + "product_config_to_bp.go", "proto.go", "provider.go", "raw_files.go", diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go index 6bfbf3776..d2a9622e3 100644 --- a/android/aconfig_providers.go +++ b/android/aconfig_providers.go @@ -187,6 +187,20 @@ func aconfigUpdateAndroidMkEntries(ctx fillInEntriesContext, mod Module, entries } } +func aconfigUpdateAndroidMkInfos(ctx fillInEntriesContext, mod Module, infos *AndroidMkProviderInfo) { + info, ok := OtherModuleProvider(ctx, mod, AconfigPropagatingProviderKey) + if !ok || len(info.AconfigFiles) == 0 { + return + } + // All of the files in the module potentially depend on the aconfig flag values. + infos.PrimaryInfo.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles)) + if len(infos.ExtraInfo) > 0 { + for _, ei := range (*infos).ExtraInfo { + ei.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles)) + } + } +} + func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, generateRule bool) Paths { inputs = SortedUniquePaths(inputs) if len(inputs) == 1 { @@ -219,7 +233,8 @@ func getAconfigFilePaths(m *ModuleBase, aconfigFiles map[string]Paths) (paths Pa } else if m.ProductSpecific() { container = "product" } else if m.SystemExtSpecific() { - container = "system_ext" + // system_ext and system partitions should be treated as one container + container = "system" } paths = append(paths, aconfigFiles[container]...) diff --git a/android/androidmk.go b/android/androidmk.go index fc628cb34..cac2cfe47 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -34,7 +34,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" ) @@ -502,6 +501,7 @@ type fillInEntriesContext interface { otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) ModuleType(module blueprint.Module) string OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) + HasMutatorFinished(mutatorName string) bool } func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint.Module) { @@ -806,15 +806,19 @@ func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs // Additional cases here require review for correct license propagation to make. var err error - switch x := mod.(type) { - case AndroidMkDataProvider: - err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod, x) - case bootstrap.GoBinaryTool: - err = translateGoBinaryModule(ctx, w, mod, x) - case AndroidMkEntriesProvider: - err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod, x) - default: - // Not exported to make so no make variables to set. + + if info, ok := ctx.otherModuleProvider(mod, AndroidMkInfoProvider); ok { + androidMkEntriesInfos := info.(*AndroidMkProviderInfo) + err = translateAndroidMkEntriesInfoModule(ctx, w, moduleInfoJSONs, mod, androidMkEntriesInfos) + } else { + switch x := mod.(type) { + case AndroidMkDataProvider: + err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod, x) + case AndroidMkEntriesProvider: + err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod, x) + default: + // Not exported to make so no make variables to set. + } } if err != nil { @@ -824,23 +828,6 @@ func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs return err } -// A simple, special Android.mk entry output func to make it possible to build blueprint tools using -// m by making them phony targets. -func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, - goBinary bootstrap.GoBinaryTool) error { - - name := ctx.ModuleName(mod) - fmt.Fprintln(w, ".PHONY:", name) - fmt.Fprintln(w, name+":", goBinary.InstallPath()) - fmt.Fprintln(w, "") - // Assuming no rules in make include go binaries in distributables. - // If the assumption is wrong, make will fail to build without the necessary .meta_lic and .meta_module files. - // In that case, add the targets and rules here to build a .meta_lic file for `name` and a .meta_module for - // `goBinary.InstallPath()` pointing to the `name`.meta_lic file. - - return nil -} - func (data *AndroidMkData) fillInData(ctx fillInEntriesContext, mod blueprint.Module) { // Get the preamble content through AndroidMkEntries logic. data.Entries = AndroidMkEntries{ @@ -983,11 +970,11 @@ func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, moduleIn return nil } -func ShouldSkipAndroidMkProcessing(ctx ConfigAndErrorContext, module Module) bool { +func ShouldSkipAndroidMkProcessing(ctx ConfigurableEvaluatorContext, module Module) bool { return shouldSkipAndroidMkProcessing(ctx, module.base()) } -func shouldSkipAndroidMkProcessing(ctx ConfigAndErrorContext, module *ModuleBase) bool { +func shouldSkipAndroidMkProcessing(ctx ConfigurableEvaluatorContext, module *ModuleBase) bool { if !module.commonProperties.NamespaceExportedToMake { // TODO(jeffrygaston) do we want to validate that there are no modules being // exported to Kati that depend on this module? @@ -1063,3 +1050,564 @@ func AndroidMkEmitAssignList(w io.Writer, varName string, lists ...[]string) { } fmt.Fprintln(w) } + +type AndroidMkProviderInfo struct { + PrimaryInfo AndroidMkInfo + ExtraInfo []AndroidMkInfo +} + +type AndroidMkInfo struct { + // Android.mk class string, e.g. EXECUTABLES, JAVA_LIBRARIES, ETC + Class string + // Optional suffix to append to the module name. Useful when a module wants to return multiple + // AndroidMkEntries objects. For example, when a java_library returns an additional entry for + // its hostdex sub-module, this SubName field is set to "-hostdex" so that it can have a + // different name than the parent's. + SubName string + // If set, this value overrides the base module name. SubName is still appended. + OverrideName string + // Dist files to output + DistFiles TaggedDistFiles + // The output file for Kati to process and/or install. If absent, the module is skipped. + OutputFile OptionalPath + // If true, the module is skipped and does not appear on the final Android-<product name>.mk + // file. Useful when a module needs to be skipped conditionally. + Disabled bool + // The postprocessing mk file to include, e.g. $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk + // If not set, $(BUILD_SYSTEM)/prebuilt.mk is used. + Include string + // Required modules that need to be built and included in the final build output when building + // this module. + Required []string + // Required host modules that need to be built and included in the final build output when + // building this module. + Host_required []string + // Required device modules that need to be built and included in the final build output when + // building this module. + Target_required []string + + HeaderStrings []string + FooterStrings []string + + // A map that holds the up-to-date Make variable values. Can be accessed from tests. + EntryMap map[string][]string + // A list of EntryMap keys in insertion order. This serves a few purposes: + // 1. Prevents churns. Golang map doesn't provide consistent iteration order, so without this, + // the outputted Android-*.mk file may change even though there have been no content changes. + // 2. Allows modules to refer to other variables, like LOCAL_BAR_VAR := $(LOCAL_FOO_VAR), + // without worrying about the variables being mixed up in the actual mk file. + // 3. Makes troubleshooting and spotting errors easier. + EntryOrder []string +} + +// TODO: rename it to AndroidMkEntriesProvider after AndroidMkEntriesProvider interface is gone. +var AndroidMkInfoProvider = blueprint.NewProvider[*AndroidMkProviderInfo]() + +func translateAndroidMkEntriesInfoModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON, + mod blueprint.Module, providerInfo *AndroidMkProviderInfo) error { + if shouldSkipAndroidMkProcessing(ctx, mod.(Module).base()) { + return nil + } + + // Deep copy the provider info since we need to modify the info later + info := deepCopyAndroidMkProviderInfo(providerInfo) + + aconfigUpdateAndroidMkInfos(ctx, mod.(Module), &info) + + // Any new or special cases here need review to verify correct propagation of license information. + info.PrimaryInfo.fillInEntries(ctx, mod) + info.PrimaryInfo.write(w) + if len(info.ExtraInfo) > 0 { + for _, ei := range info.ExtraInfo { + ei.fillInEntries(ctx, mod) + ei.write(w) + } + } + + if !info.PrimaryInfo.disabled() { + if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { + *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON) + } + } + + return nil +} + +// Utility funcs to manipulate Android.mk variable entries. + +// SetString sets a Make variable with the given name to the given value. +func (a *AndroidMkInfo) SetString(name, value string) { + if _, ok := a.EntryMap[name]; !ok { + a.EntryOrder = append(a.EntryOrder, name) + } + a.EntryMap[name] = []string{value} +} + +// SetPath sets a Make variable with the given name to the given path string. +func (a *AndroidMkInfo) SetPath(name string, path Path) { + if _, ok := a.EntryMap[name]; !ok { + a.EntryOrder = append(a.EntryOrder, name) + } + a.EntryMap[name] = []string{path.String()} +} + +// SetOptionalPath sets a Make variable with the given name to the given path string if it is valid. +// It is a no-op if the given path is invalid. +func (a *AndroidMkInfo) SetOptionalPath(name string, path OptionalPath) { + if path.Valid() { + a.SetPath(name, path.Path()) + } +} + +// AddPath appends the given path string to a Make variable with the given name. +func (a *AndroidMkInfo) AddPath(name string, path Path) { + if _, ok := a.EntryMap[name]; !ok { + a.EntryOrder = append(a.EntryOrder, name) + } + a.EntryMap[name] = append(a.EntryMap[name], path.String()) +} + +// AddOptionalPath appends the given path string to a Make variable with the given name if it is +// valid. It is a no-op if the given path is invalid. +func (a *AndroidMkInfo) AddOptionalPath(name string, path OptionalPath) { + if path.Valid() { + a.AddPath(name, path.Path()) + } +} + +// SetPaths sets a Make variable with the given name to a slice of the given path strings. +func (a *AndroidMkInfo) SetPaths(name string, paths Paths) { + if _, ok := a.EntryMap[name]; !ok { + a.EntryOrder = append(a.EntryOrder, name) + } + a.EntryMap[name] = paths.Strings() +} + +// SetOptionalPaths sets a Make variable with the given name to a slice of the given path strings +// only if there are a non-zero amount of paths. +func (a *AndroidMkInfo) SetOptionalPaths(name string, paths Paths) { + if len(paths) > 0 { + a.SetPaths(name, paths) + } +} + +// AddPaths appends the given path strings to a Make variable with the given name. +func (a *AndroidMkInfo) AddPaths(name string, paths Paths) { + if _, ok := a.EntryMap[name]; !ok { + a.EntryOrder = append(a.EntryOrder, name) + } + a.EntryMap[name] = append(a.EntryMap[name], paths.Strings()...) +} + +// SetBoolIfTrue sets a Make variable with the given name to true if the given flag is true. +// It is a no-op if the given flag is false. +func (a *AndroidMkInfo) SetBoolIfTrue(name string, flag bool) { + if flag { + if _, ok := a.EntryMap[name]; !ok { + a.EntryOrder = append(a.EntryOrder, name) + } + a.EntryMap[name] = []string{"true"} + } +} + +// SetBool sets a Make variable with the given name to if the given bool flag value. +func (a *AndroidMkInfo) SetBool(name string, flag bool) { + if _, ok := a.EntryMap[name]; !ok { + a.EntryOrder = append(a.EntryOrder, name) + } + if flag { + a.EntryMap[name] = []string{"true"} + } else { + a.EntryMap[name] = []string{"false"} + } +} + +// AddStrings appends the given strings to a Make variable with the given name. +func (a *AndroidMkInfo) AddStrings(name string, value ...string) { + if len(value) == 0 { + return + } + if _, ok := a.EntryMap[name]; !ok { + a.EntryOrder = append(a.EntryOrder, name) + } + a.EntryMap[name] = append(a.EntryMap[name], value...) +} + +// AddCompatibilityTestSuites adds the supplied test suites to the EntryMap, with special handling +// for partial MTS and MCTS test suites. +func (a *AndroidMkInfo) AddCompatibilityTestSuites(suites ...string) { + // M(C)TS supports a full test suite and partial per-module MTS test suites, with naming mts-${MODULE}. + // To reduce repetition, if we find a partial M(C)TS test suite without an full M(C)TS test suite, + // we add the full test suite to our list. + if PrefixInList(suites, "mts-") && !InList("mts", suites) { + suites = append(suites, "mts") + } + if PrefixInList(suites, "mcts-") && !InList("mcts", suites) { + suites = append(suites, "mcts") + } + a.AddStrings("LOCAL_COMPATIBILITY_SUITE", suites...) +} + +func (a *AndroidMkInfo) fillInEntries(ctx fillInEntriesContext, mod blueprint.Module) { + helperInfo := AndroidMkInfo{ + EntryMap: make(map[string][]string), + } + + amod := mod.(Module) + base := amod.base() + name := base.BaseModuleName() + if a.OverrideName != "" { + name = a.OverrideName + } + + if a.Include == "" { + a.Include = "$(BUILD_PREBUILT)" + } + a.Required = append(a.Required, amod.RequiredModuleNames(ctx)...) + a.Required = append(a.Required, amod.VintfFragmentModuleNames(ctx)...) + a.Host_required = append(a.Host_required, amod.HostRequiredModuleNames()...) + a.Target_required = append(a.Target_required, amod.TargetRequiredModuleNames()...) + + for _, distString := range a.GetDistForGoals(ctx, mod) { + a.HeaderStrings = append(a.HeaderStrings, distString) + } + + a.HeaderStrings = append(a.HeaderStrings, fmt.Sprintf("\ninclude $(CLEAR_VARS) # type: %s, name: %s, variant: %s\n", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod))) + + // Collect make variable assignment entries. + helperInfo.SetString("LOCAL_PATH", ctx.ModuleDir(mod)) + helperInfo.SetString("LOCAL_MODULE", name+a.SubName) + helperInfo.SetString("LOCAL_MODULE_CLASS", a.Class) + helperInfo.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String()) + helperInfo.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...) + helperInfo.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...) + helperInfo.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...) + helperInfo.AddStrings("LOCAL_SOONG_MODULE_TYPE", ctx.ModuleType(amod)) + + // If the install rule was generated by Soong tell Make about it. + info := OtherModuleProviderOrDefault(ctx, mod, InstallFilesProvider) + if len(info.KatiInstalls) > 0 { + // Assume the primary install file is last since it probably needs to depend on any other + // installed files. If that is not the case we can add a method to specify the primary + // installed file. + helperInfo.SetPath("LOCAL_SOONG_INSTALLED_MODULE", info.KatiInstalls[len(info.KatiInstalls)-1].to) + helperInfo.SetString("LOCAL_SOONG_INSTALL_PAIRS", info.KatiInstalls.BuiltInstalled()) + helperInfo.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", info.KatiSymlinks.InstallPaths().Paths()) + } else { + // Soong may not have generated the install rule also when `no_full_install: true`. + // Mark this module as uninstallable in order to prevent Make from creating an + // install rule there. + helperInfo.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install)) + } + + if len(info.TestData) > 0 { + helperInfo.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...) + } + + if am, ok := mod.(ApexModule); ok { + helperInfo.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", am.NotAvailableForPlatform()) + } + + archStr := base.Arch().ArchType.String() + host := false + switch base.Os().Class { + case Host: + if base.Target().HostCross { + // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common. + if base.Arch().ArchType != Common { + helperInfo.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr) + } + } else { + // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common. + if base.Arch().ArchType != Common { + helperInfo.SetString("LOCAL_MODULE_HOST_ARCH", archStr) + } + } + host = true + case Device: + // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common. + if base.Arch().ArchType != Common { + if base.Target().NativeBridge { + hostArchStr := base.Target().NativeBridgeHostArchName + if hostArchStr != "" { + helperInfo.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr) + } + } else { + helperInfo.SetString("LOCAL_MODULE_TARGET_ARCH", archStr) + } + } + + if !base.InVendorRamdisk() { + helperInfo.AddPaths("LOCAL_FULL_INIT_RC", info.InitRcPaths) + } + if len(info.VintfFragmentsPaths) > 0 { + helperInfo.AddPaths("LOCAL_FULL_VINTF_FRAGMENTS", info.VintfFragmentsPaths) + } + helperInfo.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(base.commonProperties.Proprietary)) + if Bool(base.commonProperties.Vendor) || Bool(base.commonProperties.Soc_specific) { + helperInfo.SetString("LOCAL_VENDOR_MODULE", "true") + } + helperInfo.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(base.commonProperties.Device_specific)) + helperInfo.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(base.commonProperties.Product_specific)) + helperInfo.SetBoolIfTrue("LOCAL_SYSTEM_EXT_MODULE", Bool(base.commonProperties.System_ext_specific)) + if base.commonProperties.Owner != nil { + helperInfo.SetString("LOCAL_MODULE_OWNER", *base.commonProperties.Owner) + } + } + + if host { + makeOs := base.Os().String() + if base.Os() == Linux || base.Os() == LinuxBionic || base.Os() == LinuxMusl { + makeOs = "linux" + } + helperInfo.SetString("LOCAL_MODULE_HOST_OS", makeOs) + helperInfo.SetString("LOCAL_IS_HOST_MODULE", "true") + } + + prefix := "" + if base.ArchSpecific() { + switch base.Os().Class { + case Host: + if base.Target().HostCross { + prefix = "HOST_CROSS_" + } else { + prefix = "HOST_" + } + case Device: + prefix = "TARGET_" + + } + + if base.Arch().ArchType != ctx.Config().Targets[base.Os()][0].Arch.ArchType { + prefix = "2ND_" + prefix + } + } + + if licenseMetadata, ok := OtherModuleProvider(ctx, mod, LicenseMetadataProvider); ok { + helperInfo.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath) + } + + if _, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { + helperInfo.SetBool("LOCAL_SOONG_MODULE_INFO_JSON", true) + } + + a.mergeEntries(&helperInfo) + + // Write to footer. + a.FooterStrings = append([]string{"include " + a.Include}, a.FooterStrings...) +} + +// This method merges the entries to helperInfo, then replaces a's EntryMap and +// EntryOrder with helperInfo's +func (a *AndroidMkInfo) mergeEntries(helperInfo *AndroidMkInfo) { + for _, extraEntry := range a.EntryOrder { + if v, ok := helperInfo.EntryMap[extraEntry]; ok { + v = append(v, a.EntryMap[extraEntry]...) + } else { + helperInfo.EntryMap[extraEntry] = a.EntryMap[extraEntry] + helperInfo.EntryOrder = append(helperInfo.EntryOrder, extraEntry) + } + } + a.EntryOrder = helperInfo.EntryOrder + a.EntryMap = helperInfo.EntryMap +} + +func (a *AndroidMkInfo) disabled() bool { + return a.Disabled || !a.OutputFile.Valid() +} + +// write flushes the AndroidMkEntries's in-struct data populated by AndroidMkEntries into the +// given Writer object. +func (a *AndroidMkInfo) write(w io.Writer) { + if a.disabled() { + return + } + + combinedHeaderString := strings.Join(a.HeaderStrings, "\n") + combinedFooterString := strings.Join(a.FooterStrings, "\n") + w.Write([]byte(combinedHeaderString)) + for _, name := range a.EntryOrder { + AndroidMkEmitAssignList(w, name, a.EntryMap[name]) + } + w.Write([]byte(combinedFooterString)) +} + +// Compute the list of Make strings to declare phony goals and dist-for-goals +// calls from the module's dist and dists properties. +func (a *AndroidMkInfo) GetDistForGoals(ctx fillInEntriesContext, mod blueprint.Module) []string { + distContributions := a.getDistContributions(ctx, mod) + if distContributions == nil { + return nil + } + + return generateDistContributionsForMake(distContributions) +} + +// Compute the contributions that the module makes to the dist. +func (a *AndroidMkInfo) getDistContributions(ctx fillInEntriesContext, mod blueprint.Module) *distContributions { + amod := mod.(Module).base() + name := amod.BaseModuleName() + + // Collate the set of associated tag/paths available for copying to the dist. + // Start with an empty (nil) set. + var availableTaggedDists TaggedDistFiles + + // Then merge in any that are provided explicitly by the module. + if a.DistFiles != nil { + // Merge the DistFiles into the set. + availableTaggedDists = availableTaggedDists.merge(a.DistFiles) + } + + // If no paths have been provided for the DefaultDistTag and the output file is + // valid then add that as the default dist path. + if _, ok := availableTaggedDists[DefaultDistTag]; !ok && a.OutputFile.Valid() { + availableTaggedDists = availableTaggedDists.addPathsForTag(DefaultDistTag, a.OutputFile.Path()) + } + + info := OtherModuleProviderOrDefault(ctx, mod, InstallFilesProvider) + // If the distFiles created by GenerateTaggedDistFiles contains paths for the + // DefaultDistTag then that takes priority so delete any existing paths. + if _, ok := info.DistFiles[DefaultDistTag]; ok { + delete(availableTaggedDists, DefaultDistTag) + } + + // Finally, merge the distFiles created by GenerateTaggedDistFiles. + availableTaggedDists = availableTaggedDists.merge(info.DistFiles) + + if len(availableTaggedDists) == 0 { + // Nothing dist-able for this module. + return nil + } + + // Collate the contributions this module makes to the dist. + distContributions := &distContributions{} + + if !exemptFromRequiredApplicableLicensesProperty(mod.(Module)) { + distContributions.licenseMetadataFile = info.LicenseMetadataFile + } + + // Iterate over this module's dist structs, merged from the dist and dists properties. + for _, dist := range amod.Dists() { + // Get the list of goals this dist should be enabled for. e.g. sdk, droidcore + goals := strings.Join(dist.Targets, " ") + + // Get the tag representing the output files to be dist'd. e.g. ".jar", ".proguard_map" + var tag string + if dist.Tag == nil { + // If the dist struct does not specify a tag, use the default output files tag. + tag = DefaultDistTag + } else { + tag = *dist.Tag + } + + // Get the paths of the output files to be dist'd, represented by the tag. + // Can be an empty list. + tagPaths := availableTaggedDists[tag] + if len(tagPaths) == 0 { + // Nothing to dist for this tag, continue to the next dist. + continue + } + + if len(tagPaths) > 1 && (dist.Dest != nil || dist.Suffix != nil) { + errorMessage := "%s: Cannot apply dest/suffix for more than one dist " + + "file for %q goals tag %q in module %s. The list of dist files, " + + "which should have a single element, is:\n%s" + panic(fmt.Errorf(errorMessage, mod, goals, tag, name, tagPaths)) + } + + copiesForGoals := distContributions.getCopiesForGoals(goals) + + // Iterate over each path adding a copy instruction to copiesForGoals + for _, path := range tagPaths { + // It's possible that the Path is nil from errant modules. Be defensive here. + if path == nil { + tagName := "default" // for error message readability + if dist.Tag != nil { + tagName = *dist.Tag + } + panic(fmt.Errorf("Dist file should not be nil for the %s tag in %s", tagName, name)) + } + + dest := filepath.Base(path.String()) + + if dist.Dest != nil { + var err error + if dest, err = validateSafePath(*dist.Dest); err != nil { + // This was checked in ModuleBase.GenerateBuildActions + panic(err) + } + } + + ext := filepath.Ext(dest) + suffix := "" + if dist.Suffix != nil { + suffix = *dist.Suffix + } + + productString := "" + if dist.Append_artifact_with_product != nil && *dist.Append_artifact_with_product { + productString = fmt.Sprintf("_%s", ctx.Config().DeviceProduct()) + } + + if suffix != "" || productString != "" { + dest = strings.TrimSuffix(dest, ext) + suffix + productString + ext + } + + if dist.Dir != nil { + var err error + if dest, err = validateSafePath(*dist.Dir, dest); err != nil { + // This was checked in ModuleBase.GenerateBuildActions + panic(err) + } + } + + copiesForGoals.addCopyInstruction(path, dest) + } + } + + return distContributions +} + +func deepCopyAndroidMkProviderInfo(providerInfo *AndroidMkProviderInfo) AndroidMkProviderInfo { + info := AndroidMkProviderInfo{ + PrimaryInfo: deepCopyAndroidMkInfo(&providerInfo.PrimaryInfo), + } + if len(providerInfo.ExtraInfo) > 0 { + for _, i := range providerInfo.ExtraInfo { + info.ExtraInfo = append(info.ExtraInfo, deepCopyAndroidMkInfo(&i)) + } + } + return info +} + +func deepCopyAndroidMkInfo(mkinfo *AndroidMkInfo) AndroidMkInfo { + info := AndroidMkInfo{ + Class: mkinfo.Class, + SubName: mkinfo.SubName, + OverrideName: mkinfo.OverrideName, + // There is no modification on DistFiles or OutputFile, so no need to + // make their deep copy. + DistFiles: mkinfo.DistFiles, + OutputFile: mkinfo.OutputFile, + Disabled: mkinfo.Disabled, + Include: mkinfo.Include, + Required: deepCopyStringSlice(mkinfo.Required), + Host_required: deepCopyStringSlice(mkinfo.Host_required), + Target_required: deepCopyStringSlice(mkinfo.Target_required), + HeaderStrings: deepCopyStringSlice(mkinfo.HeaderStrings), + FooterStrings: deepCopyStringSlice(mkinfo.FooterStrings), + EntryOrder: deepCopyStringSlice(mkinfo.EntryOrder), + } + info.EntryMap = make(map[string][]string) + for k, v := range mkinfo.EntryMap { + info.EntryMap[k] = deepCopyStringSlice(v) + } + + return info +} + +func deepCopyStringSlice(original []string) []string { + result := make([]string, len(original)) + copy(result, original) + return result +} diff --git a/android/arch.go b/android/arch.go index 6d896e5fc..942727ace 100644 --- a/android/arch.go +++ b/android/arch.go @@ -23,7 +23,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/proptools" ) @@ -397,45 +396,21 @@ func (target Target) Variations() []blueprint.Variation { // device_supported and host_supported properties to determine which OsTypes are enabled for this // module, then searches through the Targets to determine which have enabled Targets for this // module. -func osMutator(bpctx blueprint.BottomUpMutatorContext) { - var module Module - var ok bool - if module, ok = bpctx.Module().(Module); !ok { - // The module is not a Soong module, it is a Blueprint module. - if bootstrap.IsBootstrapModule(bpctx.Module()) { - // Bootstrap Go modules are always the build OS or linux bionic. - config := bpctx.Config().(Config) - osNames := []string{config.BuildOSTarget.OsVariation()} - for _, hostCrossTarget := range config.Targets[LinuxBionic] { - if hostCrossTarget.Arch.ArchType == config.BuildOSTarget.Arch.ArchType { - osNames = append(osNames, hostCrossTarget.OsVariation()) - } - } - osNames = FirstUniqueStrings(osNames) - bpctx.CreateVariations(osNames...) - } - return - } - - // Bootstrap Go module support above requires this mutator to be a - // blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext - // filters out non-Soong modules. Now that we've handled them, create a - // normal android.BottomUpMutatorContext. - mctx := bottomUpMutatorContextFactory(bpctx, module, false) - defer bottomUpMutatorContextPool.Put(mctx) +type osTransitionMutator struct{} - base := module.base() +type allOsInfo struct { + Os map[string]OsType + Variations []string +} - // Nothing to do for modules that are not architecture specific (e.g. a genrule). - if !base.ArchSpecific() { - return - } +var allOsProvider = blueprint.NewMutatorProvider[*allOsInfo]("os_propagate") - // Collect a list of OSTypes supported by this module based on the HostOrDevice value - // passed to InitAndroidArchModule and the device_supported and host_supported properties. +// moduleOSList collects a list of OSTypes supported by this module based on the HostOrDevice +// value passed to InitAndroidArchModule and the device_supported and host_supported properties. +func moduleOSList(ctx ConfigContext, base *ModuleBase) []OsType { var moduleOSList []OsType for _, os := range osTypeList { - for _, t := range mctx.Config().Targets[os] { + for _, t := range ctx.Config().Targets[os] { if base.supportsTarget(t) { moduleOSList = append(moduleOSList, os) break @@ -443,53 +418,91 @@ func osMutator(bpctx blueprint.BottomUpMutatorContext) { } } - createCommonOSVariant := base.commonProperties.CreateCommonOSVariant + if base.commonProperties.CreateCommonOSVariant { + // A CommonOS variant was requested so add it to the list of OS variants to + // create. It needs to be added to the end because it needs to depend on the + // the other variants and inter variant dependencies can only be created from a + // later variant in that list to an earlier one. That is because variants are + // always processed in the order in which they are created. + moduleOSList = append(moduleOSList, CommonOS) + } + + return moduleOSList +} + +func (o *osTransitionMutator) Split(ctx BaseModuleContext) []string { + module := ctx.Module() + base := module.base() + + // Nothing to do for modules that are not architecture specific (e.g. a genrule). + if !base.ArchSpecific() { + return []string{""} + } + + moduleOSList := moduleOSList(ctx, base) // If there are no supported OSes then disable the module. - if len(moduleOSList) == 0 && !createCommonOSVariant { + if len(moduleOSList) == 0 { base.Disable() - return + return []string{""} } // Convert the list of supported OsTypes to the variation names. osNames := make([]string, len(moduleOSList)) + osMapping := make(map[string]OsType, len(moduleOSList)) for i, os := range moduleOSList { osNames[i] = os.String() + osMapping[osNames[i]] = os } - if createCommonOSVariant { - // A CommonOS variant was requested so add it to the list of OS variants to - // create. It needs to be added to the end because it needs to depend on the - // the other variants in the list returned by CreateVariations(...) and inter - // variant dependencies can only be created from a later variant in that list to - // an earlier one. That is because variants are always processed in the order in - // which they are returned from CreateVariations(...). - osNames = append(osNames, CommonOS.Name) - moduleOSList = append(moduleOSList, CommonOS) + SetProvider(ctx, allOsProvider, &allOsInfo{ + Os: osMapping, + Variations: osNames, + }) + + return osNames +} + +func (o *osTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string { + return sourceVariation +} + +func (o *osTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string { + module := ctx.Module() + base := module.base() + + if !base.ArchSpecific() { + return "" } - // Create the variations, annotate each one with which OS it was created for, and - // squash the appropriate OS-specific properties into the top level properties. - modules := mctx.CreateVariations(osNames...) - for i, m := range modules { - m.base().commonProperties.CompileOS = moduleOSList[i] - m.base().setOSProperties(mctx) + return incomingVariation +} + +func (o *osTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) { + module := ctx.Module() + base := module.base() + + if variation == "" { + return } - if createCommonOSVariant { + allOsInfo, ok := ModuleProvider(ctx, allOsProvider) + if !ok { + panic(fmt.Errorf("missing allOsProvider")) + } + + // Annotate this variant with which OS it was created for, and + // squash the appropriate OS-specific properties into the top level properties. + base.commonProperties.CompileOS = allOsInfo.Os[variation] + base.setOSProperties(ctx) + + if variation == CommonOS.String() { // A CommonOS variant was requested so add dependencies from it (the last one in // the list) to the OS type specific variants. - last := len(modules) - 1 - commonOSVariant := modules[last] - commonOSVariant.base().commonProperties.CommonOSVariant = true - for _, module := range modules[0:last] { - // Ignore modules that are enabled. Note, this will only avoid adding - // dependencies on OsType variants that are explicitly disabled in their - // properties. The CommonOS variant will still depend on disabled variants - // if they are disabled afterwards, e.g. in archMutator if - if module.Enabled(mctx) { - mctx.AddInterVariantDependency(commonOsToOsSpecificVariantTag, commonOSVariant, module) - } + osList := allOsInfo.Variations[:len(allOsInfo.Variations)-1] + for _, os := range osList { + variation := []blueprint.Variation{{"os", os}} + ctx.AddVariationDependencies(variation, commonOsToOsSpecificVariantTag, ctx.ModuleName()) } } } @@ -522,7 +535,7 @@ func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module { var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"} -// archMutator splits a module into a variant for each Target requested by the module. Target selection +// archTransitionMutator splits a module into a variant for each Target requested by the module. Target selection // for a module is in three levels, OsClass, multilib, and then Target. // OsClass selection is determined by: // - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects @@ -553,41 +566,32 @@ var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"} // // Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass, // but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets(). -func archMutator(bpctx blueprint.BottomUpMutatorContext) { - var module Module - var ok bool - if module, ok = bpctx.Module().(Module); !ok { - if bootstrap.IsBootstrapModule(bpctx.Module()) { - // Bootstrap Go modules are always the build architecture. - bpctx.CreateVariations(bpctx.Config().(Config).BuildOSTarget.ArchVariation()) - } - return - } +type archTransitionMutator struct{} + +type allArchInfo struct { + Targets map[string]Target + MultiTargets []Target + Primary string + Multilib string +} - // Bootstrap Go module support above requires this mutator to be a - // blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext - // filters out non-Soong modules. Now that we've handled them, create a - // normal android.BottomUpMutatorContext. - mctx := bottomUpMutatorContextFactory(bpctx, module, false) - defer bottomUpMutatorContextPool.Put(mctx) +var allArchProvider = blueprint.NewMutatorProvider[*allArchInfo]("arch_propagate") +func (a *archTransitionMutator) Split(ctx BaseModuleContext) []string { + module := ctx.Module() base := module.base() if !base.ArchSpecific() { - return + return []string{""} } os := base.commonProperties.CompileOS if os == CommonOS { - // Make sure that the target related properties are initialized for the - // CommonOS variant. - addTargetProperties(module, commonTargetMap[os.Name], nil, true) - // Do not create arch specific variants for the CommonOS variant. - return + return []string{""} } - osTargets := mctx.Config().Targets[os] + osTargets := ctx.Config().Targets[os] image := base.commonProperties.ImageVariation // Filter NativeBridge targets unless they are explicitly supported. @@ -614,19 +618,18 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) { prefer32 := os == Windows // Determine the multilib selection for this module. - ignorePrefer32OnDevice := mctx.Config().IgnorePrefer32OnDevice() - multilib, extraMultilib := decodeMultilib(base, os, ignorePrefer32OnDevice) + multilib, extraMultilib := decodeMultilib(ctx, base) // Convert the multilib selection into a list of Targets. targets, err := decodeMultilibTargets(multilib, osTargets, prefer32) if err != nil { - mctx.ModuleErrorf("%s", err.Error()) + ctx.ModuleErrorf("%s", err.Error()) } // If there are no supported targets disable the module. if len(targets) == 0 { base.Disable() - return + return []string{""} } // If the module is using extraMultilib, decode the extraMultilib selection into @@ -635,7 +638,7 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) { if extraMultilib != "" { multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32) if err != nil { - mctx.ModuleErrorf("%s", err.Error()) + ctx.ModuleErrorf("%s", err.Error()) } multiTargets = filterHostCross(multiTargets, targets[0].HostCross) } @@ -643,7 +646,7 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) { // Recovery is always the primary architecture, filter out any other architectures. // Common arch is also allowed if image == RecoveryVariation { - primaryArch := mctx.Config().DevicePrimaryArchType() + primaryArch := ctx.Config().DevicePrimaryArchType() targets = filterToArch(targets, primaryArch, Common) multiTargets = filterToArch(multiTargets, primaryArch, Common) } @@ -651,37 +654,109 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) { // If there are no supported targets disable the module. if len(targets) == 0 { base.Disable() - return + return []string{""} } // Convert the targets into a list of arch variation names. targetNames := make([]string, len(targets)) + targetMapping := make(map[string]Target, len(targets)) for i, target := range targets { targetNames[i] = target.ArchVariation() + targetMapping[targetNames[i]] = targets[i] } - // Create the variations, annotate each one with which Target it was created for, and - // squash the appropriate arch-specific properties into the top level properties. - modules := mctx.CreateVariations(targetNames...) - for i, m := range modules { - addTargetProperties(m, targets[i], multiTargets, i == 0) - m.base().setArchProperties(mctx) + SetProvider(ctx, allArchProvider, &allArchInfo{ + Targets: targetMapping, + MultiTargets: multiTargets, + Primary: targetNames[0], + Multilib: multilib, + }) + return targetNames +} + +func (a *archTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string { + return sourceVariation +} - // Install support doesn't understand Darwin+Arm64 - if os == Darwin && targets[i].HostCross { - m.base().commonProperties.SkipInstall = true +func (a *archTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string { + module := ctx.Module() + base := module.base() + + if !base.ArchSpecific() { + return "" + } + + os := base.commonProperties.CompileOS + if os == CommonOS { + // Do not create arch specific variants for the CommonOS variant. + return "" + } + + if incomingVariation == "" { + multilib, _ := decodeMultilib(ctx, base) + if multilib == "common" { + return "common" } } + return incomingVariation +} + +func (a *archTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) { + module := ctx.Module() + base := module.base() + os := base.commonProperties.CompileOS + + if os == CommonOS { + // Make sure that the target related properties are initialized for the + // CommonOS variant. + addTargetProperties(module, commonTargetMap[os.Name], nil, true) + return + } + + if variation == "" { + return + } + + if !base.ArchSpecific() { + panic(fmt.Errorf("found variation %q for non arch specifc module", variation)) + } + + allArchInfo, ok := ModuleProvider(ctx, allArchProvider) + if !ok { + return + } + + target, ok := allArchInfo.Targets[variation] + if !ok { + panic(fmt.Errorf("missing Target for %q", variation)) + } + primary := variation == allArchInfo.Primary + multiTargets := allArchInfo.MultiTargets + + // Annotate the new variant with which Target it was created for, and + // squash the appropriate arch-specific properties into the top level properties. + addTargetProperties(ctx.Module(), target, multiTargets, primary) + base.setArchProperties(ctx) + + // Install support doesn't understand Darwin+Arm64 + if os == Darwin && target.HostCross { + base.commonProperties.SkipInstall = true + } // Create a dependency for Darwin Universal binaries from the primary to secondary // architecture. The module itself will be responsible for calling lipo to merge the outputs. if os == Darwin { - if multilib == "darwin_universal" && len(modules) == 2 { - mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[1], modules[0]) - } else if multilib == "darwin_universal_common_first" && len(modules) == 3 { - mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[2], modules[1]) + isUniversalBinary := (allArchInfo.Multilib == "darwin_universal" && len(allArchInfo.Targets) == 2) || + allArchInfo.Multilib == "darwin_universal_common_first" && len(allArchInfo.Targets) == 3 + isPrimary := variation == ctx.Config().BuildArch.String() + hasSecondaryConfigured := len(ctx.Config().Targets[Darwin]) > 1 + if isUniversalBinary && isPrimary && hasSecondaryConfigured { + secondaryArch := ctx.Config().Targets[Darwin][1].Arch.String() + variation := []blueprint.Variation{{"arch", secondaryArch}} + ctx.AddVariationDependencies(variation, DarwinUniversalVariantTag, ctx.ModuleName()) } } + } // addTargetProperties annotates a variant with the Target is is being compiled for, the list @@ -698,7 +773,9 @@ func addTargetProperties(m Module, target Target, multiTargets []Target, primary // multilib from the factory's call to InitAndroidArchModule if none was set. For modules that // called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns // the actual multilib in extraMultilib. -func decodeMultilib(base *ModuleBase, os OsType, ignorePrefer32OnDevice bool) (multilib, extraMultilib string) { +func decodeMultilib(ctx ConfigContext, base *ModuleBase) (multilib, extraMultilib string) { + os := base.commonProperties.CompileOS + ignorePrefer32OnDevice := ctx.Config().IgnorePrefer32OnDevice() // First check the "android.compile_multilib" or "host.compile_multilib" properties. switch os.Class { case Device: diff --git a/android/arch_test.go b/android/arch_test.go index 6134a065f..57c901032 100644 --- a/android/arch_test.go +++ b/android/arch_test.go @@ -451,7 +451,7 @@ func TestArchMutator(t *testing.T) { for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { - if tt.goOS != runtime.GOOS { + if tt.goOS != "" && tt.goOS != runtime.GOOS { t.Skipf("requries runtime.GOOS %s", tt.goOS) } diff --git a/android/base_module_context.go b/android/base_module_context.go index 550600052..bb8137720 100644 --- a/android/base_module_context.go +++ b/android/base_module_context.go @@ -220,6 +220,10 @@ type BaseModuleContext interface { // EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context // can be used to evaluate the final value of Configurable properties. EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue + + // HasMutatorFinished returns true if the given mutator has finished running. + // It will panic if given an invalid mutator name. + HasMutatorFinished(mutatorName string) bool } type baseModuleContext struct { @@ -270,6 +274,10 @@ func (b *baseModuleContext) setProvider(provider blueprint.AnyProviderKey, value b.bp.SetProvider(provider, value) } +func (b *baseModuleContext) HasMutatorFinished(mutatorName string) bool { + return b.bp.HasMutatorFinished(mutatorName) +} + func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module { return b.bp.GetDirectDepWithTag(name, tag) } diff --git a/android/config.go b/android/config.go index b682c2e93..00fc823a8 100644 --- a/android/config.go +++ b/android/config.go @@ -238,6 +238,11 @@ func (c Config) ReleaseAconfigFlagDefaultPermission() string { return c.config.productVariables.ReleaseAconfigFlagDefaultPermission } +// Enable object size sanitizer +func (c Config) ReleaseBuildObjectSizeSanitizer() bool { + return c.config.productVariables.GetBuildFlagBool("RELEASE_BUILD_OBJECT_SIZE_SANITIZER") +} + // The flag indicating behavior for the tree wrt building modules or using prebuilts // derived from RELEASE_DEFAULT_MODULE_BUILD_FROM_SOURCE func (c Config) ReleaseDefaultModuleBuildFromSource() bool { @@ -1663,6 +1668,17 @@ func (c *config) ApexTrimEnabled() bool { return Bool(c.productVariables.TrimmedApex) } +func (c *config) UseSoongSystemImage() bool { + return Bool(c.productVariables.UseSoongSystemImage) +} + +func (c *config) SoongDefinedSystemImage() string { + if c.UseSoongSystemImage() { + return String(c.productVariables.ProductSoongDefinedSystemImage) + } + return "" +} + func (c *config) EnforceSystemCertificate() bool { return Bool(c.productVariables.EnforceSystemCertificate) } @@ -1954,6 +1970,10 @@ func (c *config) GetBuildFlag(name string) (string, bool) { return val, ok } +func (c *config) UseOptimizedResourceShrinkingByDefault() bool { + return c.productVariables.GetBuildFlagBool("RELEASE_USE_OPTIMIZED_RESOURCE_SHRINKING_BY_DEFAULT") +} + func (c *config) UseResourceProcessorByDefault() bool { return c.productVariables.GetBuildFlagBool("RELEASE_USE_RESOURCE_PROCESSOR_BY_DEFAULT") } diff --git a/android/defaults.go b/android/defaults.go index 0d51d9d7c..3d06c69c9 100644 --- a/android/defaults.go +++ b/android/defaults.go @@ -69,7 +69,7 @@ type Defaultable interface { // Apply defaults from the supplied Defaults to the property structures supplied to // setProperties(...). - applyDefaults(TopDownMutatorContext, []Defaults) + applyDefaults(BottomUpMutatorContext, []Defaults) // Set the hook to be called after any defaults have been applied. // @@ -101,6 +101,7 @@ func InitDefaultableModule(module DefaultableModule) { // A restricted subset of context methods, similar to LoadHookContext. type DefaultableHookContext interface { EarlyModuleContext + OtherModuleProviderContext CreateModule(ModuleFactory, ...interface{}) Module AddMissingDependencies(missingDeps []string) @@ -209,7 +210,7 @@ func InitDefaultsModule(module DefaultsModule) { var _ Defaults = (*DefaultsModuleBase)(nil) -func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext, +func (defaultable *DefaultableModuleBase) applyDefaults(ctx BottomUpMutatorContext, defaultsList []Defaults) { for _, defaults := range defaultsList { @@ -226,7 +227,7 @@ func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContex // Product variable properties need special handling, the type of the filtered product variable // property struct may not be identical between the defaults module and the defaultable module. // Use PrependMatchingProperties to apply whichever properties match. -func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext, +func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx BottomUpMutatorContext, defaults Defaults, defaultableProp interface{}) { if defaultableProp == nil { return @@ -254,7 +255,7 @@ func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx Top } } -func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext, +func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx BottomUpMutatorContext, defaults Defaults, defaultableProp interface{}) { for _, def := range defaults.properties() { @@ -273,7 +274,7 @@ func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMuta func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) { ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel() - ctx.TopDown("defaults", defaultsMutator).Parallel() + ctx.BottomUp("defaults", defaultsMutator).Parallel() } func defaultsDepsMutator(ctx BottomUpMutatorContext) { @@ -282,8 +283,12 @@ func defaultsDepsMutator(ctx BottomUpMutatorContext) { } } -func defaultsMutator(ctx TopDownMutatorContext) { +func defaultsMutator(ctx BottomUpMutatorContext) { if defaultable, ok := ctx.Module().(Defaultable); ok { + if _, isDefaultsModule := ctx.Module().(Defaults); isDefaultsModule { + // Don't squash transitive defaults into defaults modules + return + } defaults := defaultable.defaults().Defaults if len(defaults) > 0 { var defaultsList []Defaults diff --git a/android/init.go b/android/init.go index d5b486b10..b46229282 100644 --- a/android/init.go +++ b/android/init.go @@ -18,5 +18,6 @@ import "encoding/gob" func init() { gob.Register(ModuleOutPath{}) + gob.Register(PhonyPath{}) gob.Register(unstableInfo{}) } diff --git a/android/module.go b/android/module.go index 009b0dfb6..1a3f328eb 100644 --- a/android/module.go +++ b/android/module.go @@ -58,7 +58,7 @@ type Module interface { base() *ModuleBase Disable() - Enabled(ctx ConfigAndErrorContext) bool + Enabled(ctx ConfigurableEvaluatorContext) bool Target() Target MultiTargets() []Target @@ -109,12 +109,12 @@ type Module interface { // Get information about the properties that can contain visibility rules. visibilityProperties() []visibilityProperty - RequiredModuleNames(ctx ConfigAndErrorContext) []string + RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string HostRequiredModuleNames() []string TargetRequiredModuleNames() []string - VintfFragmentModuleNames(ctx ConfigAndErrorContext) []string + VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string - ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools.ConfigurableEvaluator + ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator } // Qualified id for a module @@ -443,12 +443,6 @@ type commonProperties struct { // Set at module initialization time by calling InitCommonOSAndroidMultiTargetsArchModule CreateCommonOSVariant bool `blueprint:"mutated"` - // If set to true then this variant is the CommonOS variant that has dependencies on its - // OsType specific variants. - // - // Set by osMutator. - CommonOSVariant bool `blueprint:"mutated"` - // When set to true, this module is not installed to the full install path (ex: under // out/target/product/<name>/<partition>). It can be installed only to the packaging // modules like android_filesystem. @@ -1221,7 +1215,7 @@ func (m *ModuleBase) ArchSpecific() bool { // True if the current variant is a CommonOS variant, false otherwise. func (m *ModuleBase) IsCommonOSVariant() bool { - return m.commonProperties.CommonOSVariant + return m.commonProperties.CompileOS == CommonOS } // supportsTarget returns true if the given Target is supported by the current module. @@ -1339,13 +1333,21 @@ func (m *ModuleBase) PartitionTag(config DeviceConfig) string { return partition } -func (m *ModuleBase) Enabled(ctx ConfigAndErrorContext) bool { +func (m *ModuleBase) Enabled(ctx ConfigurableEvaluatorContext) bool { if m.commonProperties.ForcedDisabled { return false } return m.commonProperties.Enabled.GetOrDefault(m.ConfigurableEvaluator(ctx), !m.Os().DefaultDisabled) } +// Returns a copy of the enabled property, useful for passing it on to sub-modules +func (m *ModuleBase) EnabledProperty() proptools.Configurable[bool] { + if m.commonProperties.ForcedDisabled { + return proptools.NewSimpleConfigurable(false) + } + return m.commonProperties.Enabled.Clone() +} + func (m *ModuleBase) Disable() { m.commonProperties.ForcedDisabled = true } @@ -1536,7 +1538,7 @@ func (m *ModuleBase) InRecovery() bool { return m.base().commonProperties.ImageVariation == RecoveryVariation } -func (m *ModuleBase) RequiredModuleNames(ctx ConfigAndErrorContext) []string { +func (m *ModuleBase) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string { return m.base().commonProperties.Required.GetOrDefault(m.ConfigurableEvaluator(ctx), nil) } @@ -1548,7 +1550,7 @@ func (m *ModuleBase) TargetRequiredModuleNames() []string { return m.base().commonProperties.Target_required } -func (m *ModuleBase) VintfFragmentModuleNames(ctx ConfigAndErrorContext) []string { +func (m *ModuleBase) VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string { return m.base().commonProperties.Vintf_fragment_modules.GetOrDefault(m.ConfigurableEvaluator(ctx), nil) } @@ -2204,17 +2206,23 @@ func (m *ModuleBase) IsNativeBridgeSupported() bool { return proptools.Bool(m.commonProperties.Native_bridge_supported) } -type ConfigAndErrorContext interface { +type ConfigContext interface { + Config() Config +} + +type ConfigurableEvaluatorContext interface { + OtherModuleProviderContext Config() Config OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) + HasMutatorFinished(mutatorName string) bool } type configurationEvalutor struct { - ctx ConfigAndErrorContext + ctx ConfigurableEvaluatorContext m Module } -func (m *ModuleBase) ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools.ConfigurableEvaluator { +func (m *ModuleBase) ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator { return configurationEvalutor{ ctx: ctx, m: m.module, @@ -2228,6 +2236,12 @@ func (e configurationEvalutor) PropertyErrorf(property string, fmt string, args func (e configurationEvalutor) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue { ctx := e.ctx m := e.m + + if !ctx.HasMutatorFinished("defaults") { + ctx.OtherModulePropertyErrorf(m, property, "Cannot evaluate configurable property before the defaults mutator has run") + return proptools.ConfigurableValueUndefined() + } + switch condition.FunctionName() { case "release_flag": if condition.NumArgs() != 1 { diff --git a/android/module_context.go b/android/module_context.go index 3889e40e8..2bf2a8f00 100644 --- a/android/module_context.go +++ b/android/module_context.go @@ -85,7 +85,9 @@ type ModuleBuildParams BuildParams type ModuleContext interface { BaseModuleContext - blueprintModuleContext() blueprint.ModuleContext + // BlueprintModuleContext returns the blueprint.ModuleContext that the ModuleContext wraps. It may only be + // used by the golang module types that need to call into the bootstrap module types. + BlueprintModuleContext() blueprint.ModuleContext // Deprecated: use ModuleContext.Build instead. ModuleBuild(pctx PackageContext, params ModuleBuildParams) @@ -194,7 +196,7 @@ type ModuleContext interface { InstallInVendor() bool InstallForceOS() (*OsType, *ArchType) - RequiredModuleNames(ctx ConfigAndErrorContext) []string + RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string HostRequiredModuleNames() []string TargetRequiredModuleNames() []string @@ -779,7 +781,7 @@ func (m *moduleContext) UncheckedModule() { m.uncheckedModule = true } -func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext { +func (m *moduleContext) BlueprintModuleContext() blueprint.ModuleContext { return m.bp } @@ -855,7 +857,7 @@ func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) Optional return OptionalPath{} } -func (m *moduleContext) RequiredModuleNames(ctx ConfigAndErrorContext) []string { +func (m *moduleContext) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string { return m.module.RequiredModuleNames(ctx) } diff --git a/android/mutator.go b/android/mutator.go index 38fb857dd..940494506 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -148,9 +148,9 @@ var preArch = []RegisterMutatorFunc{ } func registerArchMutator(ctx RegisterMutatorsContext) { - ctx.BottomUpBlueprint("os", osMutator).Parallel() + ctx.Transition("os", &osTransitionMutator{}) ctx.Transition("image", &imageTransitionMutator{}) - ctx.BottomUpBlueprint("arch", archMutator).Parallel() + ctx.Transition("arch", &archTransitionMutator{}) } var preDeps = []RegisterMutatorFunc{ @@ -193,16 +193,16 @@ type BaseMutatorContext interface { // Rename all variants of a module. The new name is not visible to calls to ModuleName, // AddDependency or OtherModuleName until after this mutator pass is complete. Rename(name string) + + // CreateModule creates a new module by calling the factory method for the specified moduleType, and applies + // the specified property structs to it as if the properties were set in a blueprint file. + CreateModule(ModuleFactory, ...interface{}) Module } type TopDownMutator func(TopDownMutatorContext) type TopDownMutatorContext interface { BaseMutatorContext - - // CreateModule creates a new module by calling the factory method for the specified moduleType, and applies - // the specified property structs to it as if the properties were set in a blueprint file. - CreateModule(ModuleFactory, ...interface{}) Module } type topDownMutatorContext struct { @@ -516,6 +516,9 @@ type androidTransitionMutator struct { } func (a *androidTransitionMutator) Split(ctx blueprint.BaseModuleContext) []string { + if a.finalPhase { + panic("TransitionMutator not allowed in FinalDepsMutators") + } if m, ok := ctx.Module().(Module); ok { moduleContext := m.base().baseModuleContextFactory(ctx) return a.mutator.Split(&moduleContext) @@ -739,6 +742,14 @@ func (b *bottomUpMutatorContext) Rename(name string) { b.Module().base().commonProperties.DebugName = name } +func (b *bottomUpMutatorContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) blueprint.Module { + return b.bp.CreateModule(factory, name, props...) +} + +func (b *bottomUpMutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module { + return createModule(b, factory, "_bottomUpMutatorModule", props...) +} + func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module { if b.baseModuleContext.checkedMissingDeps() { panic("Adding deps not allowed after checking for missing deps") diff --git a/android/mutator_test.go b/android/mutator_test.go index 21eebd2c8..b3ef00f3d 100644 --- a/android/mutator_test.go +++ b/android/mutator_test.go @@ -81,6 +81,40 @@ func TestMutatorAddMissingDependencies(t *testing.T) { AssertDeepEquals(t, "foo missing deps", []string{"added_missing_dep", "regular_missing_dep"}, foo.missingDeps) } +type testTransitionMutator struct { + split func(ctx BaseModuleContext) []string + outgoingTransition func(ctx OutgoingTransitionContext, sourceVariation string) string + incomingTransition func(ctx IncomingTransitionContext, incomingVariation string) string + mutate func(ctx BottomUpMutatorContext, variation string) +} + +func (t *testTransitionMutator) Split(ctx BaseModuleContext) []string { + if t.split != nil { + return t.split(ctx) + } + return []string{""} +} + +func (t *testTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string { + if t.outgoingTransition != nil { + return t.outgoingTransition(ctx, sourceVariation) + } + return sourceVariation +} + +func (t *testTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string { + if t.incomingTransition != nil { + return t.incomingTransition(ctx, incomingVariation) + } + return incomingVariation +} + +func (t *testTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) { + if t.mutate != nil { + t.mutate(ctx, variation) + } +} + func TestModuleString(t *testing.T) { bp := ` test { @@ -94,9 +128,11 @@ func TestModuleString(t *testing.T) { FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.PreArchMutators(func(ctx RegisterMutatorsContext) { - ctx.BottomUp("pre_arch", func(ctx BottomUpMutatorContext) { - moduleStrings = append(moduleStrings, ctx.Module().String()) - ctx.CreateVariations("a", "b") + ctx.Transition("pre_arch", &testTransitionMutator{ + split: func(ctx BaseModuleContext) []string { + moduleStrings = append(moduleStrings, ctx.Module().String()) + return []string{"a", "b"} + }, }) ctx.TopDown("rename_top_down", func(ctx TopDownMutatorContext) { moduleStrings = append(moduleStrings, ctx.Module().String()) @@ -105,16 +141,23 @@ func TestModuleString(t *testing.T) { }) ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { - ctx.BottomUp("pre_deps", func(ctx BottomUpMutatorContext) { - moduleStrings = append(moduleStrings, ctx.Module().String()) - ctx.CreateVariations("c", "d") + ctx.Transition("pre_deps", &testTransitionMutator{ + split: func(ctx BaseModuleContext) []string { + moduleStrings = append(moduleStrings, ctx.Module().String()) + return []string{"c", "d"} + }, }) }) ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) { - ctx.BottomUp("post_deps", func(ctx BottomUpMutatorContext) { - moduleStrings = append(moduleStrings, ctx.Module().String()) - ctx.CreateLocalVariations("e", "f") + ctx.Transition("post_deps", &testTransitionMutator{ + split: func(ctx BaseModuleContext) []string { + moduleStrings = append(moduleStrings, ctx.Module().String()) + return []string{"e", "f"} + }, + outgoingTransition: func(ctx OutgoingTransitionContext, sourceVariation string) string { + return "" + }, }) ctx.BottomUp("rename_bottom_up", func(ctx BottomUpMutatorContext) { moduleStrings = append(moduleStrings, ctx.Module().String()) @@ -138,15 +181,15 @@ func TestModuleString(t *testing.T) { "foo{pre_arch:b}", "foo{pre_arch:a}", - // After rename_top_down. - "foo_renamed1{pre_arch:a}", + // After rename_top_down (reversed because pre_deps TransitionMutator.Split is TopDown). "foo_renamed1{pre_arch:b}", + "foo_renamed1{pre_arch:a}", - // After pre_deps. - "foo_renamed1{pre_arch:a,pre_deps:c}", - "foo_renamed1{pre_arch:a,pre_deps:d}", - "foo_renamed1{pre_arch:b,pre_deps:c}", + // After pre_deps (reversed because post_deps TransitionMutator.Split is TopDown). "foo_renamed1{pre_arch:b,pre_deps:d}", + "foo_renamed1{pre_arch:b,pre_deps:c}", + "foo_renamed1{pre_arch:a,pre_deps:d}", + "foo_renamed1{pre_arch:a,pre_deps:c}", // After post_deps. "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:e}", @@ -202,8 +245,10 @@ func TestFinalDepsPhase(t *testing.T) { ctx.AddFarVariationDependencies([]blueprint.Variation{}, dep1Tag, "common_dep_1") } }) - ctx.BottomUp("variant", func(ctx BottomUpMutatorContext) { - ctx.CreateLocalVariations("a", "b") + ctx.Transition("variant", &testTransitionMutator{ + split: func(ctx BaseModuleContext) []string { + return []string{"a", "b"} + }, }) }) @@ -243,27 +288,20 @@ func TestFinalDepsPhase(t *testing.T) { } func TestNoCreateVariationsInFinalDeps(t *testing.T) { - checkErr := func() { - if err := recover(); err == nil || !strings.Contains(fmt.Sprintf("%s", err), "not allowed in FinalDepsMutators") { - panic("Expected FinalDepsMutators consistency check to fail") - } - } - GroupFixturePreparers( FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) { - ctx.BottomUp("vars", func(ctx BottomUpMutatorContext) { - defer checkErr() - ctx.CreateVariations("a", "b") - }) - ctx.BottomUp("local_vars", func(ctx BottomUpMutatorContext) { - defer checkErr() - ctx.CreateLocalVariations("a", "b") + ctx.Transition("vars", &testTransitionMutator{ + split: func(ctx BaseModuleContext) []string { + return []string{"a", "b"} + }, }) }) ctx.RegisterModuleType("test", mutatorTestModuleFactory) }), FixtureWithRootAndroidBp(`test {name: "foo"}`), - ).RunTest(t) + ). + ExtendWithErrorHandler(FixtureExpectsOneErrorPattern("not allowed in FinalDepsMutators")). + RunTest(t) } diff --git a/android/packaging_test.go b/android/packaging_test.go index 0f7bb39a1..f5b1020fc 100644 --- a/android/packaging_test.go +++ b/android/packaging_test.go @@ -118,6 +118,7 @@ func runPackagingTest(t *testing.T, config testConfig, bp string, expected []str } result := GroupFixturePreparers( + PrepareForTestWithDefaults, PrepareForTestWithArchMutator, FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.RegisterModuleType("component", componentTestModuleFactory) diff --git a/android/paths.go b/android/paths.go index e45795989..0d94f03e6 100644 --- a/android/paths.go +++ b/android/paths.go @@ -27,7 +27,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/pathtools" ) @@ -92,8 +91,10 @@ func GlobFiles(ctx EarlyModulePathContext, globPattern string, excludes []string // the Path methods that rely on module dependencies having been resolved. type ModuleWithDepsPathContext interface { EarlyModulePathContext + OtherModuleProviderContext VisitDirectDepsBlueprint(visit func(blueprint.Module)) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag + HasMutatorFinished(mutatorName string) bool } // ModuleMissingDepsPathContext is a subset of *ModuleContext methods required by @@ -554,13 +555,6 @@ func (p OutputPaths) Strings() []string { return ret } -// PathForGoBinary returns the path to the installed location of a bootstrap_go_binary module. -func PathForGoBinary(ctx PathContext, goBinary bootstrap.GoBinaryTool) Path { - goBinaryInstallDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "bin") - rel := Rel(ctx, goBinaryInstallDir.String(), goBinary.InstallPath()) - return goBinaryInstallDir.Join(ctx, rel) -} - // Expands Paths to a SourceFileProducer or OutputFileProducer module dependency referenced via ":name" or ":name{.tag}" syntax. // If the dependency is not found, a missingErrorDependency is returned. // If the module dependency is not a SourceFileProducer or OutputFileProducer, appropriate errors will be returned. @@ -572,10 +566,6 @@ func getPathsFromModuleDep(ctx ModuleWithDepsPathContext, path, moduleName, tag if aModule, ok := module.(Module); ok && !aModule.Enabled(ctx) { return nil, missingDependencyError{[]string{moduleName}} } - if goBinary, ok := module.(bootstrap.GoBinaryTool); ok && tag == "" { - goBinaryPath := PathForGoBinary(ctx, goBinary) - return Paths{goBinaryPath}, nil - } outputFiles, err := outputFilesForModule(ctx, module, tag) if outputFiles != nil && err == nil { return outputFiles, nil diff --git a/android/product_config.go b/android/product_config.go index 04180bf2b..ce3acc9f2 100644 --- a/android/product_config.go +++ b/android/product_config.go @@ -14,7 +14,9 @@ package android -import "github.com/google/blueprint/proptools" +import ( + "github.com/google/blueprint/proptools" +) func init() { ctx := InitRegistrationContext diff --git a/android/product_config_to_bp.go b/android/product_config_to_bp.go new file mode 100644 index 000000000..680328f67 --- /dev/null +++ b/android/product_config_to_bp.go @@ -0,0 +1,35 @@ +// Copyright 2024 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 android + +func init() { + ctx := InitRegistrationContext + ctx.RegisterParallelSingletonType("product_config_to_bp_singleton", productConfigToBpSingletonFactory) +} + +type productConfigToBpSingleton struct{} + +func (s *productConfigToBpSingleton) GenerateBuildActions(ctx SingletonContext) { + // TODO: update content from make-based product config + var content string + generatedBp := PathForOutput(ctx, "soong_generated_product_config.bp") + WriteFileRule(ctx, generatedBp, content) + ctx.Phony("product_config_to_bp", generatedBp) +} + +// productConfigToBpSingleton generates a bp file from make-based product config +func productConfigToBpSingletonFactory() Singleton { + return &productConfigToBpSingleton{} +} diff --git a/android/sdk.go b/android/sdk.go index d3f04a4f9..ab9a91ccb 100644 --- a/android/sdk.go +++ b/android/sdk.go @@ -813,8 +813,6 @@ type SdkMemberProperties interface { // SdkMemberContext provides access to information common to a specific member. type SdkMemberContext interface { - ConfigAndErrorContext - // SdkModuleContext returns the module context of the sdk common os variant which is creating the // snapshot. // diff --git a/android/singleton.go b/android/singleton.go index 8542bd9e6..913bf6a56 100644 --- a/android/singleton.go +++ b/android/singleton.go @@ -90,6 +90,10 @@ type SingletonContext interface { // OtherModulePropertyErrorf reports an error on the line number of the given property of the given module OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) + + // HasMutatorFinished returns true if the given mutator has finished running. + // It will panic if given an invalid mutator name. + HasMutatorFinished(mutatorName string) bool } type singletonAdaptor struct { @@ -286,3 +290,7 @@ func (s *singletonContextAdaptor) otherModuleProvider(module blueprint.Module, p func (s *singletonContextAdaptor) OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) { s.blueprintSingletonContext().OtherModulePropertyErrorf(module, property, format, args...) } + +func (s *singletonContextAdaptor) HasMutatorFinished(mutatorName string) bool { + return s.blueprintSingletonContext().HasMutatorFinished(mutatorName) +} diff --git a/android/singleton_module_test.go b/android/singleton_module_test.go index 3b1bf39e3..3b8c6b213 100644 --- a/android/singleton_module_test.go +++ b/android/singleton_module_test.go @@ -96,12 +96,6 @@ func TestUnusedSingletonModule(t *testing.T) { } } -func testVariantSingletonModuleMutator(ctx BottomUpMutatorContext) { - if _, ok := ctx.Module().(*testSingletonModule); ok { - ctx.CreateVariations("a", "b") - } -} - func TestVariantSingletonModule(t *testing.T) { if testing.Short() { t.Skip("test fails with data race enabled") @@ -116,7 +110,11 @@ func TestVariantSingletonModule(t *testing.T) { prepareForSingletonModuleTest, FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { - ctx.BottomUp("test_singleton_module_mutator", testVariantSingletonModuleMutator) + ctx.Transition("test_singleton_module_mutator", &testTransitionMutator{ + split: func(ctx BaseModuleContext) []string { + return []string{"a", "b"} + }, + }) }) }), ). diff --git a/android/testing.go b/android/testing.go index 816707d63..196b22e3e 100644 --- a/android/testing.go +++ b/android/testing.go @@ -1326,7 +1326,15 @@ func (ctx *panickingConfigAndErrorContext) Config() Config { return ctx.ctx.Config() } -func PanickingConfigAndErrorContext(ctx *TestContext) ConfigAndErrorContext { +func (ctx *panickingConfigAndErrorContext) HasMutatorFinished(mutatorName string) bool { + return ctx.ctx.HasMutatorFinished(mutatorName) +} + +func (ctx *panickingConfigAndErrorContext) otherModuleProvider(m blueprint.Module, p blueprint.AnyProviderKey) (any, bool) { + return ctx.ctx.otherModuleProvider(m, p) +} + +func PanickingConfigAndErrorContext(ctx *TestContext) ConfigurableEvaluatorContext { return &panickingConfigAndErrorContext{ ctx: ctx, } diff --git a/android/util.go b/android/util.go index 3c0af2f38..2d269b724 100644 --- a/android/util.go +++ b/android/util.go @@ -177,6 +177,41 @@ func setFromList[T comparable](l []T) map[T]bool { return m } +// PrettyConcat returns the formatted concatenated string suitable for displaying user-facing +// messages. +func PrettyConcat(list []string, quote bool, lastSep string) string { + if len(list) == 0 { + return "" + } + + quoteStr := func(v string) string { + if !quote { + return v + } + return fmt.Sprintf("%q", v) + } + + if len(list) == 1 { + return quoteStr(list[0]) + } + + var sb strings.Builder + for i, val := range list { + if i > 0 { + sb.WriteString(", ") + } + if i == len(list)-1 { + sb.WriteString(lastSep) + if lastSep != "" { + sb.WriteString(" ") + } + } + sb.WriteString(quoteStr(val)) + } + + return sb.String() +} + // ListSetDifference checks if the two lists contain the same elements. It returns // a boolean which is true if there is a difference, and then returns lists of elements // that are in l1 but not l2, and l2 but not l1. diff --git a/android/util_test.go b/android/util_test.go index 6537d69b9..b76ffcfea 100644 --- a/android/util_test.go +++ b/android/util_test.go @@ -867,3 +867,51 @@ func TestHasIntersection(t *testing.T) { }) } } + +var prettyConcatTestCases = []struct { + name string + list []string + quote bool + lastSeparator string + expected string +}{ + { + name: "empty", + list: []string{}, + quote: false, + lastSeparator: "and", + expected: ``, + }, + { + name: "single", + list: []string{"a"}, + quote: true, + lastSeparator: "and", + expected: `"a"`, + }, + { + name: "with separator", + list: []string{"a", "b", "c"}, + quote: true, + lastSeparator: "or", + expected: `"a", "b", or "c"`, + }, + { + name: "without separator", + list: []string{"a", "b", "c"}, + quote: false, + lastSeparator: "", + expected: `a, b, c`, + }, +} + +func TestPrettyConcat(t *testing.T) { + for _, testCase := range prettyConcatTestCases { + t.Run(testCase.name, func(t *testing.T) { + concatString := PrettyConcat(testCase.list, testCase.quote, testCase.lastSeparator) + if !reflect.DeepEqual(concatString, testCase.expected) { + t.Errorf("expected %#v, got %#v", testCase.expected, concatString) + } + }) + } +} diff --git a/android/variable.go b/android/variable.go index b238c4a5d..e0d512d3a 100644 --- a/android/variable.go +++ b/android/variable.go @@ -423,6 +423,9 @@ type ProductVariables struct { TargetFSConfigGen []string `json:",omitempty"` + UseSoongSystemImage *bool `json:",omitempty"` + ProductSoongDefinedSystemImage *string `json:",omitempty"` + EnforceProductPartitionInterface *bool `json:",omitempty"` EnforceInterPartitionJavaSdkLibrary *bool `json:",omitempty"` diff --git a/android/visibility.go b/android/visibility.go index 89c0adc15..61f220026 100644 --- a/android/visibility.go +++ b/android/visibility.go @@ -283,7 +283,7 @@ func RegisterVisibilityRuleGatherer(ctx RegisterMutatorsContext) { // This must be registered after the deps have been resolved. func RegisterVisibilityRuleEnforcer(ctx RegisterMutatorsContext) { - ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel() + ctx.BottomUp("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel() } // Checks the per-module visibility rule lists before defaults expansion. @@ -507,7 +507,7 @@ func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg, propert return true, pkg, name } -func visibilityRuleEnforcer(ctx TopDownMutatorContext) { +func visibilityRuleEnforcer(ctx BottomUpMutatorContext) { qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.Module()) // Visit all the dependencies making sure that this module has access to them all. diff --git a/apex/Android.bp b/apex/Android.bp index 17fdfc36a..ef2f75570 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -15,7 +15,6 @@ bootstrap_go_package { "soong-cc", "soong-filesystem", "soong-java", - "soong-multitree", "soong-provenance", "soong-python", "soong-rust", diff --git a/apex/apex.go b/apex/apex.go index 1f4a99b55..9e3f288ce 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -32,7 +32,6 @@ import ( prebuilt_etc "android/soong/etc" "android/soong/filesystem" "android/soong/java" - "android/soong/multitree" "android/soong/rust" "android/soong/sh" ) @@ -56,11 +55,10 @@ func registerApexBuildComponents(ctx android.RegistrationContext) { } func registerPreArchMutators(ctx android.RegisterMutatorsContext) { - ctx.TopDown("prebuilt_apex_module_creator", prebuiltApexModuleCreatorMutator).Parallel() + ctx.BottomUp("prebuilt_apex_module_creator", prebuiltApexModuleCreatorMutator).Parallel() } func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { - ctx.TopDown("apex_vndk", apexVndkMutator).Parallel() ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).Parallel() } @@ -438,7 +436,6 @@ type apexBundle struct { android.ModuleBase android.DefaultableModuleBase android.OverridableModuleBase - multitree.ExportableModuleBase // Properties properties apexBundleProperties @@ -1406,8 +1403,6 @@ func (a *apexBundle) DepIsInSameApex(_ android.BaseModuleContext, _ android.Modu return true } -var _ multitree.Exportable = (*apexBundle)(nil) - func (a *apexBundle) Exportable() bool { return true } @@ -2540,7 +2535,6 @@ func newApexBundle() *apexBundle { android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) android.InitOverridableModule(module, &module.overridableProperties.Overrides) - multitree.InitExportableModule(module) return module } @@ -2797,7 +2791,7 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { return false } - if to.AvailableFor(apexName) || baselineApexAvailable(apexName, toName) { + if to.AvailableFor(apexName) { return true } @@ -2857,74 +2851,6 @@ func (a *apexBundle) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeI dpInfo.Deps = append(dpInfo.Deps, a.properties.ResolvedSystemserverclasspathFragments...) } -var ( - apexAvailBaseline = makeApexAvailableBaseline() - inverseApexAvailBaseline = invertApexBaseline(apexAvailBaseline) -) - -func baselineApexAvailable(apex, moduleName string) bool { - key := apex - moduleName = normalizeModuleName(moduleName) - - if val, ok := apexAvailBaseline[key]; ok && android.InList(moduleName, val) { - return true - } - - key = android.AvailableToAnyApex - if val, ok := apexAvailBaseline[key]; ok && android.InList(moduleName, val) { - return true - } - - return false -} - -func normalizeModuleName(moduleName string) string { - // Prebuilt modules (e.g. java_import, etc.) have "prebuilt_" prefix added by the build - // system. Trim the prefix for the check since they are confusing - moduleName = android.RemoveOptionalPrebuiltPrefix(moduleName) - if strings.HasPrefix(moduleName, "libclang_rt.") { - // This module has many arch variants that depend on the product being built. - // We don't want to list them all - moduleName = "libclang_rt" - } - if strings.HasPrefix(moduleName, "androidx.") { - // TODO(b/156996905) Set apex_available/min_sdk_version for androidx support libraries - moduleName = "androidx" - } - return moduleName -} - -// Transform the map of apex -> modules to module -> apexes. -func invertApexBaseline(m map[string][]string) map[string][]string { - r := make(map[string][]string) - for apex, modules := range m { - for _, module := range modules { - r[module] = append(r[module], apex) - } - } - return r -} - -// Retrieve the baseline of apexes to which the supplied module belongs. -func BaselineApexAvailable(moduleName string) []string { - return inverseApexAvailBaseline[normalizeModuleName(moduleName)] -} - -// This is a map from apex to modules, which overrides the apex_available setting for that -// particular module to make it available for the apex regardless of its setting. -// TODO(b/147364041): remove this -func makeApexAvailableBaseline() map[string][]string { - // The "Module separator"s below are employed to minimize merge conflicts. - m := make(map[string][]string) - // - // Module separator - // - m["com.android.runtime"] = []string{ - "libz", - } - return m -} - func init() { android.AddNeverAllowRules(createBcpPermittedPackagesRules(qBcpPackages())...) android.AddNeverAllowRules(createBcpPermittedPackagesRules(rBcpPackages())...) diff --git a/apex/apex_test.go b/apex/apex_test.go index 6f52653a4..6d9c96ebe 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -10000,208 +10000,6 @@ func TestUpdatableApexEnforcesAppUpdatability(t *testing.T) { } } -func TestApexBuildsAgainstApiSurfaceStubLibraries(t *testing.T) { - bp := ` - apex { - name: "myapex", - key: "myapex.key", - native_shared_libs: ["libbaz"], - binaries: ["binfoo"], - min_sdk_version: "29", - } - apex_key { - name: "myapex.key", - } - cc_binary { - name: "binfoo", - shared_libs: ["libbar", "libbaz", "libqux",], - apex_available: ["myapex"], - min_sdk_version: "29", - recovery_available: false, - } - cc_library { - name: "libbar", - srcs: ["libbar.cc"], - stubs: { - symbol_file: "libbar.map.txt", - versions: [ - "29", - ], - }, - } - cc_library { - name: "libbaz", - srcs: ["libbaz.cc"], - apex_available: ["myapex"], - min_sdk_version: "29", - stubs: { - symbol_file: "libbaz.map.txt", - versions: [ - "29", - ], - }, - } - cc_api_library { - name: "libbar", - src: "libbar_stub.so", - min_sdk_version: "29", - variants: ["apex.29"], - } - cc_api_variant { - name: "libbar", - variant: "apex", - version: "29", - src: "libbar_apex_29.so", - } - cc_api_library { - name: "libbaz", - src: "libbaz_stub.so", - min_sdk_version: "29", - variants: ["apex.29"], - } - cc_api_variant { - name: "libbaz", - variant: "apex", - version: "29", - src: "libbaz_apex_29.so", - } - cc_api_library { - name: "libqux", - src: "libqux_stub.so", - min_sdk_version: "29", - variants: ["apex.29"], - } - cc_api_variant { - name: "libqux", - variant: "apex", - version: "29", - src: "libqux_apex_29.so", - } - api_imports { - name: "api_imports", - apex_shared_libs: [ - "libbar", - "libbaz", - "libqux", - ], - } - ` - result := testApex(t, bp) - - hasDep := func(m android.Module, wantDep android.Module) bool { - t.Helper() - var found bool - result.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found - } - - // Library defines stubs and cc_api_library should be used with cc_api_library - binfooApexVariant := result.ModuleForTests("binfoo", "android_arm64_armv8-a_apex29").Module() - libbarCoreVariant := result.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module() - libbarApiImportCoreVariant := result.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module() - - android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(binfooApexVariant, libbarApiImportCoreVariant)) - android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbarCoreVariant)) - - binFooCFlags := result.ModuleForTests("binfoo", "android_arm64_armv8-a_apex29").Rule("ld").Args["libFlags"] - android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbar.apex.29.apiimport.so") - android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbar.apiimport.so") - android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbar.so") - - // Library defined in the same APEX should be linked with original definition instead of cc_api_library - libbazApexVariant := result.ModuleForTests("libbaz", "android_arm64_armv8-a_shared_apex29").Module() - libbazApiImportCoreVariant := result.ModuleForTests("libbaz.apiimport", "android_arm64_armv8-a_shared").Module() - android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries even from same APEX", true, hasDep(binfooApexVariant, libbazApiImportCoreVariant)) - android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbazApexVariant)) - - android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbaz.so") - android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbaz.apiimport.so") - android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbaz.apex.29.apiimport.so") - - // cc_api_library defined without original library should be linked with cc_api_library - libquxApiImportApexVariant := result.ModuleForTests("libqux.apiimport", "android_arm64_armv8-a_shared").Module() - android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries even original library definition does not exist", true, hasDep(binfooApexVariant, libquxApiImportApexVariant)) - android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libqux.apex.29.apiimport.so") -} - -func TestPlatformBinaryBuildsAgainstApiSurfaceStubLibraries(t *testing.T) { - bp := ` - apex { - name: "myapex", - key: "myapex.key", - native_shared_libs: ["libbar"], - min_sdk_version: "29", - } - apex_key { - name: "myapex.key", - } - cc_binary { - name: "binfoo", - shared_libs: ["libbar"], - recovery_available: false, - } - cc_library { - name: "libbar", - srcs: ["libbar.cc"], - apex_available: ["myapex"], - min_sdk_version: "29", - stubs: { - symbol_file: "libbar.map.txt", - versions: [ - "29", - ], - }, - } - cc_api_library { - name: "libbar", - src: "libbar_stub.so", - variants: ["apex.29"], - } - cc_api_variant { - name: "libbar", - variant: "apex", - version: "29", - src: "libbar_apex_29.so", - } - api_imports { - name: "api_imports", - apex_shared_libs: [ - "libbar", - ], - } - ` - - result := testApex(t, bp) - - hasDep := func(m android.Module, wantDep android.Module) bool { - t.Helper() - var found bool - result.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found - } - - // Library defines stubs and cc_api_library should be used with cc_api_library - binfooApexVariant := result.ModuleForTests("binfoo", "android_arm64_armv8-a").Module() - libbarCoreVariant := result.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module() - libbarApiImportCoreVariant := result.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module() - - android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(binfooApexVariant, libbarApiImportCoreVariant)) - android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbarCoreVariant)) - - binFooCFlags := result.ModuleForTests("binfoo", "android_arm64_armv8-a").Rule("ld").Args["libFlags"] - android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbar.apex.29.apiimport.so") - android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbar.apiimport.so") - android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbar.so") -} - func TestTrimmedApex(t *testing.T) { bp := ` apex { @@ -10240,21 +10038,6 @@ func TestTrimmedApex(t *testing.T) { apex_available: ["myapex","mydcla"], min_sdk_version: "29", } - cc_api_library { - name: "libc", - src: "libc.so", - min_sdk_version: "29", - recovery_available: true, - vendor_available: true, - product_available: true, - } - api_imports { - name: "api_imports", - shared_libs: [ - "libc", - ], - header_libs: [], - } ` ctx := testApex(t, bp) module := ctx.ModuleForTests("myapex", "android_common_myapex") diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 2e5662dcb..f6f3efbfb 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -260,7 +260,7 @@ func (p *prebuiltCommon) AndroidMkEntries() []android.AndroidMkEntries { // prebuiltApexModuleCreator defines the methods that need to be implemented by prebuilt_apex and // apex_set in order to create the modules needed to provide access to the prebuilt .apex file. type prebuiltApexModuleCreator interface { - createPrebuiltApexModules(ctx android.TopDownMutatorContext) + createPrebuiltApexModules(ctx android.BottomUpMutatorContext) } // prebuiltApexModuleCreatorMutator is the mutator responsible for invoking the @@ -270,7 +270,7 @@ type prebuiltApexModuleCreator interface { // will need to access dependencies added by that (exported modules) but must run before the // DepsMutator so that the deapexer module it creates can add dependencies onto itself from the // exported modules. -func prebuiltApexModuleCreatorMutator(ctx android.TopDownMutatorContext) { +func prebuiltApexModuleCreatorMutator(ctx android.BottomUpMutatorContext) { module := ctx.Module() if creator, ok := module.(prebuiltApexModuleCreator); ok { creator.createPrebuiltApexModules(ctx) @@ -532,7 +532,7 @@ func PrebuiltFactory() android.Module { return module } -func createApexSelectorModule(ctx android.TopDownMutatorContext, name string, apexFileProperties *ApexFileProperties) { +func createApexSelectorModule(ctx android.BottomUpMutatorContext, name string, apexFileProperties *ApexFileProperties) { props := struct { Name *string }{ @@ -550,7 +550,7 @@ func createApexSelectorModule(ctx android.TopDownMutatorContext, name string, ap // A deapexer module is only needed when the prebuilt apex specifies one or more modules in either // the `exported_bootclasspath_fragments` properties as that indicates that // the listed modules need access to files from within the prebuilt .apex file. -func (p *prebuiltCommon) createDeapexerModuleIfNeeded(ctx android.TopDownMutatorContext, deapexerName string, apexFileSource string) { +func (p *prebuiltCommon) createDeapexerModuleIfNeeded(ctx android.BottomUpMutatorContext, deapexerName string, apexFileSource string) { // Only create the deapexer module if it is needed. if !p.hasExportedDeps() { return @@ -691,7 +691,7 @@ var _ prebuiltApexModuleCreator = (*Prebuilt)(nil) // / | \ // V V V // selector <--- deapexer <--- exported java lib -func (p *Prebuilt) createPrebuiltApexModules(ctx android.TopDownMutatorContext) { +func (p *Prebuilt) createPrebuiltApexModules(ctx android.BottomUpMutatorContext) { apexSelectorModuleName := apexSelectorModuleName(p.Name()) createApexSelectorModule(ctx, apexSelectorModuleName, &p.properties.ApexFileProperties) @@ -946,7 +946,7 @@ func apexSetFactory() android.Module { return module } -func createApexExtractorModule(ctx android.TopDownMutatorContext, name string, apexExtractorProperties *ApexExtractorProperties) { +func createApexExtractorModule(ctx android.BottomUpMutatorContext, name string, apexExtractorProperties *ApexExtractorProperties) { props := struct { Name *string }{ @@ -972,7 +972,7 @@ var _ prebuiltApexModuleCreator = (*ApexSet)(nil) // prebuilt_apex except that instead of creating a selector module which selects one .apex file // from those provided this creates an extractor module which extracts the appropriate .apex file // from the zip file containing them. -func (a *ApexSet) createPrebuiltApexModules(ctx android.TopDownMutatorContext) { +func (a *ApexSet) createPrebuiltApexModules(ctx android.BottomUpMutatorContext) { apexExtractorModuleName := apexExtractorModuleName(a.Name()) createApexExtractorModule(ctx, apexExtractorModuleName, &a.properties.ApexExtractorProperties) diff --git a/apex/vndk.go b/apex/vndk.go index 781aa3cbf..3ececc5c1 100644 --- a/apex/vndk.go +++ b/apex/vndk.go @@ -54,13 +54,26 @@ type apexVndkProperties struct { Vndk_version *string } -func apexVndkMutator(mctx android.TopDownMutatorContext) { - if ab, ok := mctx.Module().(*apexBundle); ok && ab.vndkApex { - if ab.IsNativeBridgeSupported() { +func apexVndkDepsMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(*cc.Module); ok && cc.IsForVndkApex(mctx, m) { + vndkVersion := m.VndkVersion() + + if vndkVersion == "" { + return + } + vndkVersion = "v" + vndkVersion + + vndkApexName := "com.android.vndk." + vndkVersion + + if mctx.OtherModuleExists(vndkApexName) { + mctx.AddReverseDependency(mctx.Module(), sharedLibTag, vndkApexName) + } + } else if a, ok := mctx.Module().(*apexBundle); ok && a.vndkApex { + if a.IsNativeBridgeSupported() { mctx.PropertyErrorf("native_bridge_supported", "%q doesn't support native bridge binary.", mctx.ModuleType()) } - vndkVersion := ab.vndkVersion() + vndkVersion := a.vndkVersion() if vndkVersion != "" { apiLevel, err := android.ApiLevelFromUser(mctx, vndkVersion) if err != nil { @@ -72,32 +85,14 @@ func apexVndkMutator(mctx android.TopDownMutatorContext) { if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) { // Disable VNDK APEXes for VNDK versions less than the minimum supported API // level for the primary architecture. - ab.Disable() + a.Disable() + } else { + mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion, mctx)...) } } } } -func apexVndkDepsMutator(mctx android.BottomUpMutatorContext) { - if m, ok := mctx.Module().(*cc.Module); ok && cc.IsForVndkApex(mctx, m) { - vndkVersion := m.VndkVersion() - - if vndkVersion == "" { - return - } - vndkVersion = "v" + vndkVersion - - vndkApexName := "com.android.vndk." + vndkVersion - - if mctx.OtherModuleExists(vndkApexName) { - mctx.AddReverseDependency(mctx.Module(), sharedLibTag, vndkApexName) - } - } else if a, ok := mctx.Module().(*apexBundle); ok && a.vndkApex { - vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current") - mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion, mctx)...) - } -} - // name is module.BaseModuleName() which is used as LOCAL_MODULE_NAME and also LOCAL_OVERRIDES_* func makeCompatSymlinks(name string, ctx android.ModuleContext) (symlinks android.InstallPaths) { // small helper to add symlink commands diff --git a/bpf/bpf.go b/bpf/bpf.go index 73c8800d8..86798217f 100644 --- a/bpf/bpf.go +++ b/bpf/bpf.go @@ -56,6 +56,7 @@ var ( ) func registerBpfBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("bpf_defaults", defaultsFactory) ctx.RegisterModuleType("bpf", BpfFactory) } @@ -77,10 +78,16 @@ type BpfProperties struct { // the C/C++ module. Cflags []string - // directories (relative to the root of the source tree) that will - // be added to the include paths using -I. + // list of directories relative to the root of the source tree that + // will be added to the include paths using -I. + // If possible, don't use this. If adding paths from the current + // directory, use local_include_dirs. If adding paths from other + // modules, use export_include_dirs in that module. Include_dirs []string + // list of directories relative to the Blueprint file that will be + // added to the include path using -I. + Local_include_dirs []string // optional subdirectory under which this module is installed into. Sub_dir string @@ -94,7 +101,7 @@ type BpfProperties struct { type bpf struct { android.ModuleBase - + android.DefaultableModuleBase properties BpfProperties objs android.Paths @@ -163,6 +170,10 @@ func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) { "-I " + ctx.ModuleDir(), } + for _, dir := range android.PathsForModuleSrc(ctx, bpf.properties.Local_include_dirs) { + cflags = append(cflags, "-I "+dir.String()) + } + for _, dir := range android.PathsForSource(ctx, bpf.properties.Include_dirs) { cflags = append(cflags, "-I "+dir.String()) } @@ -264,6 +275,26 @@ func (bpf *bpf) AndroidMk() android.AndroidMkData { } } +type Defaults struct { + android.ModuleBase + android.DefaultsModuleBase +} + +func defaultsFactory() android.Module { + return DefaultsFactory() +} + +func DefaultsFactory(props ...interface{}) android.Module { + module := &Defaults{} + + module.AddProperties(props...) + module.AddProperties(&BpfProperties{}) + + android.InitDefaultsModule(module) + + return module +} + func (bpf *bpf) SubDir() string { return bpf.properties.Sub_dir } @@ -274,5 +305,7 @@ func BpfFactory() android.Module { module.AddProperties(&module.properties) android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module } diff --git a/bpf/libbpf/libbpf_prog.go b/bpf/libbpf/libbpf_prog.go index 1fdb3d636..ac6151040 100644 --- a/bpf/libbpf/libbpf_prog.go +++ b/bpf/libbpf/libbpf_prog.go @@ -61,6 +61,7 @@ var ( ) func registerLibbpfProgBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("libbpf_defaults", defaultsFactory) ctx.RegisterModuleType("libbpf_prog", LibbpfProgFactory) } @@ -88,14 +89,17 @@ type LibbpfProgProperties struct { // be added to the include path using -I Local_include_dirs []string `android:"arch_variant"` + Header_libs []string `android:"arch_variant"` + // optional subdirectory under which this module is installed into. Relative_install_path string } type libbpfProg struct { android.ModuleBase + android.DefaultableModuleBase properties LibbpfProgProperties - objs android.Paths + objs android.Paths } var _ android.ImageInterface = (*libbpfProg)(nil) @@ -139,6 +143,7 @@ func (libbpf *libbpfProg) SetImageVariation(ctx android.BaseModuleContext, varia func (libbpf *libbpfProg) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddDependency(ctx.Module(), libbpfProgDepTag, "libbpf_headers") + ctx.AddVariationDependencies(nil, cc.HeaderDepTag(), libbpf.properties.Header_libs...) } func (libbpf *libbpfProg) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -180,6 +185,11 @@ func (libbpf *libbpfProg) GenerateAndroidBuildActions(ctx android.ModuleContext) depName := ctx.OtherModuleName(dep) ctx.ModuleErrorf("module %q is not a genrule", depName) } + } else if depTag == cc.HeaderDepTag() { + depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider) + for _, dir := range depExporterInfo.IncludeDirs { + cflags = append(cflags, "-I "+dir.String()) + } } }) @@ -269,10 +279,32 @@ func (libbpf *libbpfProg) AndroidMk() android.AndroidMkData { } } +type Defaults struct { + android.ModuleBase + android.DefaultsModuleBase +} + +func defaultsFactory() android.Module { + return DefaultsFactory() +} + +func DefaultsFactory(props ...interface{}) android.Module { + module := &Defaults{} + + module.AddProperties(props...) + module.AddProperties(&LibbpfProgProperties{}) + + android.InitDefaultsModule(module) + + return module +} + func LibbpfProgFactory() android.Module { module := &libbpfProg{} module.AddProperties(&module.properties) android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitDefaultableModule(module) + return module } diff --git a/build_kzip.bash b/build_kzip.bash index 4c42048dd..850aedaf0 100755 --- a/build_kzip.bash +++ b/build_kzip.bash @@ -40,6 +40,7 @@ kzip_targets=( merge_zips xref_cxx xref_java + xref_kotlin # TODO: b/286390153 - reenable rust # xref_rust ) diff --git a/cc/Android.bp b/cc/Android.bp index e68e4a398..29526143f 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -16,7 +16,6 @@ bootstrap_go_package { "soong-etc", "soong-fuzz", "soong-genrule", - "soong-multitree", "soong-testing", "soong-tradefed", ], @@ -65,7 +64,6 @@ bootstrap_go_package { "library.go", "library_headers.go", "library_sdk_member.go", - "library_stub.go", "native_bridge_sdk_trait.go", "object.go", "test.go", diff --git a/cc/TEST_MAPPING b/cc/TEST_MAPPING new file mode 100644 index 000000000..be2809de0 --- /dev/null +++ b/cc/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "imports": [ + { + "path": "bionic" + } + ] +} diff --git a/cc/androidmk.go b/cc/androidmk.go index cecaae23a..6966f7692 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -21,7 +21,6 @@ import ( "strings" "android/soong/android" - "android/soong/multitree" ) var ( @@ -479,34 +478,6 @@ func (p *prebuiltBinaryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *a androidMkWritePrebuiltOptions(p.baseLinker, entries) } -func (a *apiLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - entries.Class = "SHARED_LIBRARIES" - entries.SubName += multitree.GetApiImportSuffix() - - entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - a.libraryDecorator.androidMkWriteExportedFlags(entries) - src := *a.properties.Src - path, file := filepath.Split(src) - stem, suffix, ext := android.SplitFileExt(file) - entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext) - entries.SetString("LOCAL_MODULE_SUFFIX", suffix) - entries.SetString("LOCAL_MODULE_STEM", stem) - entries.SetString("LOCAL_MODULE_PATH", path) - entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) - entries.SetString("LOCAL_SOONG_TOC", a.toc().String()) - }) -} - -func (a *apiHeadersDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - entries.Class = "HEADER_LIBRARIES" - entries.SubName += multitree.GetApiImportSuffix() - - entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - a.libraryDecorator.androidMkWriteExportedFlags(entries) - entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) - }) -} - func androidMkWritePrebuiltOptions(linker *baseLinker, entries *android.AndroidMkEntries) { allow := linker.Properties.Allow_undefined_symbols if allow != nil { diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go index 8a7ea8845..4063714ab 100644 --- a/cc/binary_sdk_member.go +++ b/cc/binary_sdk_member.go @@ -132,7 +132,7 @@ func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberCo if ccModule.linker != nil { specifiedDeps := specifiedDeps{} - specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx, ccModule, specifiedDeps) + specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx.SdkModuleContext(), ccModule, specifiedDeps) p.SharedLibs = specifiedDeps.sharedLibs p.SystemSharedLibs = specifiedDeps.systemSharedLibs @@ -34,7 +34,6 @@ import ( "android/soong/cc/config" "android/soong/fuzz" "android/soong/genrule" - "android/soong/multitree" ) func init() { @@ -60,10 +59,10 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { san.registerMutators(ctx) } - ctx.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator).Parallel() + ctx.BottomUp("sanitize_runtime_deps", sanitizerRuntimeDepsMutator).Parallel() ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel() - ctx.TopDown("fuzz_deps", fuzzMutatorDeps) + ctx.BottomUp("fuzz_deps", fuzzMutatorDeps) ctx.Transition("coverage", &coverageTransitionMutator{}) @@ -74,7 +73,7 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.Transition("lto", <oTransitionMutator{}) ctx.BottomUp("check_linktype", checkLinkTypeMutator).Parallel() - ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel() + ctx.BottomUp("double_loadable", checkDoubleLoadableLibraries).Parallel() }) ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { @@ -613,7 +612,7 @@ type linker interface { coverageOutputFilePath() android.OptionalPath // Get the deps that have been explicitly specified in the properties. - linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps + linkerSpecifiedDeps(ctx android.ConfigurableEvaluatorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) } @@ -970,7 +969,7 @@ func (c *Module) HiddenFromMake() bool { return c.Properties.HideFromMake } -func (c *Module) RequiredModuleNames(ctx android.ConfigAndErrorContext) []string { +func (c *Module) RequiredModuleNames(ctx android.ConfigurableEvaluatorContext) []string { required := android.CopyOf(c.ModuleBase.RequiredModuleNames(ctx)) if c.ImageVariation().Variation == android.CoreVariation { required = append(required, c.Properties.Target.Platform.Required...) @@ -2361,24 +2360,6 @@ func AddSharedLibDependenciesWithVersions(ctx android.BottomUpMutatorContext, mo } } -func GetApiImports(c LinkableInterface, actx android.BottomUpMutatorContext) multitree.ApiImportInfo { - apiImportInfo := multitree.ApiImportInfo{} - - if c.Device() { - var apiImportModule []blueprint.Module - if actx.OtherModuleExists("api_imports") { - apiImportModule = actx.AddDependency(c, nil, "api_imports") - if len(apiImportModule) > 0 && apiImportModule[0] != nil { - apiInfo, _ := android.OtherModuleProvider(actx, apiImportModule[0], multitree.ApiImportsProvider) - apiImportInfo = apiInfo - android.SetProvider(actx, multitree.ApiImportsProvider, apiInfo) - } - } - } - - return apiImportInfo -} - func GetReplaceModuleName(lib string, replaceMap map[string]string) string { if snapshot, ok := replaceMap[lib]; ok { return snapshot @@ -2448,11 +2429,6 @@ func (c *Module) shouldUseApiSurface() bool { // NDK Variant return true } - - if c.isImportedApiLibrary() { - // API Library should depend on API headers - return true - } } return false @@ -2472,19 +2448,10 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { ctx.ctx = ctx deps := c.deps(ctx) - apiImportInfo := GetApiImports(c, actx) apiNdkLibs := []string{} apiLateNdkLibs := []string{} - if c.shouldUseApiSurface() { - deps.SharedLibs, apiNdkLibs = rewriteLibsForApiImports(c, deps.SharedLibs, apiImportInfo.SharedLibs, ctx.Config()) - deps.LateSharedLibs, apiLateNdkLibs = rewriteLibsForApiImports(c, deps.LateSharedLibs, apiImportInfo.SharedLibs, ctx.Config()) - deps.SystemSharedLibs, _ = rewriteLibsForApiImports(c, deps.SystemSharedLibs, apiImportInfo.SharedLibs, ctx.Config()) - deps.ReexportHeaderLibHeaders, _ = rewriteLibsForApiImports(c, deps.ReexportHeaderLibHeaders, apiImportInfo.SharedLibs, ctx.Config()) - deps.ReexportSharedLibHeaders, _ = rewriteLibsForApiImports(c, deps.ReexportSharedLibHeaders, apiImportInfo.SharedLibs, ctx.Config()) - } - c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs variantNdkLibs := []string{} @@ -2501,11 +2468,6 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { depTag.reexportFlags = true } - // Check header lib replacement from API surface first, and then check again with VSDK - if c.shouldUseApiSurface() { - lib = GetReplaceModuleName(lib, apiImportInfo.HeaderLibs) - } - if c.isNDKStubLibrary() { variationExists := actx.OtherModuleDependencyVariantExists(nil, lib) if variationExists { @@ -2515,7 +2477,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { // any variants. actx.AddFarVariationDependencies([]blueprint.Variation{}, depTag, lib) } - } else if c.IsStubs() && !c.isImportedApiLibrary() { + } else if c.IsStubs() { actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()), depTag, lib) } else { @@ -2591,22 +2553,12 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { } name, version := StubsLibNameAndVersion(lib) - if apiLibraryName, ok := apiImportInfo.SharedLibs[name]; ok && !ctx.OtherModuleExists(name) { - name = apiLibraryName - } sharedLibNames = append(sharedLibNames, name) variations := []blueprint.Variation{ {Mutator: "link", Variation: "shared"}, } - - if _, ok := apiImportInfo.ApexSharedLibs[name]; !ok || ctx.OtherModuleExists(name) { - AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, name, version, false) - } - - if apiLibraryName, ok := apiImportInfo.ApexSharedLibs[name]; ok { - AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, apiLibraryName, version, false) - } + AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, name, version, false) } for _, lib := range deps.LateStaticLibs { @@ -2701,7 +2653,6 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { ) } - updateImportedLibraryDependency(ctx) } func BeginMutator(ctx android.BottomUpMutatorContext) { @@ -2730,10 +2681,6 @@ func checkLinkType(ctx android.BaseModuleContext, from LinkableInterface, to Lin return } - // TODO(b/244244438) : Remove this once all variants are implemented - if ccFrom, ok := from.(*Module); ok && ccFrom.isImportedApiLibrary() { - return - } if from.SdkVersion() == "" { // Platform code can link to anything return @@ -2756,10 +2703,6 @@ func checkLinkType(ctx android.BaseModuleContext, from LinkableInterface, to Lin // the NDK. return } - if c.isImportedApiLibrary() { - // Imported library from the API surface is a stub library built against interface definition. - return - } } if strings.HasPrefix(ctx.ModuleName(), "libclang_rt.") && to.Module().Name() == "libc++" { @@ -2840,7 +2783,7 @@ func checkLinkTypeMutator(ctx android.BottomUpMutatorContext) { // If a library has a vendor variant and is a (transitive) dependency of an LLNDK library, // it is subject to be double loaded. Such lib should be explicitly marked as double_loadable: true // or as vndk-sp (vndk: { enabled: true, support_system_process: true}). -func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) { +func checkDoubleLoadableLibraries(ctx android.BottomUpMutatorContext) { check := func(child, parent android.Module) bool { to, ok := child.(*Module) if !ok { @@ -2935,47 +2878,6 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { skipModuleList := map[string]bool{} - var apiImportInfo multitree.ApiImportInfo - hasApiImportInfo := false - - ctx.VisitDirectDeps(func(dep android.Module) { - if dep.Name() == "api_imports" { - apiImportInfo, _ = android.OtherModuleProvider(ctx, dep, multitree.ApiImportsProvider) - hasApiImportInfo = true - } - }) - - if hasApiImportInfo { - targetStubModuleList := map[string]string{} - targetOrigModuleList := map[string]string{} - - // Search for dependency which both original module and API imported library with APEX stub exists - ctx.VisitDirectDeps(func(dep android.Module) { - depName := ctx.OtherModuleName(dep) - if apiLibrary, ok := apiImportInfo.ApexSharedLibs[depName]; ok { - targetStubModuleList[apiLibrary] = depName - } - }) - ctx.VisitDirectDeps(func(dep android.Module) { - depName := ctx.OtherModuleName(dep) - if origLibrary, ok := targetStubModuleList[depName]; ok { - targetOrigModuleList[origLibrary] = depName - } - }) - - // Decide which library should be used between original and API imported library - ctx.VisitDirectDeps(func(dep android.Module) { - depName := ctx.OtherModuleName(dep) - if apiLibrary, ok := targetOrigModuleList[depName]; ok { - if ShouldUseStubForApex(ctx, dep) { - skipModuleList[depName] = true - } else { - skipModuleList[apiLibrary] = true - } - } - }) - } - ctx.VisitDirectDeps(func(dep android.Module) { depName := ctx.OtherModuleName(dep) depTag := ctx.OtherModuleDependencyTag(dep) @@ -3404,17 +3306,7 @@ func ShouldUseStubForApex(ctx android.ModuleContext, dep android.Module) bool { // bootstrap modules, always link to non-stub variant isNotInPlatform := dep.(android.ApexModule).NotInPlatform() - isApexImportedApiLibrary := false - - if cc, ok := dep.(*Module); ok { - if apiLibrary, ok := cc.linker.(*apiLibraryDecorator); ok { - if apiLibrary.hasApexStubs() { - isApexImportedApiLibrary = true - } - } - } - - useStubs = (isNotInPlatform || isApexImportedApiLibrary) && !bootstrap + useStubs = isNotInPlatform && !bootstrap if useStubs { // Another exception: if this module is a test for an APEX, then @@ -3439,7 +3331,7 @@ func ShouldUseStubForApex(ctx android.ModuleContext, dep android.Module) bool { // only partially overlapping apex_available. For that test_for // modules would need to be split into APEX variants and resolved // separately for each APEX they have access to. - if !isApexImportedApiLibrary && android.AvailableToSameApexes(thisModule, dep.(android.ApexModule)) { + if android.AvailableToSameApexes(thisModule, dep.(android.ApexModule)) { useStubs = false } } @@ -4023,11 +3915,6 @@ func (c *Module) IsSdkVariant() bool { return c.Properties.IsSdkVariant } -func (c *Module) isImportedApiLibrary() bool { - _, ok := c.linker.(*apiLibraryDecorator) - return ok -} - func kytheExtractAllFactory() android.Singleton { return &kytheExtractAllSingleton{} } diff --git a/cc/cc_test.go b/cc/cc_test.go index 93630dbd7..3f3347b51 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -49,17 +49,30 @@ var apexVersion = "28" func registerTestMutators(ctx android.RegistrationContext) { ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("apex", testApexMutator).Parallel() + ctx.Transition("apex", &testApexTransitionMutator{}) }) } -func testApexMutator(mctx android.BottomUpMutatorContext) { - modules := mctx.CreateVariations(apexVariationName) +type testApexTransitionMutator struct{} + +func (t *testApexTransitionMutator) Split(ctx android.BaseModuleContext) []string { + return []string{apexVariationName} +} + +func (t *testApexTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + return sourceVariation +} + +func (t *testApexTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { + return incomingVariation +} + +func (t *testApexTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { apexInfo := android.ApexInfo{ ApexVariationName: apexVariationName, MinSdkVersion: android.ApiLevelForTest(apexVersion), } - mctx.SetVariationProvider(modules[0], android.ApexInfoProvider, apexInfo) + android.SetProvider(ctx, android.ApexInfoProvider, apexInfo) } // testCcWithConfig runs tests using the prepareForCcTest diff --git a/cc/config/global.go b/cc/config/global.go index c83835712..9d3de6d68 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -286,6 +286,8 @@ var ( // New warnings to be fixed after clang-r468909 "-Wno-error=deprecated-builtins", // http://b/241601211 "-Wno-error=deprecated", // in external/googletest/googletest + // Disabling until the warning is fixed in libc++abi header files b/366180429 + "-Wno-deprecated-dynamic-exception-spec", // New warnings to be fixed after clang-r475365 "-Wno-error=enum-constexpr-conversion", // http://b/243964282 // New warnings to be fixed after clang-r522817 diff --git a/cc/fuzz.go b/cc/fuzz.go index d9e221b16..3f21bc6e7 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -57,7 +57,7 @@ func (fuzzer *fuzzer) props() []interface{} { return []interface{}{&fuzzer.Properties} } -func fuzzMutatorDeps(mctx android.TopDownMutatorContext) { +func fuzzMutatorDeps(mctx android.BottomUpMutatorContext) { currentModule, ok := mctx.Module().(*Module) if !ok { return diff --git a/cc/library.go b/cc/library.go index 03f7174c6..3833b9846 100644 --- a/cc/library.go +++ b/cc/library.go @@ -919,7 +919,7 @@ func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { return deps } -func (library *libraryDecorator) linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps { +func (library *libraryDecorator) linkerSpecifiedDeps(ctx android.ConfigurableEvaluatorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps { specifiedDeps = library.baseLinker.linkerSpecifiedDeps(ctx, module, specifiedDeps) var properties StaticOrSharedProperties if library.static() { @@ -2350,9 +2350,8 @@ func (versionTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, varia if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) { isLLNDK := m.IsLlndk() isVendorPublicLibrary := m.IsVendorPublicLibrary() - isImportedApiLibrary := m.isImportedApiLibrary() - if variation != "" || isLLNDK || isVendorPublicLibrary || isImportedApiLibrary { + if variation != "" || isLLNDK || isVendorPublicLibrary { // A stubs or LLNDK stubs variant. if m.sanitize != nil { m.sanitize.Properties.ForceDisable = true diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go index 053c46069..af3658d58 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -543,7 +543,7 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte p.ExportedFlags = exportedInfo.Flags if ccModule.linker != nil { specifiedDeps := specifiedDeps{} - specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx, ccModule, specifiedDeps) + specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx.SdkModuleContext(), ccModule, specifiedDeps) if lib := ccModule.library; lib != nil { if !lib.hasStubsVariants() { diff --git a/cc/library_stub.go b/cc/library_stub.go deleted file mode 100644 index 636782581..000000000 --- a/cc/library_stub.go +++ /dev/null @@ -1,512 +0,0 @@ -// Copyright 2021 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 cc - -import ( - "regexp" - "strings" - - "android/soong/android" - "android/soong/multitree" - - "github.com/google/blueprint/proptools" -) - -var ( - ndkVariantRegex = regexp.MustCompile("ndk\\.([a-zA-Z0-9]+)") - stubVariantRegex = regexp.MustCompile("apex\\.([a-zA-Z0-9]+)") -) - -func init() { - RegisterLibraryStubBuildComponents(android.InitRegistrationContext) -} - -func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) { - ctx.RegisterModuleType("cc_api_library", CcApiLibraryFactory) - ctx.RegisterModuleType("cc_api_headers", CcApiHeadersFactory) - ctx.RegisterModuleType("cc_api_variant", CcApiVariantFactory) -} - -func updateImportedLibraryDependency(ctx android.BottomUpMutatorContext) { - m, ok := ctx.Module().(*Module) - if !ok { - return - } - - apiLibrary, ok := m.linker.(*apiLibraryDecorator) - if !ok { - return - } - - if m.InVendorOrProduct() && apiLibrary.hasLLNDKStubs() { - // Add LLNDK variant dependency - if inList("llndk", apiLibrary.properties.Variants) { - variantName := BuildApiVariantName(m.BaseModuleName(), "llndk", "") - ctx.AddDependency(m, nil, variantName) - } - } else if m.IsSdkVariant() { - // Add NDK variant dependencies - targetVariant := "ndk." + m.StubsVersion() - if inList(targetVariant, apiLibrary.properties.Variants) { - variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "") - ctx.AddDependency(m, nil, variantName) - } - } else if m.IsStubs() { - targetVariant := "apex." + m.StubsVersion() - if inList(targetVariant, apiLibrary.properties.Variants) { - variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "") - ctx.AddDependency(m, nil, variantName) - } - } -} - -// 'cc_api_library' is a module type which is from the exported API surface -// with C shared library type. The module will replace original module, and -// offer a link to the module that generates shared library object from the -// map file. -type apiLibraryProperties struct { - Src *string `android:"arch_variant"` - Variants []string -} - -type apiLibraryDecorator struct { - *libraryDecorator - properties apiLibraryProperties -} - -func CcApiLibraryFactory() android.Module { - module, decorator := NewLibrary(android.DeviceSupported) - apiLibraryDecorator := &apiLibraryDecorator{ - libraryDecorator: decorator, - } - apiLibraryDecorator.BuildOnlyShared() - - module.stl = nil - module.sanitize = nil - decorator.disableStripping() - - module.compiler = nil - module.linker = apiLibraryDecorator - module.installer = nil - module.library = apiLibraryDecorator - module.AddProperties(&module.Properties, &apiLibraryDecorator.properties) - - // Prevent default system libs (libc, libm, and libdl) from being linked - if apiLibraryDecorator.baseLinker.Properties.System_shared_libs == nil { - apiLibraryDecorator.baseLinker.Properties.System_shared_libs = []string{} - } - - apiLibraryDecorator.baseLinker.Properties.No_libcrt = BoolPtr(true) - apiLibraryDecorator.baseLinker.Properties.Nocrt = BoolPtr(true) - - module.Init() - - return module -} - -func (d *apiLibraryDecorator) Name(basename string) string { - return basename + multitree.GetApiImportSuffix() -} - -// Export include dirs without checking for existence. -// The directories are not guaranteed to exist during Soong analysis. -func (d *apiLibraryDecorator) exportIncludes(ctx ModuleContext) { - exporterProps := d.flagExporter.Properties - for _, dir := range exporterProps.Export_include_dirs.GetOrDefault(ctx, nil) { - d.dirs = append(d.dirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir)) - } - // system headers - for _, dir := range exporterProps.Export_system_include_dirs { - d.systemDirs = append(d.systemDirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir)) - } -} - -func (d *apiLibraryDecorator) linkerInit(ctx BaseModuleContext) { - d.baseLinker.linkerInit(ctx) - - if d.hasNDKStubs() { - // Set SDK version of module as current - ctx.Module().(*Module).Properties.Sdk_version = StringPtr("current") - - // Add NDK stub as NDK known libs - name := ctx.ModuleName() - - ndkKnownLibsLock.Lock() - ndkKnownLibs := getNDKKnownLibs(ctx.Config()) - if !inList(name, *ndkKnownLibs) { - *ndkKnownLibs = append(*ndkKnownLibs, name) - } - ndkKnownLibsLock.Unlock() - } -} - -func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path { - m, _ := ctx.Module().(*Module) - - var in android.Path - - // src might not exist during the beginning of soong analysis in Multi-tree - if src := String(d.properties.Src); src != "" { - in = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), src) - } - - libName := m.BaseModuleName() + multitree.GetApiImportSuffix() - - load_cc_variant := func(apiVariantModule string) { - var mod android.Module - - ctx.VisitDirectDeps(func(depMod android.Module) { - if depMod.Name() == apiVariantModule { - mod = depMod - libName = apiVariantModule - } - }) - - if mod != nil { - variantMod, ok := mod.(*CcApiVariant) - if ok { - in = variantMod.Src() - - // Copy LLDNK properties to cc_api_library module - exportIncludeDirs := append(d.libraryDecorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil), - variantMod.exportProperties.Export_include_dirs...) - d.libraryDecorator.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string]( - nil, - []proptools.ConfigurableCase[[]string]{ - proptools.NewConfigurableCase[[]string](nil, &exportIncludeDirs), - }, - ) - - // Export headers as system include dirs if specified. Mostly for libc - if Bool(variantMod.exportProperties.Export_headers_as_system) { - d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append( - d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs, - d.libraryDecorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil)...) - d.libraryDecorator.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string](nil, nil) - } - } - } - } - - if m.InVendorOrProduct() && d.hasLLNDKStubs() { - // LLNDK variant - load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "llndk", "")) - } else if m.IsSdkVariant() { - // NDK Variant - load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "ndk", m.StubsVersion())) - } else if m.IsStubs() { - // APEX Variant - load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "apex", m.StubsVersion())) - } - - // Flags reexported from dependencies. (e.g. vndk_prebuilt_shared) - d.exportIncludes(ctx) - d.libraryDecorator.reexportDirs(deps.ReexportedDirs...) - d.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...) - d.libraryDecorator.reexportFlags(deps.ReexportedFlags...) - d.libraryDecorator.reexportDeps(deps.ReexportedDeps...) - d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...) - - if in == nil { - ctx.PropertyErrorf("src", "Unable to locate source property") - return nil - } - - // Make the _compilation_ of rdeps have an order-only dep on cc_api_library.src (an .so file) - // The .so file itself has an order-only dependency on the headers contributed by this library. - // Creating this dependency ensures that the headers are assembled before compilation of rdeps begins. - d.libraryDecorator.reexportDeps(in) - d.libraryDecorator.flagExporter.setProvider(ctx) - - d.unstrippedOutputFile = in - libName += flags.Toolchain.ShlibSuffix() - - tocFile := android.PathForModuleOut(ctx, libName+".toc") - d.tocFile = android.OptionalPathForPath(tocFile) - TransformSharedObjectToToc(ctx, in, tocFile) - - outputFile := android.PathForModuleOut(ctx, libName) - - // TODO(b/270485584) This copies with a new name, just to avoid conflict with prebuilts. - // We can just use original input if there is any way to avoid name conflict without copy. - ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, - Description: "API surface imported library", - Input: in, - Output: outputFile, - Args: map[string]string{ - "cpFlags": "-L", - }, - }) - - android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{ - SharedLibrary: outputFile, - Target: ctx.Target(), - - TableOfContents: d.tocFile, - }) - - d.shareStubs(ctx) - - return outputFile -} - -// Share additional information about stub libraries with provider -func (d *apiLibraryDecorator) shareStubs(ctx ModuleContext) { - stubs := ctx.GetDirectDepsWithTag(stubImplDepTag) - if len(stubs) > 0 { - var stubsInfo []SharedStubLibrary - for _, stub := range stubs { - stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider) - flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider) - stubsInfo = append(stubsInfo, SharedStubLibrary{ - Version: moduleLibraryInterface(stub).stubsVersion(), - SharedLibraryInfo: stubInfo, - FlagExporterInfo: flagInfo, - }) - } - android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{ - SharedStubLibraries: stubsInfo, - - IsLLNDK: ctx.IsLlndk(), - }) - } -} - -func (d *apiLibraryDecorator) availableFor(what string) bool { - // Stub from API surface should be available for any APEX. - return true -} - -func (d *apiLibraryDecorator) hasApexStubs() bool { - for _, variant := range d.properties.Variants { - if strings.HasPrefix(variant, "apex") { - return true - } - } - return false -} - -func (d *apiLibraryDecorator) hasStubsVariants() bool { - return d.hasApexStubs() -} - -func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseModuleContext) []string { - m, ok := ctx.Module().(*Module) - - if !ok { - return nil - } - - // TODO(b/244244438) Create more version information for NDK and APEX variations - // NDK variants - if m.IsSdkVariant() { - // TODO(b/249193999) Do not check if module has NDK stubs once all NDK cc_api_library contains ndk variant of cc_api_variant. - if d.hasNDKStubs() { - return d.getNdkVersions() - } - } - - if d.hasLLNDKStubs() && m.InVendorOrProduct() { - // LLNDK libraries only need a single stubs variant. - return []string{android.FutureApiLevel.String()} - } - - stubsVersions := d.getStubVersions() - - if len(stubsVersions) != 0 { - return stubsVersions - } - - if m.MinSdkVersion() == "" { - return nil - } - - firstVersion, err := nativeApiLevelFromUser(ctx, - m.MinSdkVersion()) - - if err != nil { - return nil - } - - return ndkLibraryVersions(ctx, firstVersion) -} - -func (d *apiLibraryDecorator) hasLLNDKStubs() bool { - return inList("llndk", d.properties.Variants) -} - -func (d *apiLibraryDecorator) hasNDKStubs() bool { - for _, variant := range d.properties.Variants { - if ndkVariantRegex.MatchString(variant) { - return true - } - } - return false -} - -func (d *apiLibraryDecorator) getNdkVersions() []string { - ndkVersions := []string{} - - for _, variant := range d.properties.Variants { - if match := ndkVariantRegex.FindStringSubmatch(variant); len(match) == 2 { - ndkVersions = append(ndkVersions, match[1]) - } - } - - return ndkVersions -} - -func (d *apiLibraryDecorator) getStubVersions() []string { - stubVersions := []string{} - - for _, variant := range d.properties.Variants { - if match := stubVariantRegex.FindStringSubmatch(variant); len(match) == 2 { - stubVersions = append(stubVersions, match[1]) - } - } - - return stubVersions -} - -// 'cc_api_headers' is similar with 'cc_api_library', but which replaces -// header libraries. The module will replace any dependencies to existing -// original header libraries. -type apiHeadersDecorator struct { - *libraryDecorator -} - -func CcApiHeadersFactory() android.Module { - module, decorator := NewLibrary(android.DeviceSupported) - apiHeadersDecorator := &apiHeadersDecorator{ - libraryDecorator: decorator, - } - apiHeadersDecorator.HeaderOnly() - - module.stl = nil - module.sanitize = nil - decorator.disableStripping() - - module.compiler = nil - module.linker = apiHeadersDecorator - module.installer = nil - - // Prevent default system libs (libc, libm, and libdl) from being linked - if apiHeadersDecorator.baseLinker.Properties.System_shared_libs == nil { - apiHeadersDecorator.baseLinker.Properties.System_shared_libs = []string{} - } - - apiHeadersDecorator.baseLinker.Properties.No_libcrt = BoolPtr(true) - apiHeadersDecorator.baseLinker.Properties.Nocrt = BoolPtr(true) - - module.Init() - - return module -} - -func (d *apiHeadersDecorator) Name(basename string) string { - return basename + multitree.GetApiImportSuffix() -} - -func (d *apiHeadersDecorator) availableFor(what string) bool { - // Stub from API surface should be available for any APEX. - return true -} - -type ccApiexportProperties struct { - Src *string `android:"arch_variant"` - Variant *string - Version *string -} - -type variantExporterProperties struct { - // Header directory to export - Export_include_dirs []string `android:"arch_variant"` - - // Export all headers as system include - Export_headers_as_system *bool -} - -type CcApiVariant struct { - android.ModuleBase - - properties ccApiexportProperties - exportProperties variantExporterProperties - - src android.Path -} - -var _ android.Module = (*CcApiVariant)(nil) -var _ android.ImageInterface = (*CcApiVariant)(nil) - -func CcApiVariantFactory() android.Module { - module := &CcApiVariant{} - - module.AddProperties(&module.properties) - module.AddProperties(&module.exportProperties) - - android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth) - return module -} - -func (v *CcApiVariant) GenerateAndroidBuildActions(ctx android.ModuleContext) { - // No need to build - - if String(v.properties.Src) == "" { - ctx.PropertyErrorf("src", "src is a required property") - } - - // Skip the existence check of the stub prebuilt file. - // The file is not guaranteed to exist during Soong analysis. - // Build orchestrator will be responsible for creating a connected ninja graph. - v.src = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), String(v.properties.Src)) -} - -func (v *CcApiVariant) Name() string { - version := String(v.properties.Version) - return BuildApiVariantName(v.BaseModuleName(), *v.properties.Variant, version) -} - -func (v *CcApiVariant) Src() android.Path { - return v.src -} - -func BuildApiVariantName(baseName string, variant string, version string) string { - names := []string{baseName, variant} - if version != "" { - names = append(names, version) - } - - return strings.Join(names[:], ".") + multitree.GetApiImportSuffix() -} - -// Implement ImageInterface to generate image variants -func (v *CcApiVariant) ImageMutatorBegin(ctx android.BaseModuleContext) {} -func (v *CcApiVariant) VendorVariantNeeded(ctx android.BaseModuleContext) bool { - return String(v.properties.Variant) == "llndk" -} -func (v *CcApiVariant) ProductVariantNeeded(ctx android.BaseModuleContext) bool { - return String(v.properties.Variant) == "llndk" -} -func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool { - return inList(String(v.properties.Variant), []string{"ndk", "apex"}) -} -func (v *CcApiVariant) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false } -func (v *CcApiVariant) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false } -func (v *CcApiVariant) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false } -func (v *CcApiVariant) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { return false } -func (v *CcApiVariant) ExtraImageVariations(ctx android.BaseModuleContext) []string { return nil } -func (v *CcApiVariant) SetImageVariation(ctx android.BaseModuleContext, variation string) { -} diff --git a/cc/linker.go b/cc/linker.go index 00568177f..1efacade8 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -645,7 +645,7 @@ func (linker *baseLinker) link(ctx ModuleContext, panic(fmt.Errorf("baseLinker doesn't know how to link")) } -func (linker *baseLinker) linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps { +func (linker *baseLinker) linkerSpecifiedDeps(ctx android.ConfigurableEvaluatorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps { eval := module.ConfigurableEvaluator(ctx) specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, linker.Properties.Shared_libs.GetOrDefault(eval, nil)...) diff --git a/cc/ndk_abi.go b/cc/ndk_abi.go index 8202cc05a..2706261a8 100644 --- a/cc/ndk_abi.go +++ b/cc/ndk_abi.go @@ -46,7 +46,7 @@ func (n *ndkAbiDumpSingleton) GenerateBuildActions(ctx android.SingletonContext) if m, ok := module.(*Module); ok { if installer, ok := m.installer.(*stubDecorator); ok { - if canDumpAbi(ctx.Config(), ctx.ModuleDir(module)) { + if installer.hasAbiDump { depPaths = append(depPaths, installer.abiDumpPath) } } diff --git a/cc/ndk_library.go b/cc/ndk_library.go index bd6dfa301..94e0452dd 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -125,6 +125,7 @@ type stubDecorator struct { parsedCoverageXmlPath android.ModuleOutPath installPath android.Path abiDumpPath android.OutputPath + hasAbiDump bool abiDiffPaths android.Paths apiLevel android.ApiLevel @@ -330,11 +331,11 @@ func (this *stubDecorator) findPrebuiltAbiDump(ctx ModuleContext, } // Feature flag. -func canDumpAbi(config android.Config, moduleDir string) bool { +func (this *stubDecorator) canDumpAbi(ctx ModuleContext) bool { if runtime.GOOS == "darwin" { return false } - if strings.HasPrefix(moduleDir, "bionic/") { + if strings.HasPrefix(ctx.ModuleDir(), "bionic/") { // Bionic has enough uncommon implementation details like ifuncs and asm // code that the ABI tracking here has a ton of false positives. That's // causing pretty extreme friction for development there, so disabling @@ -343,8 +344,14 @@ func canDumpAbi(config android.Config, moduleDir string) bool { // http://b/358653811 return false } + + if this.apiLevel.IsCurrent() { + // "current" (AKA 10000) is not tracked. + return false + } + // http://b/156513478 - return config.ReleaseNdkAbiMonitored() + return ctx.Config().ReleaseNdkAbiMonitored() } // Feature flag to disable diffing against prebuilts. @@ -357,6 +364,7 @@ func (this *stubDecorator) dumpAbi(ctx ModuleContext, symbolList android.Path) { this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx, this.apiLevel.String(), ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.stg") + this.hasAbiDump = true headersList := getNdkABIHeadersFile(ctx) ctx.Build(pctx, android.BuildParams{ Rule: stg, @@ -478,7 +486,7 @@ func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) O nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile, c.apiLevel, "") objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc) c.versionScriptPath = nativeAbiResult.versionScript - if canDumpAbi(ctx.Config(), ctx.ModuleDir()) { + if c.canDumpAbi(ctx) { c.dumpAbi(ctx, nativeAbiResult.symbolList) if canDiffAbi(ctx.Config()) { c.diffAbi(ctx) diff --git a/cc/object.go b/cc/object.go index a4f4c8408..c89520ab7 100644 --- a/cc/object.go +++ b/cc/object.go @@ -203,7 +203,7 @@ func (object *objectLinker) link(ctx ModuleContext, return outputFile } -func (object *objectLinker) linkerSpecifiedDeps(ctx android.ConfigAndErrorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps { +func (object *objectLinker) linkerSpecifiedDeps(ctx android.ConfigurableEvaluatorContext, module *Module, specifiedDeps specifiedDeps) specifiedDeps { eval := module.ConfigurableEvaluator(ctx) specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, object.Properties.Shared_libs.GetOrDefault(eval, nil)...) diff --git a/cc/sanitize.go b/cc/sanitize.go index 7b0652c38..7f52ce1c7 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -176,7 +176,7 @@ func (t SanitizerType) registerMutators(ctx android.RegisterMutatorsContext) { switch t { case cfi, Hwasan, Asan, tsan, Fuzzer, scs, Memtag_stack: sanitizer := &sanitizerSplitMutator{t} - ctx.TopDown(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator) + ctx.BottomUp(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator) ctx.Transition(t.variationName(), sanitizer) case Memtag_heap, Memtag_globals, intOverflow: // do nothing @@ -1153,7 +1153,7 @@ type sanitizerSplitMutator struct { // If an APEX is sanitized or not depends on whether it contains at least one // sanitized module. Transition mutators cannot propagate information up the // dependency graph this way, so we need an auxiliary mutator to do so. -func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.TopDownMutatorContext) { +func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.BottomUpMutatorContext) { if sanitizeable, ok := ctx.Module().(Sanitizeable); ok { enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name()) ctx.VisitDirectDeps(func(dep android.Module) { @@ -1355,7 +1355,7 @@ func (c *Module) IsSanitizerExplicitlyDisabled(t SanitizerType) bool { } // Propagate the ubsan minimal runtime dependency when there are integer overflow sanitized static dependencies. -func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) { +func sanitizerRuntimeDepsMutator(mctx android.BottomUpMutatorContext) { // Change this to PlatformSanitizable when/if non-cc modules support ubsan sanitizers. if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil { if c.sanitize.Properties.ForceDisable { @@ -1437,11 +1437,11 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { //"null", //"shift-base", //"signed-integer-overflow", - // TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on. - // https://llvm.org/PR19302 - // http://reviews.llvm.org/D6974 - // "object-size", ) + + if mctx.Config().ReleaseBuildObjectSizeSanitizer() { + sanitizers = append(sanitizers, "object-size") + } } sanitizers = append(sanitizers, sanProps.Misc_undefined...) } @@ -51,13 +51,6 @@ func (sdkTransitionMutator) Split(ctx android.BaseModuleContext) []string { return []string{""} } } - case *CcApiVariant: - ccApiVariant, _ := ctx.Module().(*CcApiVariant) - if String(ccApiVariant.properties.Variant) == "ndk" { - return []string{"sdk"} - } else { - return []string{""} - } } return []string{""} @@ -84,11 +77,6 @@ func (sdkTransitionMutator) IncomingTransition(ctx android.IncomingTransitionCon return incomingVariation } } - case *CcApiVariant: - ccApiVariant, _ := ctx.Module().(*CcApiVariant) - if String(ccApiVariant.properties.Variant) == "ndk" { - return "sdk" - } } if ctx.IsAddingDependency() { diff --git a/cc/testing.go b/cc/testing.go index 159f86c60..14a6b7a6a 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -20,7 +20,6 @@ import ( "android/soong/android" "android/soong/genrule" - "android/soong/multitree" ) func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { @@ -29,9 +28,6 @@ func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { RegisterBinaryBuildComponents(ctx) RegisterLibraryBuildComponents(ctx) RegisterLibraryHeadersBuildComponents(ctx) - RegisterLibraryStubBuildComponents(ctx) - - multitree.RegisterApiImportsModule(ctx) ctx.RegisterModuleType("prebuilt_build_tool", android.NewPrebuiltBuildTool) ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory) diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 24a44b4da..577c6cc74 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -212,7 +212,14 @@ func writeDepFile(outputFile string, eventHandler *metrics.EventHandler, ninjaDe } // Check if there are changes to the environment file, product variable file and -// soong_build binary, in which case no incremental will be performed. +// soong_build binary, in which case no incremental will be performed. For env +// variables we check the used env file, which will be removed in soong ui if +// there is any changes to the env variables used last time, in which case the +// check below will fail and a full build will be attempted. If any new env +// variables are added in the new run, soong ui won't be able to detect it, the +// used env file check below will pass. But unless there is a soong build code +// change, in which case the soong build binary check will fail, otherwise the +// new env variables shouldn't have any affect. func incrementalValid(config android.Config, configCacheFile string) (*ConfigCache, bool) { var newConfigCache ConfigCache data, err := os.ReadFile(shared.JoinPath(topDir, usedEnvFile)) diff --git a/docs/OWNERS b/docs/OWNERS new file mode 100644 index 000000000..776beca32 --- /dev/null +++ b/docs/OWNERS @@ -0,0 +1 @@ +per-file map_files.md = danalbert@google.com diff --git a/docs/map_files.md b/docs/map_files.md index e1ddefc27..8d6af879f 100644 --- a/docs/map_files.md +++ b/docs/map_files.md @@ -88,12 +88,17 @@ but is useful when developing APIs for an unknown future release. ### introduced -Indicates the version in which an API was first introduced. For example, -`introduced=21` specifies that the API was first added (or first made public) in -API level 21. This tag can be applied to either a version definition or an -individual symbol. If applied to a version, all symbols contained in the version -will have the tag applied. An `introduced` tag on a symbol overrides the value -set for the version, if both are defined. +Indicates the version in which an API was first introduced in the NDK. For +example, `introduced=21` specifies that the API was first added (or first made +public) in API level 21. This tag can be applied to either a version definition +or an individual symbol. If applied to a version, all symbols contained in the +version will have the tag applied. An `introduced` tag on a symbol overrides the +value set for the version, if both are defined. + +The `introduced` tag should only be used with NDK APIs. Other API surface tags +(such as `apex`) will override `introduced`. APIs that are in the NDK should +never use tags like `apex`, and APIs that are not in the NDK should never use +`introduced`. Note: The map file alone does not contain all the information needed to determine which API level an API was added in. The `first_version` property of diff --git a/docs/tidy.md b/docs/tidy.md index ae0ca9360..2e4c9579d 100644 --- a/docs/tidy.md +++ b/docs/tidy.md @@ -38,7 +38,7 @@ For example, in clang-tidy is enabled explicitly and with a different check list: ``` cc_defaults { - name: "bpf_defaults", + name: "bpf_cc_defaults", // snipped tidy: true, tidy_checks: [ @@ -52,7 +52,7 @@ cc_defaults { } ``` That means in normal builds, even without `WITH_TIDY=1`, -the modules that use `bpf_defaults` _should_ run clang-tidy +the modules that use `bpf_cc_defaults` _should_ run clang-tidy over C/C++ source files with the given `tidy_checks`. However since clang-tidy warnings and its runtime cost might diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index a8f97e3b7..035399282 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -136,9 +136,6 @@ type filesystemProperties struct { // Install aconfig_flags.pb file for the modules installed in this partition. Gen_aconfig_flags_pb *bool - // Update the Base_dir of the $PRODUCT_OUT directory with the packaging files. - Update_product_out *bool - Fsverity fsverityProperties } @@ -150,14 +147,14 @@ type filesystemProperties struct { func filesystemFactory() android.Module { module := &filesystem{} module.filterPackagingSpec = module.filterInstallablePackagingSpec - initFilesystemModule(module) + initFilesystemModule(module, module) return module } -func initFilesystemModule(module *filesystem) { - module.AddProperties(&module.properties) - android.InitPackageModule(module) - module.PackagingBase.DepsCollectFirstTargetOnly = true +func initFilesystemModule(module android.DefaultableModule, filesystemModule *filesystem) { + module.AddProperties(&filesystemModule.properties) + android.InitPackageModule(filesystemModule) + filesystemModule.PackagingBase.DepsCollectFirstTargetOnly = true android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) } @@ -335,7 +332,7 @@ func (f *filesystem) copyPackagingSpecs(ctx android.ModuleContext, builder *andr } func (f *filesystem) copyFilesToProductOut(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath) { - if !proptools.Bool(f.properties.Update_product_out) { + if f.Name() != ctx.Config().SoongDefinedSystemImage() { return } installPath := android.PathForModuleInPartitionInstall(ctx, f.partitionName()) diff --git a/filesystem/system_image.go b/filesystem/system_image.go index a8fd36822..63cb627d8 100644 --- a/filesystem/system_image.go +++ b/filesystem/system_image.go @@ -27,7 +27,7 @@ type systemImage struct { type systemImageProperties struct { // Path to the input linker config json file. - Linker_config_src *string + Linker_config_src *string `android:"path"` } // android_system_image is a specialization of android_filesystem for the 'system' partition. @@ -38,7 +38,7 @@ func systemImageFactory() android.Module { module.AddProperties(&module.properties) module.filesystem.buildExtraFiles = module.buildExtraFiles module.filesystem.filterPackagingSpec = module.filterPackagingSpec - initFilesystemModule(&module.filesystem) + initFilesystemModule(module, &module.filesystem) return module } diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go index 3a9a64daa..1d647965a 100644 --- a/filesystem/vbmeta.go +++ b/filesystem/vbmeta.go @@ -213,6 +213,7 @@ func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.InstallFile(v.installDir, v.installFileName(), v.output) ctx.SetOutputFiles([]android.Path{v.output}, "") + android.SetProvider(ctx, android.AndroidMkInfoProvider, v.prepareAndroidMKProviderInfo()) } // Returns the embedded shell command that prints the rollback index @@ -265,20 +266,17 @@ func (v *vbmeta) extractPublicKeys(ctx android.ModuleContext) map[string]android return result } -var _ android.AndroidMkEntriesProvider = (*vbmeta)(nil) - -// Implements android.AndroidMkEntriesProvider -func (v *vbmeta) AndroidMkEntries() []android.AndroidMkEntries { - return []android.AndroidMkEntries{android.AndroidMkEntries{ - Class: "ETC", - OutputFile: android.OptionalPathForPath(v.output), - ExtraEntries: []android.AndroidMkExtraEntriesFunc{ - func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - entries.SetString("LOCAL_MODULE_PATH", v.installDir.String()) - entries.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName()) - }, +func (v *vbmeta) prepareAndroidMKProviderInfo() *android.AndroidMkProviderInfo { + providerData := android.AndroidMkProviderInfo{ + PrimaryInfo: android.AndroidMkInfo{ + Class: "ETC", + OutputFile: android.OptionalPathForPath(v.output), + EntryMap: make(map[string][]string), }, - }} + } + providerData.PrimaryInfo.SetString("LOCAL_MODULE_PATH", v.installDir.String()) + providerData.PrimaryInfo.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName()) + return &providerData } var _ Filesystem = (*vbmeta)(nil) diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go index 306d65e29..a0598376b 100644 --- a/fuzz/fuzz_common.go +++ b/fuzz/fuzz_common.go @@ -449,7 +449,7 @@ func IsValidFrameworkForModule(targetFramework Framework, lang Lang, moduleFrame } } -func IsValid(ctx android.ConfigAndErrorContext, fuzzModule FuzzModule) bool { +func IsValid(ctx android.ConfigurableEvaluatorContext, fuzzModule FuzzModule) bool { // Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of // fuzz targets we're going to package anyway. if !fuzzModule.Enabled(ctx) || fuzzModule.InRamdisk() || fuzzModule.InVendorRamdisk() || fuzzModule.InRecovery() { diff --git a/genrule/genrule.go b/genrule/genrule.go index fd72d3c15..a48038bac 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -25,7 +25,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/proptools" "android/soong/android" @@ -365,11 +364,6 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { tools = append(tools, path.Path()) addLocationLabel(tag.label, toolLocation{android.Paths{path.Path()}}) } - case bootstrap.GoBinaryTool: - // A GoBinaryTool provides the install path to a tool, which will be copied. - p := android.PathForGoBinary(ctx, t) - tools = append(tools, p) - addLocationLabel(tag.label, toolLocation{android.Paths{p}}) default: ctx.ModuleErrorf("%q is not a host tool provider", tool) return diff --git a/golang/Android.bp b/golang/Android.bp new file mode 100644 index 000000000..3eae94fa2 --- /dev/null +++ b/golang/Android.bp @@ -0,0 +1,22 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-golang", + pkgPath: "android/soong/golang", + deps: [ + "blueprint", + "blueprint-pathtools", + "blueprint-bootstrap", + "soong", + "soong-android", + ], + srcs: [ + "golang.go", + ], + testSrcs: [ + "golang_test.go", + ], + pluginFor: ["soong_build"], +} diff --git a/golang/golang.go b/golang/golang.go new file mode 100644 index 000000000..618a0852b --- /dev/null +++ b/golang/golang.go @@ -0,0 +1,136 @@ +// Copyright 2024 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 golang wraps the blueprint blueprint_go_binary and bootstrap_go_binary module types in versions +// that implement android.Module that are used when building in Soong. This simplifies the code in Soong +// so it can always assume modules are an android.Module. +// The original blueprint blueprint_go_binary and bootstrap_go_binary module types are still used during +// bootstrapping, so the Android.bp entries for these module types must be compatible with both the +// original blueprint module types and these wrapped module types. +package golang + +import ( + "android/soong/android" + "github.com/google/blueprint" + "github.com/google/blueprint/bootstrap" +) + +func init() { + // Wrap the blueprint Go module types with Soong ones that interoperate with the rest of the Soong modules. + bootstrap.GoModuleTypesAreWrapped() + RegisterGoModuleTypes(android.InitRegistrationContext) +} + +func RegisterGoModuleTypes(ctx android.RegistrationContext) { + ctx.RegisterModuleType("bootstrap_go_package", goPackageModuleFactory) + ctx.RegisterModuleType("blueprint_go_binary", goBinaryModuleFactory) +} + +// A GoPackage is a module for building Go packages. +type GoPackage struct { + android.ModuleBase + bootstrap.GoPackage +} + +func goPackageModuleFactory() android.Module { + module := &GoPackage{} + module.AddProperties(module.Properties()...) + android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst) + return module +} + +func (g *GoPackage) GenerateBuildActions(ctx blueprint.ModuleContext) { + // The embedded ModuleBase and bootstrap.GoPackage each implement GenerateBuildActions, + // the delegation has to be implemented manually to disambiguate. Call ModuleBase's + // GenerateBuildActions, which will call GenerateAndroidBuildActions, which will call + // bootstrap.GoPackage.GenerateBuildActions. + g.ModuleBase.GenerateBuildActions(ctx) +} + +func (g *GoPackage) GenerateAndroidBuildActions(ctx android.ModuleContext) { + g.GoPackage.GenerateBuildActions(ctx.BlueprintModuleContext()) +} + +// A GoBinary is a module for building executable binaries from Go sources. +type GoBinary struct { + android.ModuleBase + bootstrap.GoBinary + + outputFile android.Path +} + +func goBinaryModuleFactory() android.Module { + module := &GoBinary{} + module.AddProperties(module.Properties()...) + android.InitAndroidArchModule(module, android.HostSupportedNoCross, android.MultilibFirst) + return module +} + +func (g *GoBinary) GenerateBuildActions(ctx blueprint.ModuleContext) { + // The embedded ModuleBase and bootstrap.GoBinary each implement GenerateBuildActions, + // the delegation has to be implemented manually to disambiguate. Call ModuleBase's + // GenerateBuildActions, which will call GenerateAndroidBuildActions, which will call + // bootstrap.GoBinary.GenerateBuildActions. + g.ModuleBase.GenerateBuildActions(ctx) +} + +func (g *GoBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // Install the file in Soong instead of blueprint so that Soong knows about the install rules. + g.GoBinary.SetSkipInstall() + + // Run the build actions from the wrapped blueprint bootstrap module. + g.GoBinary.GenerateBuildActions(ctx.BlueprintModuleContext()) + + // Translate the bootstrap module's string path into a Path + outputFile := android.PathForArbitraryOutput(ctx, android.Rel(ctx, ctx.Config().OutDir(), g.IntermediateFile())).WithoutRel() + g.outputFile = outputFile + + // Don't create install rules for modules used by bootstrap, the install command line will differ from + // what was used during bootstrap, which will cause ninja to rebuild the module on the next run, + // triggering reanalysis. + if !usedByBootstrap(ctx.ModuleName()) { + installPath := ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), outputFile) + + // Modules in an unexported namespace have no install rule, only add modules in the exported namespaces + // to the blueprint_tools phony rules. + if !ctx.Config().KatiEnabled() || g.ExportedToMake() { + ctx.Phony("blueprint_tools", installPath) + } + } + + ctx.SetOutputFiles(android.Paths{outputFile}, "") +} + +func usedByBootstrap(name string) bool { + switch name { + case "loadplugins", "soong_build": + return true + default: + return false + } +} + +func (g *GoBinary) HostToolPath() android.OptionalPath { + return android.OptionalPathForPath(g.outputFile) +} + +func (g *GoBinary) AndroidMkEntries() []android.AndroidMkEntries { + return []android.AndroidMkEntries{ + { + Class: "EXECUTABLES", + OutputFile: android.OptionalPathForPath(g.outputFile), + Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk", + }, + } +} diff --git a/golang/golang_test.go b/golang/golang_test.go new file mode 100644 index 000000000..b51214402 --- /dev/null +++ b/golang/golang_test.go @@ -0,0 +1,51 @@ +// Copyright 2024 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 golang + +import ( + "android/soong/android" + "github.com/google/blueprint/bootstrap" + "path/filepath" + "testing" +) + +func TestGolang(t *testing.T) { + bp := ` + bootstrap_go_package { + name: "gopkg", + pkgPath: "test/pkg", + } + + blueprint_go_binary { + name: "gobin", + deps: ["gopkg"], + } + ` + + result := android.GroupFixturePreparers( + android.PrepareForTestWithArchMutator, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + RegisterGoModuleTypes(ctx) + ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUpBlueprint("bootstrap_deps", bootstrap.BootstrapDeps) + }) + }), + ).RunTestWithBp(t, bp) + + bin := result.ModuleForTests("gobin", result.Config.BuildOSTarget.String()) + + expected := filepath.Join("out/soong/host", result.Config.PrebuiltOS(), "bin/go/gobin/obj/gobin") + android.AssertPathsRelativeToTopEquals(t, "output files", []string{expected}, bin.OutputFiles(result.TestContext, t, "")) +} diff --git a/java/base.go b/java/base.go index ef299b279..ff7e06837 100644 --- a/java/base.go +++ b/java/base.go @@ -535,7 +535,8 @@ type Module struct { linter // list of the xref extraction files - kytheFiles android.Paths + kytheFiles android.Paths + kytheKotlinFiles android.Paths hideApexVariantFromMake bool @@ -1370,7 +1371,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName) kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName) - kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags) + j.kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags) if ctx.Failed() { return } diff --git a/java/boot_jars.go b/java/boot_jars.go index 6223dede8..3c3bd550c 100644 --- a/java/boot_jars.go +++ b/java/boot_jars.go @@ -21,7 +21,7 @@ import ( // isActiveModule returns true if the given module should be considered for boot // jars, i.e. if it's enabled and the preferred one in case of source and // prebuilt alternatives. -func isActiveModule(ctx android.ConfigAndErrorContext, module android.Module) bool { +func isActiveModule(ctx android.ConfigurableEvaluatorContext, module android.Module) bool { if !module.Enabled(ctx) { return false } diff --git a/java/config/config.go b/java/config/config.go index c28e07032..4c1c72393 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -145,6 +145,7 @@ func init() { pctx.SourcePathVariable("JmodCmd", "${JavaToolchain}/jmod") pctx.SourcePathVariable("JrtFsJar", "${JavaHome}/lib/jrt-fs.jar") pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar") + pctx.SourcePathVariable("KotlinKytheExtractor", "prebuilts/build-tools/${hostPrebuiltTag}/bin/kotlinc_extractor") pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime") pctx.SourcePathVariable("ResourceProcessorBusyBox", "prebuilts/bazel/common/android_tools/android_tools/all_android_tools_deploy.jar") diff --git a/java/config/kotlin.go b/java/config/kotlin.go index e5e187cad..302d021db 100644 --- a/java/config/kotlin.go +++ b/java/config/kotlin.go @@ -50,4 +50,11 @@ func init() { }, " ")) pctx.StaticVariable("KotlincGlobalFlags", strings.Join([]string{}, " ")) + // Use KotlincKytheGlobalFlags to prevent kotlinc version skew issues between android and + // g3 kythe indexers. + // This is necessary because there might be instances of kotlin code in android + // platform that are not fully compatible with the kotlinc used in g3 kythe indexers. + // e.g. uninitialized variables are a warning in 1.*, but an error in 2.* + // https://github.com/JetBrains/kotlin/blob/master/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt#L748 + pctx.StaticVariable("KotlincKytheGlobalFlags", strings.Join([]string{"-language-version 1.9"}, " ")) } diff --git a/java/dex.go b/java/dex.go index 7d42efc9c..e0e642c63 100644 --- a/java/dex.go +++ b/java/dex.go @@ -120,7 +120,7 @@ func (d *DexProperties) resourceShrinkingEnabled(ctx android.ModuleContext) bool } func (d *DexProperties) optimizedResourceShrinkingEnabled(ctx android.ModuleContext) bool { - return d.resourceShrinkingEnabled(ctx) && Bool(d.Optimize.Optimized_shrink_resources) + return d.resourceShrinkingEnabled(ctx) && BoolDefault(d.Optimize.Optimized_shrink_resources, ctx.Config().UseOptimizedResourceShrinkingByDefault()) } func (d *dexer) optimizeOrObfuscateEnabled() bool { @@ -245,6 +245,16 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, if err != nil { ctx.PropertyErrorf("min_sdk_version", "%s", err) } + if !Bool(d.dexProperties.No_dex_container) && effectiveVersion.FinalOrFutureInt() >= 36 { + // W is 36, but we have not bumped the SDK version yet, so check for both. + if ctx.Config().PlatformSdkVersion().FinalInt() >= 36 || + ctx.Config().PlatformSdkCodename() == "Wear" { + // TODO(b/329465418): Skip this module since it causes issue with app DRM + if ctx.ModuleName() != "framework-minus-apex" { + flags = append([]string{"-JDcom.android.tools.r8.dexContainerExperiment"}, flags...) + } + } + } // If the specified SDK level is 10000, then configure the compiler to use the // current platform SDK level and to compile the build as a platform build. @@ -390,7 +400,7 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams) r8Flags = append(r8Flags, "--resource-input", d.resourcesInput.Path().String()) r8Deps = append(r8Deps, d.resourcesInput.Path()) r8Flags = append(r8Flags, "--resource-output", d.resourcesOutput.Path().String()) - if Bool(opt.Optimized_shrink_resources) { + if d.dexProperties.optimizedResourceShrinkingEnabled(ctx) { r8Flags = append(r8Flags, "--optimized-resource-shrinking") } } diff --git a/java/java.go b/java/java.go index 95f4fd892..d63bbe6e1 100644 --- a/java/java.go +++ b/java/java.go @@ -356,12 +356,17 @@ type UsesLibraryDependency interface { // TODO(jungjw): Move this to kythe.go once it's created. type xref interface { XrefJavaFiles() android.Paths + XrefKotlinFiles() android.Paths } func (j *Module) XrefJavaFiles() android.Paths { return j.kytheFiles } +func (j *Module) XrefKotlinFiles() android.Paths { + return j.kytheKotlinFiles +} + func (d dependencyTag) PropagateAconfigValidation() bool { return d.static } @@ -3304,15 +3309,20 @@ type kytheExtractJavaSingleton struct { func (ks *kytheExtractJavaSingleton) GenerateBuildActions(ctx android.SingletonContext) { var xrefTargets android.Paths + var xrefKotlinTargets android.Paths ctx.VisitAllModules(func(module android.Module) { if javaModule, ok := module.(xref); ok { xrefTargets = append(xrefTargets, javaModule.XrefJavaFiles()...) + xrefKotlinTargets = append(xrefKotlinTargets, javaModule.XrefKotlinFiles()...) } }) // TODO(asmundak): perhaps emit a rule to output a warning if there were no xrefTargets if len(xrefTargets) > 0 { ctx.Phony("xref_java", xrefTargets...) } + if len(xrefKotlinTargets) > 0 { + ctx.Phony("xref_kotlin", xrefKotlinTargets...) + } } var Bool = proptools.Bool @@ -3335,6 +3345,10 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, if lib, ok := depModule.(SdkLibraryDependency); ok && lib.sharedLibrary() { // A shared SDK library. This should be added as a top-level CLC element. sdkLib = &depName + } else if lib, ok := depModule.(SdkLibraryComponentDependency); ok && lib.OptionalSdkLibraryImplementation() != nil { + if depModule.Name() == proptools.String(lib.OptionalSdkLibraryImplementation())+".impl" { + sdkLib = lib.OptionalSdkLibraryImplementation() + } } else if ulib, ok := depModule.(ProvidesUsesLib); ok { // A non-SDK library disguised as an SDK library by the means of `provides_uses_lib` // property. This should be handled in the same way as a shared SDK library. diff --git a/java/java_test.go b/java/java_test.go index e4e6bca9c..c13db3e30 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -2674,7 +2674,7 @@ func TestDisableFromTextStubForCoverageBuild(t *testing.T) { android.AssertBoolEquals(t, "stub module expected to depend on from-source stub", true, CheckModuleHasDependency(t, result.TestContext, apiScopePublic.stubsLibraryModuleName("foo"), "android_common", - apiScopePublic.sourceStubLibraryModuleName("foo"))) + apiScopePublic.sourceStubsLibraryModuleName("foo"))) android.AssertBoolEquals(t, "stub module expected to not depend on from-text stub", false, CheckModuleHasDependency(t, result.TestContext, diff --git a/java/kotlin.go b/java/kotlin.go index c28bc3f54..f42d16304 100644 --- a/java/kotlin.go +++ b/java/kotlin.go @@ -64,6 +64,28 @@ var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports "kotlincFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "classesDir", "headerClassesDir", "headerJar", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", "name") +var kotlinKytheExtract = pctx.AndroidStaticRule("kotlinKythe", + blueprint.RuleParams{ + Command: `rm -rf "$srcJarDir" && mkdir -p "$srcJarDir" && ` + + `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" -f "*.kt" $srcJars && ` + + `${config.KotlinKytheExtractor} -corpus ${kytheCorpus} --srcs @$out.rsp --srcs @"$srcJarDir/list" $commonSrcFilesList --cp @$classpath -o $out --kotlin_out $outJar ` + + // wrap the additional kotlin args. + // Skip Xbuild file, pass the cp explicitly. + // Skip header jars, those should not have an effect on kythe results. + ` --args '${config.KotlincGlobalFlags} ` + + ` ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` + + ` $kotlincFlags -jvm-target $kotlinJvmTarget ` + + `${config.KotlincKytheGlobalFlags}'`, + CommandDeps: []string{ + "${config.KotlinKytheExtractor}", + "${config.ZipSyncCmd}", + }, + Rspfile: "$out.rsp", + RspfileContent: "$in", + }, + "classpath", "kotlincFlags", "commonSrcFilesList", "kotlinJvmTarget", "outJar", "srcJars", "srcJarDir", +) + func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Paths) android.OptionalPath { if len(commonSrcFiles) > 0 { // The list of common_srcs may be too long to put on the command line, but @@ -81,7 +103,7 @@ func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Path } // kotlinCompile takes .java and .kt sources and srcJars, and compiles the .kt sources into a classes jar in outputFile. -func kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile android.WritablePath, +func (j *Module) kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile android.WritablePath, srcFiles, commonSrcFiles, srcJars android.Paths, flags javaBuilderFlags) { @@ -127,6 +149,31 @@ func kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile andro "name": kotlinName, }, }) + + // Emit kythe xref rule + if (ctx.Config().EmitXrefRules()) && ctx.Module() == ctx.PrimaryModule() { + extractionFile := outputFile.ReplaceExtension(ctx, "kzip") + args := map[string]string{ + "classpath": classpathRspFile.String(), + "kotlincFlags": flags.kotlincFlags, + "kotlinJvmTarget": flags.javaVersion.StringForKotlinc(), + "outJar": outputFile.String(), + "srcJars": strings.Join(srcJars.Strings(), " "), + "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars.xref").String(), + } + if commonSrcsList.Valid() { + args["commonSrcFilesList"] = "--common_srcs @" + commonSrcsList.String() + } + ctx.Build(pctx, android.BuildParams{ + Rule: kotlinKytheExtract, + Description: "kotlinKythe", + Output: extractionFile, + Inputs: srcFiles, + Implicits: deps, + Args: args, + }) + j.kytheKotlinFiles = append(j.kytheKotlinFiles, extractionFile) + } } var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupports{Goma: true}, diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go index 67ed84e1d..5b145c658 100644 --- a/java/platform_compat_config.go +++ b/java/platform_compat_config.go @@ -110,6 +110,7 @@ func (p *platformCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleCon p.installConfigFile = android.PathForModuleInstall(ctx, "etc", "compatconfig", p.configFile.Base()) rule.Build(configFileName, "Extract compat/compat_config.xml and install it") ctx.InstallFile(p.installDirPath, p.configFile.Base(), p.configFile) + ctx.SetOutputFiles(android.Paths{p.configFile}, "") } func (p *platformCompatConfig) AndroidMkEntries() []android.AndroidMkEntries { diff --git a/java/ravenwood.go b/java/ravenwood.go index bb136cf6e..9239bbd6b 100644 --- a/java/ravenwood.go +++ b/java/ravenwood.go @@ -33,8 +33,8 @@ func RegisterRavenwoodBuildComponents(ctx android.RegistrationContext) { var ravenwoodLibContentTag = dependencyTag{name: "ravenwoodlibcontent"} var ravenwoodUtilsTag = dependencyTag{name: "ravenwoodutils"} var ravenwoodRuntimeTag = dependencyTag{name: "ravenwoodruntime"} -var ravenwoodDataTag = dependencyTag{name: "ravenwooddata"} var ravenwoodTestResourceApkTag = dependencyTag{name: "ravenwoodtestresapk"} +var ravenwoodTestInstResourceApkTag = dependencyTag{name: "ravenwoodtest-inst-res-apk"} const ravenwoodUtilsName = "ravenwood-utils" const ravenwoodRuntimeName = "ravenwood-runtime" @@ -57,11 +57,17 @@ type ravenwoodTestProperties struct { Jni_libs []string // Specify another android_app module here to copy it to the test directory, so that - // the ravenwood test can access it. + // the ravenwood test can access it. This APK will be loaded as resources of the test + // target app. // TODO: For now, we simply refer to another android_app module and copy it to the // test directory. Eventually, android_ravenwood_test should support all the resource // related properties and build resources from the `res/` directory. Resource_apk *string + + // Specify another android_app module here to copy it to the test directory, so that + // the ravenwood test can access it. This APK will be loaded as resources of the test + // instrumentation app itself. + Inst_resource_apk *string } type ravenwoodTest struct { @@ -128,6 +134,10 @@ func (r *ravenwoodTest) DepsMutator(ctx android.BottomUpMutatorContext) { if resourceApk := proptools.String(r.ravenwoodTestProperties.Resource_apk); resourceApk != "" { ctx.AddVariationDependencies(nil, ravenwoodTestResourceApkTag, resourceApk) } + + if resourceApk := proptools.String(r.ravenwoodTestProperties.Inst_resource_apk); resourceApk != "" { + ctx.AddVariationDependencies(nil, ravenwoodTestInstResourceApkTag, resourceApk) + } } func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -195,13 +205,16 @@ func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { } resApkInstallPath := installPath.Join(ctx, "ravenwood-res-apks") - if resApk := ctx.GetDirectDepsWithTag(ravenwoodTestResourceApkTag); len(resApk) > 0 { - for _, installFile := range android.OtherModuleProviderOrDefault( - ctx, resApk[0], android.InstallFilesProvider).InstallFiles { - installResApk := ctx.InstallFile(resApkInstallPath, "ravenwood-res.apk", installFile) + + copyResApk := func(tag blueprint.DependencyTag, toFileName string) { + if resApk := ctx.GetDirectDepsWithTag(tag); len(resApk) > 0 { + installFile := android.OutputFileForModule(ctx, resApk[0], "") + installResApk := ctx.InstallFile(resApkInstallPath, toFileName, installFile) installDeps = append(installDeps, installResApk) } } + copyResApk(ravenwoodTestResourceApkTag, "ravenwood-res.apk") + copyResApk(ravenwoodTestInstResourceApkTag, "ravenwood-inst-res.apk") // Install our JAR with all dependencies ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...) @@ -228,7 +241,10 @@ type ravenwoodLibgroupProperties struct { Jni_libs []string // We use this to copy framework-res.apk to the ravenwood runtime directory. - Data []string + Data []string `android:"path,arch_variant"` + + // We use this to copy font files to the ravenwood runtime directory. + Fonts []string `android:"path,arch_variant"` } type ravenwoodLibgroup struct { @@ -267,9 +283,6 @@ func (r *ravenwoodLibgroup) DepsMutator(ctx android.BottomUpMutatorContext) { for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs { ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib) } - for _, data := range r.ravenwoodLibgroupProperties.Data { - ctx.AddVariationDependencies(nil, ravenwoodDataTag, data) - } } func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -309,12 +322,17 @@ func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContex } dataInstallPath := installPath.Join(ctx, "ravenwood-data") - for _, data := range r.ravenwoodLibgroupProperties.Data { - libModule := ctx.GetDirectDepWithTag(data, ravenwoodDataTag) - file := android.OutputFileForModule(ctx, libModule, "") + data := android.PathsForModuleSrc(ctx, r.ravenwoodLibgroupProperties.Data) + for _, file := range data { ctx.InstallFile(dataInstallPath, file.Base(), file) } + fontsInstallPath := installPath.Join(ctx, "fonts") + fonts := android.PathsForModuleSrc(ctx, r.ravenwoodLibgroupProperties.Fonts) + for _, file := range fonts { + ctx.InstallFile(fontsInstallPath, file.Base(), file) + } + // Normal build should perform install steps ctx.Phony(r.BaseModuleName(), android.PathForPhony(ctx, r.BaseModuleName()+"-install")) } diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go index d26db930d..753a118e9 100644 --- a/java/ravenwood_test.go +++ b/java/ravenwood_test.go @@ -19,6 +19,7 @@ import ( "testing" "android/soong/android" + "android/soong/etc" ) var prepareRavenwoodRuntime = android.GroupFixturePreparers( @@ -59,11 +60,19 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( } android_app { name: "app1", - sdk_version: "current", + sdk_version: "current", } android_app { name: "app2", - sdk_version: "current", + sdk_version: "current", + } + android_app { + name: "app3", + sdk_version: "current", + } + prebuilt_font { + name: "Font.ttf", + src: "Font.ttf", } android_ravenwood_libgroup { name: "ravenwood-runtime", @@ -76,7 +85,10 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( "ravenwood-runtime-jni2", ], data: [ - "app1", + ":app1", + ], + fonts: [ + ":Font.ttf" ], } android_ravenwood_libgroup { @@ -97,6 +109,7 @@ func TestRavenwoodRuntime(t *testing.T) { ctx := android.GroupFixturePreparers( PrepareForIntegrationTestWithJava, + etc.PrepareForTestWithPrebuiltEtc, prepareRavenwoodRuntime, ).RunTest(t) @@ -114,6 +127,7 @@ func TestRavenwoodRuntime(t *testing.T) { runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/libred.so") runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni3.so") runtime.Output(installPathPrefix + "/ravenwood-runtime/ravenwood-data/app1.apk") + runtime.Output(installPathPrefix + "/ravenwood-runtime/fonts/Font.ttf") utils := ctx.ModuleForTests("ravenwood-utils", "android_common") utils.Output(installPathPrefix + "/ravenwood-utils/framework-rules.ravenwood.jar") } @@ -125,29 +139,30 @@ func TestRavenwoodTest(t *testing.T) { ctx := android.GroupFixturePreparers( PrepareForIntegrationTestWithJava, + etc.PrepareForTestWithPrebuiltEtc, prepareRavenwoodRuntime, ).RunTestWithBp(t, ` - cc_library_shared { - name: "jni-lib1", - host_supported: true, - srcs: ["jni.cpp"], - } - cc_library_shared { - name: "jni-lib2", - host_supported: true, - srcs: ["jni.cpp"], - stem: "libblue", - shared_libs: [ - "jni-lib3", - ], - } - cc_library_shared { - name: "jni-lib3", - host_supported: true, - srcs: ["jni.cpp"], - stem: "libpink", - } - android_ravenwood_test { + cc_library_shared { + name: "jni-lib1", + host_supported: true, + srcs: ["jni.cpp"], + } + cc_library_shared { + name: "jni-lib2", + host_supported: true, + srcs: ["jni.cpp"], + stem: "libblue", + shared_libs: [ + "jni-lib3", + ], + } + cc_library_shared { + name: "jni-lib3", + host_supported: true, + srcs: ["jni.cpp"], + stem: "libpink", + } + android_ravenwood_test { name: "ravenwood-test", srcs: ["Test.java"], jni_libs: [ @@ -156,6 +171,7 @@ func TestRavenwoodTest(t *testing.T) { "ravenwood-runtime-jni2", ], resource_apk: "app2", + inst_resource_apk: "app3", sdk_version: "test_current", } `) @@ -183,6 +199,7 @@ func TestRavenwoodTest(t *testing.T) { module.Output(installPathPrefix + "/ravenwood-test/lib64/libblue.so") module.Output(installPathPrefix + "/ravenwood-test/lib64/libpink.so") module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-res.apk") + module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-inst-res.apk") // ravenwood-runtime*.so are included in the runtime, so it shouldn't be emitted. for _, o := range module.AllOutputs() { diff --git a/java/sdk_library.go b/java/sdk_library.go index b7aa4e56d..9f0564a9c 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -248,7 +248,7 @@ func (scope *apiScope) apiLibraryModuleName(baseName string) string { return scope.stubsLibraryModuleName(baseName) + ".from-text" } -func (scope *apiScope) sourceStubLibraryModuleName(baseName string) string { +func (scope *apiScope) sourceStubsLibraryModuleName(baseName string) string { return scope.stubsLibraryModuleName(baseName) + ".from-source" } @@ -830,16 +830,6 @@ func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, } type commonToSdkLibraryAndImportProperties struct { - // The naming scheme to use for the components that this module creates. - // - // If not specified then it defaults to "default". - // - // This is a temporary mechanism to simplify conversion from separate modules for each - // component that follow a different naming pattern to the default one. - // - // TODO(b/155480189) - Remove once naming inconsistencies have been resolved. - Naming_scheme *string - // Specifies whether this module can be used as an Android shared library; defaults // to true. // @@ -915,8 +905,6 @@ type commonToSdkLibraryAndImport struct { scopePaths map[*apiScope]*scopePaths - namingScheme sdkLibraryComponentNamingScheme - commonSdkLibraryProperties commonToSdkLibraryAndImportProperties // Paths to commonSdkLibraryProperties.Doctag_files @@ -944,15 +932,6 @@ func (c *commonToSdkLibraryAndImport) initCommon(module commonSdkLibraryAndImpor } func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android.DefaultableHookContext) bool { - schemeProperty := proptools.StringDefault(c.commonSdkLibraryProperties.Naming_scheme, "default") - switch schemeProperty { - case "default": - c.namingScheme = &defaultNamingScheme{} - default: - ctx.PropertyErrorf("naming_scheme", "expected 'default' but was %q", schemeProperty) - return false - } - namePtr := proptools.StringPtr(c.module.RootLibraryName()) c.sdkLibraryComponentProperties.SdkLibraryName = namePtr @@ -995,41 +974,41 @@ func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string { // Name of the java_library module that compiles the stubs source. func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string { baseName := c.module.RootLibraryName() - return c.namingScheme.stubsLibraryModuleName(apiScope, baseName) + return apiScope.stubsLibraryModuleName(baseName) } // Name of the java_library module that compiles the exportable stubs source. func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string { baseName := c.module.RootLibraryName() - return c.namingScheme.exportableStubsLibraryModuleName(apiScope, baseName) + return apiScope.exportableStubsLibraryModuleName(baseName) } // Name of the droidstubs module that generates the stubs source and may also // generate/check the API. func (c *commonToSdkLibraryAndImport) stubsSourceModuleName(apiScope *apiScope) string { baseName := c.module.RootLibraryName() - return c.namingScheme.stubsSourceModuleName(apiScope, baseName) + return apiScope.stubsSourceModuleName(baseName) } // Name of the java_api_library module that generates the from-text stubs source // and compiles to a jar file. func (c *commonToSdkLibraryAndImport) apiLibraryModuleName(apiScope *apiScope) string { baseName := c.module.RootLibraryName() - return c.namingScheme.apiLibraryModuleName(apiScope, baseName) + return apiScope.apiLibraryModuleName(baseName) } // Name of the java_library module that compiles the stubs // generated from source Java files. func (c *commonToSdkLibraryAndImport) sourceStubsLibraryModuleName(apiScope *apiScope) string { baseName := c.module.RootLibraryName() - return c.namingScheme.sourceStubsLibraryModuleName(apiScope, baseName) + return apiScope.sourceStubsLibraryModuleName(baseName) } // Name of the java_library module that compiles the exportable stubs // generated from source Java files. func (c *commonToSdkLibraryAndImport) exportableSourceStubsLibraryModuleName(apiScope *apiScope) string { baseName := c.module.RootLibraryName() - return c.namingScheme.exportableSourceStubsLibraryModuleName(apiScope, baseName) + return apiScope.exportableSourceStubsLibraryModuleName(baseName) } // The component names for different outputs of the java_sdk_library. @@ -1748,6 +1727,7 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) staticLibs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs) props := struct { Name *string + Enabled proptools.Configurable[bool] Visibility []string Libs []string Static_libs proptools.Configurable[[]string] @@ -1755,6 +1735,7 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) Stem *string }{ Name: proptools.StringPtr(module.implLibraryModuleName()), + Enabled: module.EnabledProperty(), Visibility: visibility, Libs: append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...), @@ -1783,6 +1764,7 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) type libraryProperties struct { Name *string + Enabled proptools.Configurable[bool] Visibility []string Srcs []string Installable *bool @@ -1809,6 +1791,7 @@ type libraryProperties struct { func (module *SdkLibrary) stubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties { props := libraryProperties{} + props.Enabled = module.EnabledProperty() props.Visibility = []string{"//visibility:override", "//visibility:private"} // sources are generated from the droiddoc sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) @@ -1859,6 +1842,7 @@ func (module *SdkLibrary) createExportableStubsLibrary(mctx android.DefaultableH func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) { props := struct { Name *string + Enabled proptools.Configurable[bool] Visibility []string Srcs []string Installable *bool @@ -1900,6 +1884,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC // * libs (static_libs/libs) props.Name = proptools.StringPtr(name) + props.Enabled = module.EnabledProperty() props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility) props.Srcs = append(props.Srcs, module.properties.Srcs...) props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...) @@ -2025,6 +2010,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { props := struct { Name *string + Enabled proptools.Configurable[bool] Visibility []string Api_contributions []string Libs proptools.Configurable[[]string] @@ -2037,6 +2023,7 @@ func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, }{} props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope)) + props.Enabled = module.EnabledProperty() props.Visibility = []string{"//visibility:override", "//visibility:private"} apiContributions := []string{} @@ -2087,6 +2074,7 @@ func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope, doDist bool) libraryProperties { props := libraryProperties{} + props.Enabled = module.EnabledProperty() props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility) sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) props.Sdk_version = proptools.StringPtr(sdkVersion) @@ -2179,6 +2167,7 @@ func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) { } props := struct { Name *string + Enabled proptools.Configurable[bool] Lib_name *string Apex_available []string On_bootclasspath_since *string @@ -2189,6 +2178,7 @@ func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) { Uses_libs_dependencies []string }{ Name: proptools.StringPtr(module.xmlPermissionsModuleName()), + Enabled: module.EnabledProperty(), Lib_name: proptools.StringPtr(module.BaseModuleName()), Apex_available: module.ApexProperties.Apex_available, On_bootclasspath_since: module.commonSdkLibraryProperties.On_bootclasspath_since, @@ -2284,11 +2274,6 @@ func (module *SdkLibrary) getApiDir() string { // runtime libs and xml file. If requested, the stubs and docs are created twice // once for public API level and once for system API level func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookContext) { - // If the module has been disabled then don't create any child modules. - if !module.Enabled(mctx) { - return - } - if len(module.properties.Srcs) == 0 { mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs") return @@ -2395,50 +2380,6 @@ func (module *SdkLibrary) defaultsToStubs() bool { return proptools.Bool(module.sdkLibraryProperties.Default_to_stubs) } -// Defines how to name the individual component modules the sdk library creates. -type sdkLibraryComponentNamingScheme interface { - stubsLibraryModuleName(scope *apiScope, baseName string) string - - stubsSourceModuleName(scope *apiScope, baseName string) string - - apiLibraryModuleName(scope *apiScope, baseName string) string - - sourceStubsLibraryModuleName(scope *apiScope, baseName string) string - - exportableStubsLibraryModuleName(scope *apiScope, baseName string) string - - exportableSourceStubsLibraryModuleName(scope *apiScope, baseName string) string -} - -type defaultNamingScheme struct { -} - -func (s *defaultNamingScheme) stubsLibraryModuleName(scope *apiScope, baseName string) string { - return scope.stubsLibraryModuleName(baseName) -} - -func (s *defaultNamingScheme) stubsSourceModuleName(scope *apiScope, baseName string) string { - return scope.stubsSourceModuleName(baseName) -} - -func (s *defaultNamingScheme) apiLibraryModuleName(scope *apiScope, baseName string) string { - return scope.apiLibraryModuleName(baseName) -} - -func (s *defaultNamingScheme) sourceStubsLibraryModuleName(scope *apiScope, baseName string) string { - return scope.sourceStubLibraryModuleName(baseName) -} - -func (s *defaultNamingScheme) exportableStubsLibraryModuleName(scope *apiScope, baseName string) string { - return scope.exportableStubsLibraryModuleName(baseName) -} - -func (s *defaultNamingScheme) exportableSourceStubsLibraryModuleName(scope *apiScope, baseName string) string { - return scope.exportableSourceStubsLibraryModuleName(baseName) -} - -var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil) - func moduleStubLinkType(j *Module) (stub bool, ret sdkLinkType) { kind := android.ToSdkKind(proptools.String(j.properties.Stub_contributing_api)) switch kind { @@ -3510,7 +3451,6 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe } } - s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary()) s.Compile_dex = sdk.dexProperties.Compile_dex s.Doctag_paths = sdk.doctagPaths diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index bb6331506..31fbc5a58 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -422,7 +422,7 @@ func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) { for _, expectation := range expectations { verify("sdklib.impl", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined) - stubName := apiScopePublic.sourceStubLibraryModuleName("sdklib") + stubName := apiScopePublic.sourceStubsLibraryModuleName("sdklib") verify(stubName, expectation.lib, expectation.on_stub_classpath, expectation.in_stub_combined) } } diff --git a/multitree/Android.bp b/multitree/Android.bp deleted file mode 100644 index 78c49627b..000000000 --- a/multitree/Android.bp +++ /dev/null @@ -1,20 +0,0 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -bootstrap_go_package { - name: "soong-multitree", - pkgPath: "android/soong/multitree", - deps: [ - "blueprint", - "soong-android", - ], - srcs: [ - "api_imports.go", - "api_surface.go", - "export.go", - "metadata.go", - "import.go", - ], - pluginFor: ["soong_build"], -} diff --git a/multitree/api_imports.go b/multitree/api_imports.go deleted file mode 100644 index 51b9e07a5..000000000 --- a/multitree/api_imports.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2022 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 multitree - -import ( - "android/soong/android" - "strings" - - "github.com/google/blueprint" -) - -var ( - apiImportNameSuffix = ".apiimport" -) - -func init() { - RegisterApiImportsModule(android.InitRegistrationContext) - android.RegisterMakeVarsProvider(pctx, makeVarsProvider) -} - -func RegisterApiImportsModule(ctx android.RegistrationContext) { - ctx.RegisterModuleType("api_imports", apiImportsFactory) -} - -type ApiImports struct { - android.ModuleBase - properties apiImportsProperties -} - -type apiImportsProperties struct { - Shared_libs []string // List of C shared libraries from API surfaces - Header_libs []string // List of C header libraries from API surfaces - Apex_shared_libs []string // List of C shared libraries with APEX stubs -} - -// 'api_imports' is a module which describes modules available from API surfaces. -// This module is required to get the list of all imported API modules, because -// it is discouraged to loop and fetch all modules from its type information. The -// only module with name 'api_imports' will be used from the build. -func apiImportsFactory() android.Module { - module := &ApiImports{} - module.AddProperties(&module.properties) - android.InitAndroidModule(module) - return module -} - -func (imports *ApiImports) GenerateAndroidBuildActions(ctx android.ModuleContext) { - // ApiImport module does not generate any build actions -} - -type ApiImportInfo struct { - SharedLibs, HeaderLibs, ApexSharedLibs map[string]string -} - -var ApiImportsProvider = blueprint.NewMutatorProvider[ApiImportInfo]("deps") - -// Store module lists into ApiImportInfo and share it over mutator provider. -func (imports *ApiImports) DepsMutator(ctx android.BottomUpMutatorContext) { - generateNameMapWithSuffix := func(names []string) map[string]string { - moduleNameMap := make(map[string]string) - for _, name := range names { - moduleNameMap[name] = name + apiImportNameSuffix - } - - return moduleNameMap - } - - sharedLibs := generateNameMapWithSuffix(imports.properties.Shared_libs) - headerLibs := generateNameMapWithSuffix(imports.properties.Header_libs) - apexSharedLibs := generateNameMapWithSuffix(imports.properties.Apex_shared_libs) - - android.SetProvider(ctx, ApiImportsProvider, ApiImportInfo{ - SharedLibs: sharedLibs, - HeaderLibs: headerLibs, - ApexSharedLibs: apexSharedLibs, - }) -} - -func GetApiImportSuffix() string { - return apiImportNameSuffix -} - -func makeVarsProvider(ctx android.MakeVarsContext) { - ctx.VisitAllModules(func(m android.Module) { - if i, ok := m.(*ApiImports); ok { - ctx.Strict("API_IMPORTED_SHARED_LIBRARIES", strings.Join(i.properties.Shared_libs, " ")) - ctx.Strict("API_IMPORTED_HEADER_LIBRARIES", strings.Join(i.properties.Header_libs, " ")) - } - }) -} diff --git a/multitree/api_surface.go b/multitree/api_surface.go deleted file mode 100644 index 0f605d84a..000000000 --- a/multitree/api_surface.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2021 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 multitree - -import ( - "android/soong/android" - "github.com/google/blueprint" -) - -var ( - pctx = android.NewPackageContext("android/soong/multitree") -) - -func init() { - RegisterApiSurfaceBuildComponents(android.InitRegistrationContext) -} - -var PrepareForTestWithApiSurface = android.FixtureRegisterWithContext(RegisterApiSurfaceBuildComponents) - -func RegisterApiSurfaceBuildComponents(ctx android.RegistrationContext) { - ctx.RegisterModuleType("api_surface", ApiSurfaceFactory) -} - -type ApiSurface struct { - android.ModuleBase - ExportableModuleBase - properties apiSurfaceProperties - - taggedOutputs map[string]android.Paths -} - -type apiSurfaceProperties struct { - Contributions []string -} - -func ApiSurfaceFactory() android.Module { - module := &ApiSurface{} - module.AddProperties(&module.properties) - android.InitAndroidModule(module) - InitExportableModule(module) - return module -} - -func (surface *ApiSurface) DepsMutator(ctx android.BottomUpMutatorContext) { - if surface.properties.Contributions != nil { - ctx.AddVariationDependencies(nil, nil, surface.properties.Contributions...) - } - -} -func (surface *ApiSurface) GenerateAndroidBuildActions(ctx android.ModuleContext) { - contributionFiles := make(map[string]android.Paths) - var allOutputs android.Paths - ctx.WalkDeps(func(child, parent android.Module) bool { - if contribution, ok := child.(ApiContribution); ok { - copied := contribution.CopyFilesWithTag(ctx) - for tag, files := range copied { - contributionFiles[child.Name()+"#"+tag] = files - } - for _, paths := range copied { - allOutputs = append(allOutputs, paths...) - } - return false // no transitive dependencies - } - return false - }) - - // phony target - ctx.Build(pctx, android.BuildParams{ - Rule: blueprint.Phony, - Output: android.PathForPhony(ctx, ctx.ModuleName()), - Inputs: allOutputs, - }) - - surface.taggedOutputs = contributionFiles - - ctx.SetOutputFiles(allOutputs, "") -} - -func (surface *ApiSurface) TaggedOutputs() map[string]android.Paths { - return surface.taggedOutputs -} - -func (surface *ApiSurface) Exportable() bool { - return true -} - -var _ Exportable = (*ApiSurface)(nil) - -type ApiContribution interface { - // copy files necessaryt to construct an API surface - // For C, it will be map.txt and .h files - // For Java, it will be api.txt - CopyFilesWithTag(ctx android.ModuleContext) map[string]android.Paths // output paths - - // Generate Android.bp in out/ to use the exported .txt files - // GenerateBuildFiles(ctx ModuleContext) Paths //output paths -} diff --git a/multitree/export.go b/multitree/export.go deleted file mode 100644 index 8be8f7058..000000000 --- a/multitree/export.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2022 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 multitree - -import ( - "android/soong/android" - - "github.com/google/blueprint/proptools" -) - -type moduleExportProperty struct { - // True if the module is exported to the other components in a multi-tree. - // Any components in the multi-tree can import this module to use. - Export *bool -} - -type ExportableModuleBase struct { - properties moduleExportProperty -} - -type Exportable interface { - // Properties for the exporable module. - exportableModuleProps() *moduleExportProperty - - // Check if this module can be exported. - // If this returns false, the module will not be exported regardless of the 'export' value. - Exportable() bool - - // Returns 'true' if this module has 'export: true' - // This module will not be exported if it returns 'false' to 'Exportable()' interface even if - // it has 'export: true'. - IsExported() bool - - // Map from tags to outputs. - // Each module can tag their outputs for convenience. - TaggedOutputs() map[string]android.Paths -} - -type ExportableModule interface { - android.Module - Exportable -} - -func InitExportableModule(module ExportableModule) { - module.AddProperties(module.exportableModuleProps()) -} - -func (m *ExportableModuleBase) exportableModuleProps() *moduleExportProperty { - return &m.properties -} - -func (m *ExportableModuleBase) IsExported() bool { - return proptools.Bool(m.properties.Export) -} diff --git a/multitree/import.go b/multitree/import.go deleted file mode 100644 index 1e5c421bc..000000000 --- a/multitree/import.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2022 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 multitree - -import ( - "android/soong/android" -) - -var ( - nameSuffix = ".imported" -) - -type MultitreeImportedModuleInterface interface { - GetMultitreeImportedModuleName() string -} - -func init() { - android.RegisterModuleType("imported_filegroup", importedFileGroupFactory) - - android.PreArchMutators(RegisterMultitreePreArchMutators) -} - -type importedFileGroupProperties struct { - // Imported modules from the other components in a multi-tree - Imported []string -} - -type importedFileGroup struct { - android.ModuleBase - - properties importedFileGroupProperties - srcs android.Paths -} - -func (ifg *importedFileGroup) Name() string { - return ifg.BaseModuleName() + nameSuffix -} - -func importedFileGroupFactory() android.Module { - module := &importedFileGroup{} - module.AddProperties(&module.properties) - - android.InitAndroidModule(module) - return module -} - -var _ MultitreeImportedModuleInterface = (*importedFileGroup)(nil) - -func (ifg *importedFileGroup) GetMultitreeImportedModuleName() string { - // The base module name of the imported filegroup is used as the imported module name - return ifg.BaseModuleName() -} - -var _ android.SourceFileProducer = (*importedFileGroup)(nil) - -func (ifg *importedFileGroup) Srcs() android.Paths { - return ifg.srcs -} - -func (ifg *importedFileGroup) GenerateAndroidBuildActions(ctx android.ModuleContext) { - // srcs from this module must not be used. Adding a dot path to avoid the empty - // source failure. Still soong returns error when a module wants to build against - // this source, which is intended. - ifg.srcs = android.PathsForModuleSrc(ctx, []string{"."}) -} - -func RegisterMultitreePreArchMutators(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("multitree_imported_rename", MultitreeImportedRenameMutator).Parallel() -} - -func MultitreeImportedRenameMutator(ctx android.BottomUpMutatorContext) { - if m, ok := ctx.Module().(MultitreeImportedModuleInterface); ok { - name := m.GetMultitreeImportedModuleName() - if !ctx.OtherModuleExists(name) { - // Provide an empty filegroup not to break the build while updating the metadata. - // In other cases, soong will report an error to guide users to run 'm update-meta' - // first. - if !ctx.Config().TargetMultitreeUpdateMeta() { - ctx.ModuleErrorf("\"%s\" filegroup must be imported.\nRun 'm update-meta' first to import the filegroup.", name) - } - ctx.Rename(name) - } - } -} diff --git a/multitree/metadata.go b/multitree/metadata.go deleted file mode 100644 index 0eb0efc95..000000000 --- a/multitree/metadata.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2022 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 multitree - -import ( - "android/soong/android" - "encoding/json" -) - -func init() { - android.RegisterParallelSingletonType("update-meta", UpdateMetaSingleton) -} - -func UpdateMetaSingleton() android.Singleton { - return &updateMetaSingleton{} -} - -type jsonImported struct { - FileGroups map[string][]string `json:",omitempty"` -} - -type metadataJsonFlags struct { - Imported jsonImported `json:",omitempty"` - Exported map[string][]string `json:",omitempty"` -} - -type updateMetaSingleton struct { - importedModules []string - generatedMetadataFile android.OutputPath -} - -func (s *updateMetaSingleton) GenerateBuildActions(ctx android.SingletonContext) { - metadata := metadataJsonFlags{ - Imported: jsonImported{ - FileGroups: make(map[string][]string), - }, - Exported: make(map[string][]string), - } - ctx.VisitAllModules(func(module android.Module) { - if ifg, ok := module.(*importedFileGroup); ok { - metadata.Imported.FileGroups[ifg.BaseModuleName()] = ifg.properties.Imported - } - if e, ok := module.(ExportableModule); ok { - if e.IsExported() && e.Exportable() { - for tag, files := range e.TaggedOutputs() { - // TODO(b/219846705): refactor this to a dictionary - metadata.Exported[e.Name()+":"+tag] = append(metadata.Exported[e.Name()+":"+tag], files.Strings()...) - } - } - } - }) - jsonStr, err := json.Marshal(metadata) - if err != nil { - ctx.Errorf(err.Error()) - } - s.generatedMetadataFile = android.PathForOutput(ctx, "multitree", "metadata.json") - android.WriteFileRule(ctx, s.generatedMetadataFile, string(jsonStr)) -} - -func (s *updateMetaSingleton) MakeVars(ctx android.MakeVarsContext) { - ctx.Strict("MULTITREE_METADATA", s.generatedMetadataFile.String()) -} diff --git a/rust/clippy.go b/rust/clippy.go index 6f0ed7ff1..426fd7393 100644 --- a/rust/clippy.go +++ b/rust/clippy.go @@ -38,11 +38,14 @@ func (c *clippy) props() []interface{} { } func (c *clippy) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) { - enabled, lints, err := config.ClippyLintsForDir(ctx.ModuleDir(), c.Properties.Clippy_lints) + dirEnabled, lints, err := config.ClippyLintsForDir(ctx.ModuleDir(), c.Properties.Clippy_lints) if err != nil { ctx.PropertyErrorf("clippy_lints", err.Error()) } - flags.Clippy = enabled + + envDisable := ctx.Config().IsEnvTrue("SOONG_DISABLE_CLIPPY") + + flags.Clippy = dirEnabled && !envDisable flags.ClippyFlags = append(flags.ClippyFlags, lints) return flags, deps } diff --git a/rust/config/global.go b/rust/config/global.go index 990a64331..68a74c204 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -24,7 +24,7 @@ import ( var ( pctx = android.NewPackageContext("android/soong/rust/config") - RustDefaultVersion = "1.80.1" + RustDefaultVersion = "1.81.0" RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2021" Stdlibs = []string{ diff --git a/rust/coverage.go b/rust/coverage.go index 91a78060d..381fcf1b4 100644 --- a/rust/coverage.go +++ b/rust/coverage.go @@ -87,10 +87,6 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags } func (cov *coverage) begin(ctx BaseModuleContext) { - if ctx.Host() { - // Host coverage not yet supported. - } else { - // Update useSdk and sdkVersion args if Rust modules become SDK aware. - cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.RustModule().nativeCoverage(), false, "") - } + // Update useSdk and sdkVersion args if Rust modules become SDK aware. + cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.RustModule().nativeCoverage(), false, "") } diff --git a/rust/rust.go b/rust/rust.go index 240c22178..50f822b53 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -29,7 +29,6 @@ import ( "android/soong/cc" cc_config "android/soong/cc/config" "android/soong/fuzz" - "android/soong/multitree" "android/soong/rust/config" ) @@ -1218,47 +1217,6 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { skipModuleList := map[string]bool{} - var apiImportInfo multitree.ApiImportInfo - hasApiImportInfo := false - - ctx.VisitDirectDeps(func(dep android.Module) { - if dep.Name() == "api_imports" { - apiImportInfo, _ = android.OtherModuleProvider(ctx, dep, multitree.ApiImportsProvider) - hasApiImportInfo = true - } - }) - - if hasApiImportInfo { - targetStubModuleList := map[string]string{} - targetOrigModuleList := map[string]string{} - - // Search for dependency which both original module and API imported library with APEX stub exists - ctx.VisitDirectDeps(func(dep android.Module) { - depName := ctx.OtherModuleName(dep) - if apiLibrary, ok := apiImportInfo.ApexSharedLibs[depName]; ok { - targetStubModuleList[apiLibrary] = depName - } - }) - ctx.VisitDirectDeps(func(dep android.Module) { - depName := ctx.OtherModuleName(dep) - if origLibrary, ok := targetStubModuleList[depName]; ok { - targetOrigModuleList[origLibrary] = depName - } - }) - - // Decide which library should be used between original and API imported library - ctx.VisitDirectDeps(func(dep android.Module) { - depName := ctx.OtherModuleName(dep) - if apiLibrary, ok := targetOrigModuleList[depName]; ok { - if cc.ShouldUseStubForApex(ctx, dep) { - skipModuleList[depName] = true - } else { - skipModuleList[apiLibrary] = true - } - } - }) - } - var transitiveAndroidMkSharedLibs []*android.DepSet[string] var directAndroidMkSharedLibs []string @@ -1609,13 +1567,6 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { deps := mod.deps(ctx) var commonDepVariations []blueprint.Variation - apiImportInfo := cc.GetApiImports(mod, actx) - if mod.usePublicApi() || mod.useVendorApi() { - for idx, lib := range deps.SharedLibs { - deps.SharedLibs[idx] = cc.GetReplaceModuleName(lib, apiImportInfo.SharedLibs) - } - } - if ctx.Os() == android.Android { deps.SharedLibs, _ = cc.FilterNdkLibs(mod, ctx.Config(), deps.SharedLibs) } @@ -1708,15 +1659,7 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { variations := []blueprint.Variation{ {Mutator: "link", Variation: "shared"}, } - // For core variant, add a dep on the implementation (if it exists) and its .apiimport (if it exists) - // GenerateAndroidBuildActions will pick the correct impl/stub based on the api_domain boundary - if _, ok := apiImportInfo.ApexSharedLibs[name]; !ok || ctx.OtherModuleExists(name) { - cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, name, version, false) - } - - if apiLibraryName, ok := apiImportInfo.ApexSharedLibs[name]; ok { - cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, apiLibraryName, version, false) - } + cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, name, version, false) } for _, lib := range deps.WholeStaticLibs { diff --git a/scripts/check_prebuilt_presigned_apk.py b/scripts/check_prebuilt_presigned_apk.py index abab2e146..db64f90c6 100755 --- a/scripts/check_prebuilt_presigned_apk.py +++ b/scripts/check_prebuilt_presigned_apk.py @@ -36,7 +36,7 @@ def has_preprocessed_issues(args, *, fail=False): if fail: sys.exit(args.apk + ': Contains compressed JNI libraries') return True - # It's ok for non-privileged apps to have compressed dex files, see go/gms-uncompressed-jni-slides + # It's ok for non-privileged apps to have compressed dex files if args.privileged and args.uncompress_priv_app_dex: if info.filename.endswith('.dex') and info.compress_type != zipfile.ZIP_STORED: if fail: @@ -46,6 +46,10 @@ def has_preprocessed_issues(args, *, fail=False): def main(): + # This script enforces requirements for presigned apps as documented in: + # go/gms-uncompressed-jni-slides + # https://docs.partner.android.com/gms/building/integrating/jni-libs + # https://docs.partner.android.com/gms/policies/domains/mba#jni-lib parser = argparse.ArgumentParser() parser.add_argument('--aapt2', help = "the path to the aapt2 executable") parser.add_argument('--zipalign', help = "the path to the zipalign executable") diff --git a/scripts/manifest.py b/scripts/manifest.py index 81f9c61a8..32603e869 100755 --- a/scripts/manifest.py +++ b/scripts/manifest.py @@ -23,9 +23,40 @@ from xml.dom import minidom android_ns = 'http://schemas.android.com/apk/res/android' +def get_or_create_applications(doc, manifest): + """Get all <application> tags from the manifest, or create one if none exist. + Multiple <application> tags may exist when manifest feature flagging is used. + """ + applications = get_children_with_tag(manifest, 'application') + if len(applications) == 0: + application = doc.createElement('application') + indent = get_indent(manifest.firstChild, 1) + first = manifest.firstChild + manifest.insertBefore(doc.createTextNode(indent), first) + manifest.insertBefore(application, first) + applications.append(application) + return applications + + +def get_or_create_uses_sdks(doc, manifest): + """Get all <uses-sdk> tags from the manifest, or create one if none exist. + Multiple <uses-sdk> tags may exist when manifest feature flagging is used. + """ + uses_sdks = get_children_with_tag(manifest, 'uses-sdk') + if len(uses_sdks) == 0: + uses_sdk = doc.createElement('uses-sdk') + indent = get_indent(manifest.firstChild, 1) + manifest.insertBefore(uses_sdk, manifest.firstChild) + + # Insert an indent before uses-sdk to line it up with the indentation of the + # other children of the <manifest> tag. + manifest.insertBefore(doc.createTextNode(indent), manifest.firstChild) + uses_sdks.append(uses_sdk) + return uses_sdks + def get_children_with_tag(parent, tag_name): children = [] - for child in parent.childNodes: + for child in parent.childNodes: if child.nodeType == minidom.Node.ELEMENT_NODE and \ child.tagName == tag_name: children.append(child) diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py index b10125994..1e32d1d7d 100755 --- a/scripts/manifest_check.py +++ b/scripts/manifest_check.py @@ -25,10 +25,7 @@ import subprocess import sys from xml.dom import minidom -from manifest import android_ns -from manifest import get_children_with_tag -from manifest import parse_manifest -from manifest import write_xml +from manifest import * class ManifestMismatchError(Exception): @@ -122,7 +119,7 @@ def enforce_uses_libraries(manifest, required, optional, missing_optional, relax # handles module names specified in Android.bp properties. However not all # <uses-library> entries in the manifest correspond to real modules: some of # the optional libraries may be missing at build time. Therefor this script - # accepts raw module names as spelled in Android.bp/Amdroid.mk and trims the + # accepts raw module names as spelled in Android.bp/Android.mk and trims the # optional namespace part manually. required = trim_namespace_parts(required) optional = trim_namespace_parts(optional) @@ -205,15 +202,9 @@ def extract_uses_libs_xml(xml): """Extract <uses-library> tags from the manifest.""" manifest = parse_manifest(xml) - elems = get_children_with_tag(manifest, 'application') - if len(elems) > 1: - raise RuntimeError('found multiple <application> tags') - if not elems: - return [], [], [] - - application = elems[0] - - libs = get_children_with_tag(application, 'uses-library') + libs = [child + for application in get_or_create_applications(xml, manifest) + for child in get_children_with_tag(application, 'uses-library')] required = [uses_library_name(x) for x in libs if uses_library_required(x)] optional = [ @@ -266,7 +257,7 @@ def extract_target_sdk_version(manifest, is_apk=False): manifest: manifest (either parsed XML or aapt dump of APK) is_apk: if the manifest comes from an APK or an XML file """ - if is_apk: #pylint: disable=no-else-return + if is_apk: #pylint: disable=no-else-return return extract_target_sdk_version_apk(manifest) else: return extract_target_sdk_version_xml(manifest) @@ -376,7 +367,7 @@ def main(): # Create a status file that is empty on success, or contains an # error message on failure. When exceptions are suppressed, - # dexpreopt command command will check file size to determine if + # dexpreopt command will check file size to determine if # the check has failed. if args.enforce_uses_libraries_status: with open(args.enforce_uses_libraries_status, 'w') as f: @@ -386,7 +377,7 @@ def main(): if args.extract_target_sdk_version: try: print(extract_target_sdk_version(manifest, is_apk)) - except: #pylint: disable=bare-except + except: #pylint: disable=bare-except # Failed; don't crash, return "any" SDK version. This will # result in dexpreopt not adding any compatibility libraries. print(10000) diff --git a/scripts/manifest_check_test.py b/scripts/manifest_check_test.py index 8003b3e19..abe0d8b0e 100755 --- a/scripts/manifest_check_test.py +++ b/scripts/manifest_check_test.py @@ -44,8 +44,8 @@ def required_apk(value): class EnforceUsesLibrariesTest(unittest.TestCase): """Unit tests for add_extract_native_libs function.""" - def run_test(self, xml, apk, uses_libraries=[], optional_uses_libraries=[], - missing_optional_uses_libraries=[]): #pylint: disable=dangerous-default-value + def run_test(self, xml, apk, uses_libraries=(), optional_uses_libraries=(), + missing_optional_uses_libraries=()): #pylint: disable=dangerous-default-value doc = minidom.parseString(xml) try: relax = False @@ -114,14 +114,14 @@ class EnforceUsesLibrariesTest(unittest.TestCase): self.assertFalse(matches) def test_missing_uses_library(self): - xml = self.xml_tmpl % ('') - apk = self.apk_tmpl % ('') + xml = self.xml_tmpl % '' + apk = self.apk_tmpl % '' matches = self.run_test(xml, apk, uses_libraries=['foo']) self.assertFalse(matches) def test_missing_optional_uses_library(self): - xml = self.xml_tmpl % ('') - apk = self.apk_tmpl % ('') + xml = self.xml_tmpl % '' + apk = self.apk_tmpl % '' matches = self.run_test(xml, apk, optional_uses_libraries=['foo']) self.assertFalse(matches) @@ -234,6 +234,32 @@ class EnforceUsesLibrariesTest(unittest.TestCase): optional_uses_libraries=['//x/y/z:bar']) self.assertTrue(matches) + def test_multiple_applications(self): + xml = """<?xml version="1.0" encoding="utf-8"?> + <manifest xmlns:android="http://schemas.android.com/apk/res/android"> + <application android:featureFlag="foo"> + <uses-library android:name="foo" /> + <uses-library android:name="bar" android:required="false" /> + </application> + <application android:featureFlag="!foo"> + <uses-library android:name="foo" /> + <uses-library android:name="qux" android:required="false" /> + </application> + </manifest> + """ + apk = self.apk_tmpl % ('\n'.join([ + uses_library_apk('foo'), + uses_library_apk('bar', required_apk(False)), + uses_library_apk('foo'), + uses_library_apk('qux', required_apk(False)) + ])) + matches = self.run_test( + xml, + apk, + uses_libraries=['//x/y/z:foo'], + optional_uses_libraries=['//x/y/z:bar', '//x/y/z:qux']) + self.assertTrue(matches) + class ExtractTargetSdkVersionTest(unittest.TestCase): @@ -256,12 +282,12 @@ class ExtractTargetSdkVersionTest(unittest.TestCase): "targetSdkVersion:'%s'\n" "uses-permission: name='android.permission.ACCESS_NETWORK_STATE'\n") - def test_targert_sdk_version_28(self): + def test_target_sdk_version_28(self): xml = self.xml_tmpl % '28' apk = self.apk_tmpl % '28' self.run_test(xml, apk, '28') - def test_targert_sdk_version_29(self): + def test_target_sdk_version_29(self): xml = self.xml_tmpl % '29' apk = self.apk_tmpl % '29' self.run_test(xml, apk, '29') diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py index 58079aa5d..9847ad5bb 100755 --- a/scripts/manifest_fixer.py +++ b/scripts/manifest_fixer.py @@ -23,15 +23,7 @@ import sys from xml.dom import minidom -from manifest import android_ns -from manifest import compare_version_gt -from manifest import ensure_manifest_android_ns -from manifest import find_child_with_attribute -from manifest import get_children_with_tag -from manifest import get_indent -from manifest import parse_manifest -from manifest import write_xml - +from manifest import * def parse_args(): """Parse commandline arguments.""" @@ -48,9 +40,9 @@ def parse_args(): parser.add_argument('--library', dest='library', action='store_true', help='manifest is for a static library') parser.add_argument('--uses-library', dest='uses_libraries', action='append', - help='specify additional <uses-library> tag to add. android:requred is set to true') + help='specify additional <uses-library> tag to add. android:required is set to true') parser.add_argument('--optional-uses-library', dest='optional_uses_libraries', action='append', - help='specify additional <uses-library> tag to add. android:requred is set to false') + help='specify additional <uses-library> tag to add. android:required is set to false') parser.add_argument('--uses-non-sdk-api', dest='uses_non_sdk_api', action='store_true', help='manifest is for a package built against the platform') parser.add_argument('--logging-parent', dest='logging_parent', default='', @@ -91,47 +83,33 @@ def raise_min_sdk_version(doc, min_sdk_version, target_sdk_version, library): manifest = parse_manifest(doc) - # Get or insert the uses-sdk element - uses_sdk = get_children_with_tag(manifest, 'uses-sdk') - if len(uses_sdk) > 1: - raise RuntimeError('found multiple uses-sdk elements') - elif len(uses_sdk) == 1: - element = uses_sdk[0] - else: - element = doc.createElement('uses-sdk') - indent = get_indent(manifest.firstChild, 1) - manifest.insertBefore(element, manifest.firstChild) - - # Insert an indent before uses-sdk to line it up with the indentation of the - # other children of the <manifest> tag. - manifest.insertBefore(doc.createTextNode(indent), manifest.firstChild) - - # Get or insert the minSdkVersion attribute. If it is already present, make - # sure it as least the requested value. - min_attr = element.getAttributeNodeNS(android_ns, 'minSdkVersion') - if min_attr is None: - min_attr = doc.createAttributeNS(android_ns, 'android:minSdkVersion') - min_attr.value = min_sdk_version - element.setAttributeNode(min_attr) - else: - if compare_version_gt(min_sdk_version, min_attr.value): + for uses_sdk in get_or_create_uses_sdks(doc, manifest): + # Get or insert the minSdkVersion attribute. If it is already present, make + # sure it as least the requested value. + min_attr = uses_sdk.getAttributeNodeNS(android_ns, 'minSdkVersion') + if min_attr is None: + min_attr = doc.createAttributeNS(android_ns, 'android:minSdkVersion') min_attr.value = min_sdk_version - - # Insert the targetSdkVersion attribute if it is missing. If it is already - # present leave it as is. - target_attr = element.getAttributeNodeNS(android_ns, 'targetSdkVersion') - if target_attr is None: - target_attr = doc.createAttributeNS(android_ns, 'android:targetSdkVersion') - if library: - # TODO(b/117122200): libraries shouldn't set targetSdkVersion at all, but - # ManifestMerger treats minSdkVersion="Q" as targetSdkVersion="Q" if it - # is empty. Set it to something low so that it will be overriden by the - # main manifest, but high enough that it doesn't cause implicit - # permissions grants. - target_attr.value = '16' + uses_sdk.setAttributeNode(min_attr) else: - target_attr.value = target_sdk_version - element.setAttributeNode(target_attr) + if compare_version_gt(min_sdk_version, min_attr.value): + min_attr.value = min_sdk_version + + # Insert the targetSdkVersion attribute if it is missing. If it is already + # present leave it as is. + target_attr = uses_sdk.getAttributeNodeNS(android_ns, 'targetSdkVersion') + if target_attr is None: + target_attr = doc.createAttributeNS(android_ns, 'android:targetSdkVersion') + if library: + # TODO(b/117122200): libraries shouldn't set targetSdkVersion at all, but + # ManifestMerger treats minSdkVersion="Q" as targetSdkVersion="Q" if it + # is empty. Set it to something low so that it will be overridden by the + # main manifest, but high enough that it doesn't cause implicit + # permissions grants. + target_attr.value = '16' + else: + target_attr.value = target_sdk_version + uses_sdk.setAttributeNode(target_attr) def add_logging_parent(doc, logging_parent_value): @@ -147,37 +125,27 @@ def add_logging_parent(doc, logging_parent_value): manifest = parse_manifest(doc) logging_parent_key = 'android.content.pm.LOGGING_PARENT' - elems = get_children_with_tag(manifest, 'application') - application = elems[0] if len(elems) == 1 else None - if len(elems) > 1: - raise RuntimeError('found multiple <application> tags') - elif not elems: - application = doc.createElement('application') - indent = get_indent(manifest.firstChild, 1) - first = manifest.firstChild - manifest.insertBefore(doc.createTextNode(indent), first) - manifest.insertBefore(application, first) - - indent = get_indent(application.firstChild, 2) - - last = application.lastChild - if last is not None and last.nodeType != minidom.Node.TEXT_NODE: - last = None - - if not find_child_with_attribute(application, 'meta-data', android_ns, - 'name', logging_parent_key): - ul = doc.createElement('meta-data') - ul.setAttributeNS(android_ns, 'android:name', logging_parent_key) - ul.setAttributeNS(android_ns, 'android:value', logging_parent_value) - application.insertBefore(doc.createTextNode(indent), last) - application.insertBefore(ul, last) + for application in get_or_create_applications(doc, manifest): + indent = get_indent(application.firstChild, 2) + last = application.lastChild + if last is not None and last.nodeType != minidom.Node.TEXT_NODE: + last = None - # align the closing tag with the opening tag if it's not - # indented - if last and last.nodeType != minidom.Node.TEXT_NODE: - indent = get_indent(application.previousSibling, 1) - application.appendChild(doc.createTextNode(indent)) + if not find_child_with_attribute(application, 'meta-data', android_ns, + 'name', logging_parent_key): + ul = doc.createElement('meta-data') + ul.setAttributeNS(android_ns, 'android:name', logging_parent_key) + ul.setAttributeNS(android_ns, 'android:value', logging_parent_value) + application.insertBefore(doc.createTextNode(indent), last) + application.insertBefore(ul, last) + last = application.lastChild + + # align the closing tag with the opening tag if it's not + # indented + if last and last.nodeType != minidom.Node.TEXT_NODE: + indent = get_indent(application.previousSibling, 1) + application.appendChild(doc.createTextNode(indent)) def add_uses_libraries(doc, new_uses_libraries, required): @@ -192,42 +160,32 @@ def add_uses_libraries(doc, new_uses_libraries, required): """ manifest = parse_manifest(doc) - elems = get_children_with_tag(manifest, 'application') - application = elems[0] if len(elems) == 1 else None - if len(elems) > 1: - raise RuntimeError('found multiple <application> tags') - elif not elems: - application = doc.createElement('application') - indent = get_indent(manifest.firstChild, 1) - first = manifest.firstChild - manifest.insertBefore(doc.createTextNode(indent), first) - manifest.insertBefore(application, first) - - indent = get_indent(application.firstChild, 2) - - last = application.lastChild - if last is not None and last.nodeType != minidom.Node.TEXT_NODE: - last = None - - for name in new_uses_libraries: - if find_child_with_attribute(application, 'uses-library', android_ns, - 'name', name) is not None: - # If the uses-library tag of the same 'name' attribute value exists, - # respect it. - continue + for application in get_or_create_applications(doc, manifest): + indent = get_indent(application.firstChild, 2) + + last = application.lastChild + if last is not None and last.nodeType != minidom.Node.TEXT_NODE: + last = None + + for name in new_uses_libraries: + if find_child_with_attribute(application, 'uses-library', android_ns, + 'name', name) is not None: + # If the uses-library tag of the same 'name' attribute value exists, + # respect it. + continue - ul = doc.createElement('uses-library') - ul.setAttributeNS(android_ns, 'android:name', name) - ul.setAttributeNS(android_ns, 'android:required', str(required).lower()) + ul = doc.createElement('uses-library') + ul.setAttributeNS(android_ns, 'android:name', name) + ul.setAttributeNS(android_ns, 'android:required', str(required).lower()) - application.insertBefore(doc.createTextNode(indent), last) - application.insertBefore(ul, last) + application.insertBefore(doc.createTextNode(indent), last) + application.insertBefore(ul, last) - # align the closing tag with the opening tag if it's not - # indented - if application.lastChild.nodeType != minidom.Node.TEXT_NODE: - indent = get_indent(application.previousSibling, 1) - application.appendChild(doc.createTextNode(indent)) + # align the closing tag with the opening tag if it's not + # indented + if application.lastChild.nodeType != minidom.Node.TEXT_NODE: + indent = get_indent(application.previousSibling, 1) + application.appendChild(doc.createTextNode(indent)) def add_uses_non_sdk_api(doc): @@ -240,111 +198,63 @@ def add_uses_non_sdk_api(doc): """ manifest = parse_manifest(doc) - elems = get_children_with_tag(manifest, 'application') - application = elems[0] if len(elems) == 1 else None - if len(elems) > 1: - raise RuntimeError('found multiple <application> tags') - elif not elems: - application = doc.createElement('application') - indent = get_indent(manifest.firstChild, 1) - first = manifest.firstChild - manifest.insertBefore(doc.createTextNode(indent), first) - manifest.insertBefore(application, first) - - attr = application.getAttributeNodeNS(android_ns, 'usesNonSdkApi') - if attr is None: - attr = doc.createAttributeNS(android_ns, 'android:usesNonSdkApi') - attr.value = 'true' - application.setAttributeNode(attr) + for application in get_or_create_applications(doc, manifest): + attr = application.getAttributeNodeNS(android_ns, 'usesNonSdkApi') + if attr is None: + attr = doc.createAttributeNS(android_ns, 'android:usesNonSdkApi') + attr.value = 'true' + application.setAttributeNode(attr) def add_use_embedded_dex(doc): manifest = parse_manifest(doc) - elems = get_children_with_tag(manifest, 'application') - application = elems[0] if len(elems) == 1 else None - if len(elems) > 1: - raise RuntimeError('found multiple <application> tags') - elif not elems: - application = doc.createElement('application') - indent = get_indent(manifest.firstChild, 1) - first = manifest.firstChild - manifest.insertBefore(doc.createTextNode(indent), first) - manifest.insertBefore(application, first) - - attr = application.getAttributeNodeNS(android_ns, 'useEmbeddedDex') - if attr is None: - attr = doc.createAttributeNS(android_ns, 'android:useEmbeddedDex') - attr.value = 'true' - application.setAttributeNode(attr) - elif attr.value != 'true': - raise RuntimeError('existing attribute mismatches the option of --use-embedded-dex') + for application in get_or_create_applications(doc, manifest): + attr = application.getAttributeNodeNS(android_ns, 'useEmbeddedDex') + if attr is None: + attr = doc.createAttributeNS(android_ns, 'android:useEmbeddedDex') + attr.value = 'true' + application.setAttributeNode(attr) + elif attr.value != 'true': + raise RuntimeError('existing attribute mismatches the option of --use-embedded-dex') def add_extract_native_libs(doc, extract_native_libs): manifest = parse_manifest(doc) - elems = get_children_with_tag(manifest, 'application') - application = elems[0] if len(elems) == 1 else None - if len(elems) > 1: - raise RuntimeError('found multiple <application> tags') - elif not elems: - application = doc.createElement('application') - indent = get_indent(manifest.firstChild, 1) - first = manifest.firstChild - manifest.insertBefore(doc.createTextNode(indent), first) - manifest.insertBefore(application, first) - - value = str(extract_native_libs).lower() - attr = application.getAttributeNodeNS(android_ns, 'extractNativeLibs') - if attr is None: - attr = doc.createAttributeNS(android_ns, 'android:extractNativeLibs') - attr.value = value - application.setAttributeNode(attr) - elif attr.value != value: - raise RuntimeError('existing attribute extractNativeLibs="%s" conflicts with --extract-native-libs="%s"' % - (attr.value, value)) + for application in get_or_create_applications(doc, manifest): + value = str(extract_native_libs).lower() + attr = application.getAttributeNodeNS(android_ns, 'extractNativeLibs') + if attr is None: + attr = doc.createAttributeNS(android_ns, 'android:extractNativeLibs') + attr.value = value + application.setAttributeNode(attr) + elif attr.value != value: + raise RuntimeError('existing attribute extractNativeLibs="%s" conflicts with --extract-native-libs="%s"' % + (attr.value, value)) def set_has_code_to_false(doc): manifest = parse_manifest(doc) - elems = get_children_with_tag(manifest, 'application') - application = elems[0] if len(elems) == 1 else None - if len(elems) > 1: - raise RuntimeError('found multiple <application> tags') - elif not elems: - application = doc.createElement('application') - indent = get_indent(manifest.firstChild, 1) - first = manifest.firstChild - manifest.insertBefore(doc.createTextNode(indent), first) - manifest.insertBefore(application, first) - - attr = application.getAttributeNodeNS(android_ns, 'hasCode') - if attr is not None: - # Do nothing if the application already has a hasCode attribute. - return - attr = doc.createAttributeNS(android_ns, 'android:hasCode') - attr.value = 'false' - application.setAttributeNode(attr) + for application in get_or_create_applications(doc, manifest): + attr = application.getAttributeNodeNS(android_ns, 'hasCode') + if attr is not None: + # Do nothing if the application already has a hasCode attribute. + continue + attr = doc.createAttributeNS(android_ns, 'android:hasCode') + attr.value = 'false' + application.setAttributeNode(attr) + def set_test_only_flag_to_true(doc): manifest = parse_manifest(doc) - elems = get_children_with_tag(manifest, 'application') - application = elems[0] if len(elems) == 1 else None - if len(elems) > 1: - raise RuntimeError('found multiple <application> tags') - elif not elems: - application = doc.createElement('application') - indent = get_indent(manifest.firstChild, 1) - first = manifest.firstChild - manifest.insertBefore(doc.createTextNode(indent), first) - manifest.insertBefore(application, first) - - attr = application.getAttributeNodeNS(android_ns, 'testOnly') - if attr is not None: - # Do nothing If the application already has a testOnly attribute. - return - attr = doc.createAttributeNS(android_ns, 'android:testOnly') - attr.value = 'true' - application.setAttributeNode(attr) + for application in get_or_create_applications(doc, manifest): + attr = application.getAttributeNodeNS(android_ns, 'testOnly') + if attr is not None: + # Do nothing If the application already has a testOnly attribute. + continue + attr = doc.createAttributeNS(android_ns, 'android:testOnly') + attr.value = 'true' + application.setAttributeNode(attr) + def set_max_sdk_version(doc, max_sdk_version): """Replace the maxSdkVersion attribute value for permission and @@ -364,6 +274,7 @@ def set_max_sdk_version(doc, max_sdk_version): if max_attr and max_attr.value == 'current': max_attr.value = max_sdk_version + def override_placeholder_version(doc, new_version): """Replace the versionCode attribute value if it\'s currently set to the placeholder version of 0. @@ -374,9 +285,10 @@ def override_placeholder_version(doc, new_version): """ manifest = parse_manifest(doc) version = manifest.getAttribute("android:versionCode") - if (version == '0'): + if version == '0': manifest.setAttribute("android:versionCode", new_version) + def main(): """Program entry point.""" try: @@ -427,5 +339,6 @@ def main(): print('error: ' + str(err), file=sys.stderr) sys.exit(-1) + if __name__ == '__main__': main() diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py index 0a62b10a4..e4d8dc383 100755 --- a/scripts/manifest_fixer_test.py +++ b/scripts/manifest_fixer_test.py @@ -20,12 +20,13 @@ import io import sys import unittest from xml.dom import minidom -import xml.etree.ElementTree as ET +import xml.etree.ElementTree as ElementTree import manifest_fixer sys.dont_write_bytecode = True + class CompareVersionGtTest(unittest.TestCase): """Unit tests for compare_version_gt function.""" @@ -69,25 +70,24 @@ class RaiseMinSdkVersionTest(unittest.TestCase): '%s' '</manifest>\n') - # pylint: disable=redefined-builtin - def uses_sdk(self, min=None, target=None, extra=''): + def uses_sdk(self, min_sdk=None, target_sdk=None, extra=''): attrs = '' - if min: - attrs += ' android:minSdkVersion="%s"' % (min) - if target: - attrs += ' android:targetSdkVersion="%s"' % (target) + if min_sdk: + attrs += ' android:minSdkVersion="%s"' % min_sdk + if target_sdk: + attrs += ' android:targetSdkVersion="%s"' % target_sdk if extra: attrs += ' ' + extra - return ' <uses-sdk%s/>\n' % (attrs) + return ' <uses-sdk%s/>\n' % attrs def assert_xml_equal(self, output, expected): - self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected)) def test_no_uses_sdk(self): """Tests inserting a uses-sdk element into a manifest.""" manifest_input = self.manifest_tmpl % '' - expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28') output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False) self.assert_xml_equal(output, expected) @@ -95,7 +95,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): """Tests inserting a minSdkVersion attribute into a uses-sdk element.""" manifest_input = self.manifest_tmpl % ' <uses-sdk extra="foo"/>\n' - expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28', + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28', extra='extra="foo"') output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False) self.assert_xml_equal(output, expected) @@ -103,64 +103,64 @@ class RaiseMinSdkVersionTest(unittest.TestCase): def test_raise_min(self): """Tests inserting a minSdkVersion attribute into a uses-sdk element.""" - manifest_input = self.manifest_tmpl % self.uses_sdk(min='27') - expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28') + manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28') output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False) self.assert_xml_equal(output, expected) def test_raise(self): """Tests raising a minSdkVersion attribute.""" - manifest_input = self.manifest_tmpl % self.uses_sdk(min='27') - expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28') + manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='28') output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False) self.assert_xml_equal(output, expected) def test_no_raise_min(self): """Tests a minSdkVersion that doesn't need raising.""" - manifest_input = self.manifest_tmpl % self.uses_sdk(min='28') - expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27') + manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='28') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27') output = self.raise_min_sdk_version_test(manifest_input, '27', '27', False) self.assert_xml_equal(output, expected) def test_raise_codename(self): """Tests raising a minSdkVersion attribute to a codename.""" - manifest_input = self.manifest_tmpl % self.uses_sdk(min='28') - expected = self.manifest_tmpl % self.uses_sdk(min='P', target='P') + manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='28') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='P', target_sdk='P') output = self.raise_min_sdk_version_test(manifest_input, 'P', 'P', False) self.assert_xml_equal(output, expected) def test_no_raise_codename(self): """Tests a minSdkVersion codename that doesn't need raising.""" - manifest_input = self.manifest_tmpl % self.uses_sdk(min='P') - expected = self.manifest_tmpl % self.uses_sdk(min='P', target='28') + manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='P') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='P', target_sdk='28') output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False) self.assert_xml_equal(output, expected) def test_target(self): """Tests an existing targetSdkVersion is preserved.""" - manifest_input = self.manifest_tmpl % self.uses_sdk(min='26', target='27') - expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27') + manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='26', target_sdk='27') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False) self.assert_xml_equal(output, expected) def test_no_target(self): """Tests inserting targetSdkVersion when minSdkVersion exists.""" - manifest_input = self.manifest_tmpl % self.uses_sdk(min='27') - expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29') + manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='29') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False) self.assert_xml_equal(output, expected) def test_target_no_min(self): """"Tests inserting targetSdkVersion when minSdkVersion exists.""" - manifest_input = self.manifest_tmpl % self.uses_sdk(target='27') - expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27') + manifest_input = self.manifest_tmpl % self.uses_sdk(target_sdk='27') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False) self.assert_xml_equal(output, expected) @@ -168,23 +168,23 @@ class RaiseMinSdkVersionTest(unittest.TestCase): """Tests inserting targetSdkVersion when minSdkVersion does not exist.""" manifest_input = self.manifest_tmpl % '' - expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='29') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False) self.assert_xml_equal(output, expected) def test_library_no_target(self): """Tests inserting targetSdkVersion when minSdkVersion exists.""" - manifest_input = self.manifest_tmpl % self.uses_sdk(min='27') - expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16') + manifest_input = self.manifest_tmpl % self.uses_sdk(min_sdk='27') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='16') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True) self.assert_xml_equal(output, expected) def test_library_target_no_min(self): """Tests inserting targetSdkVersion when minSdkVersion exists.""" - manifest_input = self.manifest_tmpl % self.uses_sdk(target='27') - expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27') + manifest_input = self.manifest_tmpl % self.uses_sdk(target_sdk='27') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='27') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True) self.assert_xml_equal(output, expected) @@ -192,7 +192,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): """Tests inserting targetSdkVersion when minSdkVersion does not exist.""" manifest_input = self.manifest_tmpl % '' - expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16') + expected = self.manifest_tmpl % self.uses_sdk(min_sdk='28', target_sdk='16') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True) self.assert_xml_equal(output, expected) @@ -228,12 +228,24 @@ class RaiseMinSdkVersionTest(unittest.TestCase): self.assert_xml_equal(output, expected) + def test_multiple_uses_sdks(self): + """Tests a manifest that contains multiple uses_sdks elements.""" + + manifest_input = self.manifest_tmpl % ( + ' <uses-sdk android:featureFlag="foo" android:minSdkVersion="21" />\n' + ' <uses-sdk android:featureFlag="!foo" android:minSdkVersion="22" />\n') + expected = self.manifest_tmpl % ( + ' <uses-sdk android:featureFlag="foo" android:minSdkVersion="28" android:targetSdkVersion="28" />\n' + ' <uses-sdk android:featureFlag="!foo" android:minSdkVersion="28" android:targetSdkVersion="28" />\n') + + output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False) + self.assert_xml_equal(output, expected) class AddLoggingParentTest(unittest.TestCase): """Unit tests for add_logging_parent function.""" def assert_xml_equal(self, output, expected): - self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected)) def add_logging_parent_test(self, input_manifest, logging_parent=None): doc = minidom.parseString(input_manifest) @@ -253,8 +265,8 @@ class AddLoggingParentTest(unittest.TestCase): attrs = '' if logging_parent: meta_text = ('<meta-data android:name="android.content.pm.LOGGING_PARENT" ' - 'android:value="%s"/>\n') % (logging_parent) - attrs += ' <application>\n %s </application>\n' % (meta_text) + 'android:value="%s"/>\n') % logging_parent + attrs += ' <application>\n %s </application>\n' % meta_text return attrs @@ -277,7 +289,7 @@ class AddUsesLibrariesTest(unittest.TestCase): """Unit tests for add_uses_libraries function.""" def assert_xml_equal(self, output, expected): - self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected)) def run_test(self, input_manifest, new_uses_libraries): doc = minidom.parseString(input_manifest) @@ -289,18 +301,16 @@ class AddUsesLibrariesTest(unittest.TestCase): manifest_tmpl = ( '<?xml version="1.0" encoding="utf-8"?>\n' '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n' - ' <application>\n' '%s' - ' </application>\n' '</manifest>\n') def uses_libraries(self, name_required_pairs): - ret = '' + ret = ' <application>\n' for name, required in name_required_pairs: ret += ( ' <uses-library android:name="%s" android:required="%s"/>\n' ) % (name, required) - + ret += ' </application>\n' return ret def test_empty(self): @@ -361,12 +371,23 @@ class AddUsesLibrariesTest(unittest.TestCase): output = self.run_test(manifest_input, ['foo', 'bar']) self.assert_xml_equal(output, expected) + def test_multiple_application(self): + """When there are multiple applications, the libs are added to each.""" + manifest_input = self.manifest_tmpl % ( + self.uses_libraries([('foo', 'false')]) + + self.uses_libraries([('bar', 'false')])) + expected = self.manifest_tmpl % ( + self.uses_libraries([('foo', 'false'), ('bar', 'true')]) + + self.uses_libraries([('bar', 'false'), ('foo', 'true')])) + output = self.run_test(manifest_input, ['foo', 'bar']) + self.assert_xml_equal(output, expected) + class AddUsesNonSdkApiTest(unittest.TestCase): """Unit tests for add_uses_libraries function.""" def assert_xml_equal(self, output, expected): - self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected)) def run_test(self, input_manifest): doc = minidom.parseString(input_manifest) @@ -378,11 +399,11 @@ class AddUsesNonSdkApiTest(unittest.TestCase): manifest_tmpl = ( '<?xml version="1.0" encoding="utf-8"?>\n' '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n' - ' <application%s/>\n' + ' %s\n' '</manifest>\n') def uses_non_sdk_api(self, value): - return ' android:usesNonSdkApi="true"' if value else '' + return '<application %s/>' % ('android:usesNonSdkApi="true"' if value else '') def test_set_true(self): """Empty new_uses_libraries must not touch the manifest.""" @@ -398,12 +419,19 @@ class AddUsesNonSdkApiTest(unittest.TestCase): output = self.run_test(manifest_input) self.assert_xml_equal(output, expected) + def test_multiple_applications(self): + """new_uses_libraries must be added to all applications.""" + manifest_input = self.manifest_tmpl % (self.uses_non_sdk_api(True) + self.uses_non_sdk_api(False)) + expected = self.manifest_tmpl % (self.uses_non_sdk_api(True) + self.uses_non_sdk_api(True)) + output = self.run_test(manifest_input) + self.assert_xml_equal(output, expected) + class UseEmbeddedDexTest(unittest.TestCase): """Unit tests for add_use_embedded_dex function.""" def assert_xml_equal(self, output, expected): - self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected)) def run_test(self, input_manifest): doc = minidom.parseString(input_manifest) @@ -415,14 +443,14 @@ class UseEmbeddedDexTest(unittest.TestCase): manifest_tmpl = ( '<?xml version="1.0" encoding="utf-8"?>\n' '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n' - ' <application%s/>\n' + ' %s\n' '</manifest>\n') def use_embedded_dex(self, value): - return ' android:useEmbeddedDex="%s"' % value + return '<application android:useEmbeddedDex="%s" />' % value def test_manifest_with_undeclared_preference(self): - manifest_input = self.manifest_tmpl % '' + manifest_input = self.manifest_tmpl % '<application/>' expected = self.manifest_tmpl % self.use_embedded_dex('true') output = self.run_test(manifest_input) self.assert_xml_equal(output, expected) @@ -437,12 +465,24 @@ class UseEmbeddedDexTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.use_embedded_dex('false') self.assertRaises(RuntimeError, self.run_test, manifest_input) + def test_multiple_applications(self): + manifest_input = self.manifest_tmpl % ( + self.use_embedded_dex('true') + + '<application/>' + ) + expected = self.manifest_tmpl % ( + self.use_embedded_dex('true') + + self.use_embedded_dex('true') + ) + output = self.run_test(manifest_input) + self.assert_xml_equal(output, expected) + class AddExtractNativeLibsTest(unittest.TestCase): """Unit tests for add_extract_native_libs function.""" def assert_xml_equal(self, output, expected): - self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected)) def run_test(self, input_manifest, value): doc = minidom.parseString(input_manifest) @@ -454,20 +494,20 @@ class AddExtractNativeLibsTest(unittest.TestCase): manifest_tmpl = ( '<?xml version="1.0" encoding="utf-8"?>\n' '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n' - ' <application%s/>\n' + ' %s\n' '</manifest>\n') def extract_native_libs(self, value): - return ' android:extractNativeLibs="%s"' % value + return '<application android:extractNativeLibs="%s" />' % value def test_set_true(self): - manifest_input = self.manifest_tmpl % '' + manifest_input = self.manifest_tmpl % '<application/>' expected = self.manifest_tmpl % self.extract_native_libs('true') output = self.run_test(manifest_input, True) self.assert_xml_equal(output, expected) def test_set_false(self): - manifest_input = self.manifest_tmpl % '' + manifest_input = self.manifest_tmpl % '<application/>' expected = self.manifest_tmpl % self.extract_native_libs('false') output = self.run_test(manifest_input, False) self.assert_xml_equal(output, expected) @@ -482,12 +522,18 @@ class AddExtractNativeLibsTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.extract_native_libs('true') self.assertRaises(RuntimeError, self.run_test, manifest_input, False) + def test_multiple_applications(self): + manifest_input = self.manifest_tmpl % (self.extract_native_libs('true') + '<application/>') + expected = self.manifest_tmpl % (self.extract_native_libs('true') + self.extract_native_libs('true')) + output = self.run_test(manifest_input, True) + self.assert_xml_equal(output, expected) + class AddNoCodeApplicationTest(unittest.TestCase): """Unit tests for set_has_code_to_false function.""" def assert_xml_equal(self, output, expected): - self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected)) def run_test(self, input_manifest): doc = minidom.parseString(input_manifest) @@ -515,7 +561,7 @@ class AddNoCodeApplicationTest(unittest.TestCase): self.assert_xml_equal(output, expected) def test_has_application_has_code_false(self): - """ Do nothing if there's already an application elemeent. """ + """ Do nothing if there's already an application element. """ manifest_input = self.manifest_tmpl % ' <application android:hasCode="false"/>\n' output = self.run_test(manifest_input) self.assert_xml_equal(output, manifest_input) @@ -527,12 +573,25 @@ class AddNoCodeApplicationTest(unittest.TestCase): output = self.run_test(manifest_input) self.assert_xml_equal(output, manifest_input) + def test_multiple_applications(self): + """ Apply to all applications """ + manifest_input = self.manifest_tmpl % ( + ' <application android:hasCode="true" />\n' + + ' <application android:hasCode="false" />\n' + + ' <application/>\n') + expected = self.manifest_tmpl % ( + ' <application android:hasCode="true" />\n' + + ' <application android:hasCode="false" />\n' + + ' <application android:hasCode="false" />\n') + output = self.run_test(manifest_input) + self.assert_xml_equal(output, expected) + class AddTestOnlyApplicationTest(unittest.TestCase): """Unit tests for set_test_only_flag_to_true function.""" def assert_xml_equal(self, output, expected): - self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected)) def run_test(self, input_manifest): doc = minidom.parseString(input_manifest) @@ -571,12 +630,26 @@ class AddTestOnlyApplicationTest(unittest.TestCase): output = self.run_test(manifest_input) self.assert_xml_equal(output, manifest_input) + def test_multiple_applications(self): + manifest_input = self.manifest_tmpl % ( + ' <application android:testOnly="true" />\n' + + ' <application android:testOnly="false" />\n' + + ' <application/>\n' + ) + expected = self.manifest_tmpl % ( + ' <application android:testOnly="true" />\n' + + ' <application android:testOnly="false" />\n' + + ' <application android:testOnly="true" />\n' + ) + output = self.run_test(manifest_input) + self.assert_xml_equal(output, expected) + class SetMaxSdkVersionTest(unittest.TestCase): """Unit tests for set_max_sdk_version function.""" def assert_xml_equal(self, output, expected): - self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected)) def run_test(self, input_manifest, max_sdk_version): doc = minidom.parseString(input_manifest) @@ -591,15 +664,15 @@ class SetMaxSdkVersionTest(unittest.TestCase): '%s' '</manifest>\n') - def permission(self, max=None): - if max is None: + def permission(self, max_sdk=None): + if max_sdk is None: return ' <permission/>' - return ' <permission android:maxSdkVersion="%s"/>\n' % max + return ' <permission android:maxSdkVersion="%s"/>\n' % max_sdk - def uses_permission(self, max=None): - if max is None: + def uses_permission(self, max_sdk=None): + if max_sdk is None: return ' <uses-permission/>' - return ' <uses-permission android:maxSdkVersion="%s"/>\n' % max + return ' <uses-permission android:maxSdkVersion="%s"/>\n' % max_sdk def test_permission_no_max_sdk_version(self): """Tests if permission has no maxSdkVersion attribute""" @@ -643,11 +716,12 @@ class SetMaxSdkVersionTest(unittest.TestCase): output = self.run_test(manifest_input, '9000') self.assert_xml_equal(output, expected) + class OverrideDefaultVersionTest(unittest.TestCase): """Unit tests for override_default_version function.""" def assert_xml_equal(self, output, expected): - self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + self.assertEqual(ElementTree.canonicalize(output), ElementTree.canonicalize(expected)) def run_test(self, input_manifest, version): doc = minidom.parseString(input_manifest) diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index 0fb5c70d2..09a7c9e8c 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -1703,61 +1703,6 @@ java_sdk_library_import { ) } -func TestSnapshotWithJavaSdkLibrary_NamingScheme(t *testing.T) { - result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, ` - sdk { - name: "mysdk", - java_sdk_libs: ["myjavalib"], - } - - java_sdk_library { - name: "myjavalib", - apex_available: ["//apex_available:anyapex"], - srcs: ["Test.java"], - sdk_version: "current", - naming_scheme: "default", - public: { - enabled: true, - }, - } - `) - - CheckSnapshot(t, result, "mysdk", "", - checkAndroidBpContents(` -// This is auto-generated. DO NOT EDIT. - -apex_contributions_defaults { - name: "mysdk.contributions", - contents: ["prebuilt_myjavalib"], -} - -java_sdk_library_import { - name: "myjavalib", - prefer: false, - visibility: ["//visibility:public"], - apex_available: ["//apex_available:anyapex"], - naming_scheme: "default", - shared_library: true, - public: { - jars: ["sdk_library/public/myjavalib-stubs.jar"], - stub_srcs: ["sdk_library/public/myjavalib_stub_sources"], - current_api: "sdk_library/public/myjavalib.txt", - removed_api: "sdk_library/public/myjavalib-removed.txt", - sdk_version: "current", - }, -} -`), - checkAllCopyRules(` -.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar -.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt -.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt -`), - checkMergeZips( - ".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip", - ), - ) -} - func TestSnapshotWithJavaSdkLibrary_DoctagFiles(t *testing.T) { result := android.GroupFixturePreparers( prepareForSdkTestWithJavaSdkLibrary, diff --git a/sdk/sdk.go b/sdk/sdk.go index 2fb3a3f30..aa82abbb4 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -84,20 +84,6 @@ type sdkProperties struct { // True if this is a module_exports (or module_exports_snapshot) module type. Module_exports bool `blueprint:"mutated"` - - // The additional visibility to add to the prebuilt modules to allow them to - // reference each other. - // - // This can only be used to widen the visibility of the members: - // - // * Specifying //visibility:public here will make all members visible and - // essentially ignore their own visibility. - // * Specifying //visibility:private here is an error. - // * Specifying any other rule here will add it to the members visibility and - // be output to the member prebuilt in the snapshot. Duplicates will be - // dropped. Adding a rule to members that have //visibility:private will - // cause the //visibility:private to be discarded. - Prebuilt_visibility []string } // sdk defines an SDK which is a logical group of modules (e.g. native libs, headers, java libs, etc.) @@ -130,8 +116,6 @@ func newSdkModule(moduleExports bool) *sdk { s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties, &traitsWrapper) - // Make sure that the prebuilt visibility property is verified for errors. - android.AddVisibilityProperty(s, "prebuilt_visibility", &s.properties.Prebuilt_visibility) android.InitCommonOSAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon) android.InitDefaultableModule(s) android.AddLoadHook(s, func(ctx android.LoadHookContext) { diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index 416dce62c..2532a2581 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -53,9 +53,6 @@ func TestSnapshotVisibility(t *testing.T) { // generated sdk_snapshot. ":__subpackages__", ], - prebuilt_visibility: [ - "//prebuilts/mysdk", - ], java_header_libs: [ "myjavalib", "mypublicjavalib", @@ -162,18 +159,6 @@ java_import { `)) } -func TestPrebuiltVisibilityProperty_IsValidated(t *testing.T) { - testSdkError(t, `prebuilt_visibility: cannot mix "//visibility:private" with any other visibility rules`, ` - sdk { - name: "mysdk", - prebuilt_visibility: [ - "//foo", - "//visibility:private", - ], - } -`) -} - func TestSdkInstall(t *testing.T) { sdk := ` sdk { diff --git a/sdk/update.go b/sdk/update.go index 93bb861e9..7f4f80a34 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -22,7 +22,6 @@ import ( "sort" "strings" - "android/soong/apex" "android/soong/cc" "android/soong/java" @@ -1137,9 +1136,6 @@ func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType apexAvailable = []string{android.AvailableToPlatform} } - // Add in any baseline apex available settings. - apexAvailable = append(apexAvailable, apex.BaselineApexAvailable(member.Name())...) - // Remove duplicates and sort. apexAvailable = android.FirstUniqueStrings(apexAvailable) sort.Strings(apexAvailable) @@ -1993,14 +1989,6 @@ func (m *memberContext) IsTargetBuildBeforeTiramisu() bool { return m.builder.targetBuildRelease.EarlierThan(buildReleaseT) } -func (m *memberContext) Config() android.Config { - return m.sdkMemberContext.Config() -} - -func (m *memberContext) OtherModulePropertyErrorf(module android.Module, property string, fmt string, args ...interface{}) { - m.sdkMemberContext.OtherModulePropertyErrorf(module, property, fmt, args) -} - var _ android.SdkMemberContext = (*memberContext)(nil) func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) { diff --git a/tests/build_action_caching_test.sh b/tests/build_action_caching_test.sh new file mode 100755 index 000000000..981827d6f --- /dev/null +++ b/tests/build_action_caching_test.sh @@ -0,0 +1,110 @@ +#!/bin/bash -u + +set -o pipefail + +# Test that the mk and ninja files generated by Soong don't change if some +# incremental modules are restored from cache. + +OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)" +echo ${OUTPUT_DIR} + +function cleanup { + rm -rf "${OUTPUT_DIR}" +} +trap cleanup EXIT + +function run_soong_build { + USE_RBE=false TARGET_PRODUCT=aosp_arm TARGET_RELEASE=trunk_staging TARGET_BUILD_VARIANT=userdebug build/soong/soong_ui.bash --make-mode --incremental-build-actions nothing +} + +function run_soong_clean { + build/soong/soong_ui.bash --make-mode clean +} + +function assert_files_equal { + if [ $# -ne 2 ]; then + echo "Usage: assert_files_equal file1 file2" + exit 1 + fi + + if ! cmp -s "$1" "$2"; then + echo "Files are different: $1 $2" + exit 1 + fi +} + +function compare_mtimes() { + if [ $# -ne 2 ]; then + echo "Usage: compare_mtimes file1 file2" + exit 1 + fi + + file1_mtime=$(stat -c '%Y' $1) + file2_mtime=$(stat -c '%Y' $2) + + if [ "$file1_mtime" -eq "$file2_mtime" ]; then + return 1 + else + return 0 + fi +} + +function test_build_action_restoring() { + run_soong_clean + cat > ${OUTPUT_DIR}/Android.bp <<'EOF' +python_binary_host { + name: "my_little_binary_host", + srcs: ["my_little_binary_host.py"], +} +EOF + touch ${OUTPUT_DIR}/my_little_binary_host.py + run_soong_build + mkdir -p "${OUTPUT_DIR}/before" + cp -pr out/soong/build_aosp_arm_ninja_incremental out/soong/*.mk out/soong/build.aosp_arm.*.ninja ${OUTPUT_DIR}/before + # add a comment to the bp file, this should force a new analysis but no module + # should be really impacted, so all the incremental modules should be skipped. + cat >> ${OUTPUT_DIR}/Android.bp <<'EOF' +// new comments +EOF + run_soong_build + mkdir -p "${OUTPUT_DIR}/after" + cp -pr out/soong/build_aosp_arm_ninja_incremental out/soong/*.mk out/soong/build.aosp_arm.*.ninja ${OUTPUT_DIR}/after + + compare_files +} + +function compare_files() { + for file_before in ${OUTPUT_DIR}/before/*.ninja; do + file_after="${OUTPUT_DIR}/after/$(basename "$file_before")" + assert_files_equal $file_before $file_after + compare_mtimes $file_before $file_after + if [ $? -ne 0 ]; then + echo "Files have identical mtime: $file_before $file_after" + exit 1 + fi + done + + for file_before in ${OUTPUT_DIR}/before/*.mk; do + file_after="${OUTPUT_DIR}/after/$(basename "$file_before")" + assert_files_equal $file_before $file_after + compare_mtimes $file_before $file_after + # mk files shouldn't be regenerated + if [ $? -ne 1 ]; then + echo "Files have different mtimes: $file_before $file_after" + exit 1 + fi + done + + for file_before in ${OUTPUT_DIR}/before/build_aosp_arm_ninja_incremental/*.ninja; do + file_after="${OUTPUT_DIR}/after/build_aosp_arm_ninja_incremental/$(basename "$file_before")" + assert_files_equal $file_before $file_after + compare_mtimes $file_before $file_after + # ninja files of skipped modules shouldn't be regenerated + if [ $? -ne 1 ]; then + echo "Files have different mtimes: $file_before $file_after" + exit 1 + fi + done +} + +test_build_action_restoring diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go index 2bad5a88f..2ec897273 100644 --- a/ui/build/androidmk_denylist.go +++ b/ui/build/androidmk_denylist.go @@ -25,6 +25,8 @@ var androidmk_denylist []string = []string{ "dalvik/", "developers/", "development/", + "device/common/", + "device/google_car/", "device/sample/", "frameworks/", // Do not block other directories in kernel/, see b/319658303. @@ -41,6 +43,15 @@ var androidmk_denylist []string = []string{ "trusty/", // Add back toolchain/ once defensive Android.mk files are removed //"toolchain/", + "vendor/google_contexthub/", + "vendor/google_data/", + "vendor/google_elmyra/", + "vendor/google_mhl/", + "vendor/google_pdk/", + "vendor/google_testing/", + "vendor/partner_testing/", + "vendor/partner_tools/", + "vendor/pdk/", } func blockAndroidMks(ctx Context, androidMks []string) { diff --git a/ui/build/config.go b/ui/build/config.go index f02222e1a..851a22ae1 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -54,6 +54,16 @@ func init() { rbeRandPrefix = rand.Intn(1000) } +// Which builder are we using? +type ninjaCommandType = int + +const ( + _ = iota + NINJA_NINJA + NINJA_N2 + NINJA_SISO +) + type Config struct{ *configImpl } type configImpl struct { @@ -123,9 +133,8 @@ type configImpl struct { // could consider merging them. moduleDebugFile string - // Whether to use n2 instead of ninja. This is controlled with the - // environment variable SOONG_USE_N2 - useN2 bool + // Which builder are we using + ninjaCommand ninjaCommandType } type NinjaWeightListSource uint @@ -288,8 +297,16 @@ func NewConfig(ctx Context, args ...string) Config { ret.moduleDebugFile, _ = filepath.Abs(shared.JoinPath(ret.SoongOutDir(), "soong-debug-info.json")) } - if os.Getenv("SOONG_USE_N2") == "true" { - ret.useN2 = true + ret.ninjaCommand = NINJA_NINJA + switch os.Getenv("SOONG_NINJA") { + case "n2": + ret.ninjaCommand = NINJA_N2 + case "siso": + ret.ninjaCommand = NINJA_SISO + default: + if os.Getenv("SOONG_USE_N2") == "true" { + ret.ninjaCommand = NINJA_N2 + } } ret.environ.Unset( @@ -349,7 +366,8 @@ func NewConfig(ctx Context, args ...string) Config { // We read it here already, don't let others share in the fun "GENERATE_SOONG_DEBUG", - // Use config.useN2 instead. + // Use config.ninjaCommand instead. + "SOONG_NINJA", "SOONG_USE_N2", ) @@ -1375,8 +1393,10 @@ func (c *configImpl) shouldCleanupRBELogsDir() bool { // Perform a log directory cleanup only when the log directory // is auto created by the build rather than user-specified. for _, f := range []string{"RBE_proxy_log_dir", "FLAG_output_dir"} { - if _, ok := c.environ.Get(f); ok { - return false + if v, ok := c.environ.Get(f); ok { + if v != c.rbeTmpDir() { + return false + } } } return true @@ -1641,6 +1661,12 @@ func (c *configImpl) N2Bin() string { return strings.ReplaceAll(path, "/linux-x86/", "/linux_musl-x86/") } +func (c *configImpl) SisoBin() string { + path := c.PrebuiltBuildTool("siso") + // Use musl instead of glibc because glibc on the build server is old and has bugs + return strings.ReplaceAll(path, "/linux-x86/", "/linux_musl-x86/") +} + func (c *configImpl) PrebuiltBuildTool(name string) string { if v, ok := c.environ.Get("SANITIZE_HOST"); ok { if sanitize := strings.Fields(v); inList("address", sanitize) { diff --git a/ui/build/ninja.go b/ui/build/ninja.go index 4e3e54443..def0783a2 100644 --- a/ui/build/ninja.go +++ b/ui/build/ninja.go @@ -49,14 +49,10 @@ func runNinjaForBuild(ctx Context, config Config) { nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo) defer nr.Close() - executable := config.NinjaBin() - args := []string{ - "-d", "keepdepfile", - "-d", "keeprsp", - "-d", "stats", - "--frontend_file", fifo, - } - if config.useN2 { + var executable string + var args []string + switch config.ninjaCommand { + case NINJA_N2: executable = config.N2Bin() args = []string{ "-d", "trace", @@ -66,8 +62,31 @@ func runNinjaForBuild(ctx Context, config Config) { //"-d", "stats", "--frontend-file", fifo, } + case NINJA_SISO: + executable = config.SisoBin() + args = []string{ + "ninja", + "--log_dir", config.SoongOutDir(), + // TODO: implement these features, or remove them. + //"-d", "trace", + //"-d", "keepdepfile", + //"-d", "keeprsp", + //"-d", "stats", + //"--frontend-file", fifo, + } + default: + // NINJA_NINJA is the default. + executable = config.NinjaBin() + args = []string{ + "-d", "keepdepfile", + "-d", "keeprsp", + "-d", "stats", + "--frontend_file", fifo, + "-o", "usesphonyoutputs=yes", + "-w", "dupbuild=err", + "-w", "missingdepfile=err", + } } - args = append(args, config.NinjaArgs()...) var parallel int @@ -83,17 +102,10 @@ func runNinjaForBuild(ctx Context, config Config) { args = append(args, "-f", config.CombinedNinjaFile()) - if !config.useN2 { - args = append(args, - "-o", "usesphonyoutputs=yes", - "-w", "dupbuild=err", - "-w", "missingdepfile=err") - } - if !config.BuildBrokenMissingOutputs() { // Missing outputs will be treated as errors. // BUILD_BROKEN_MISSING_OUTPUTS can be used to bypass this check. - if !config.useN2 { + if config.ninjaCommand != NINJA_N2 { args = append(args, "-w", "missingoutfile=err", ) @@ -110,21 +122,18 @@ func runNinjaForBuild(ctx Context, config Config) { cmd.Environment.AppendFromKati(config.KatiEnvFile()) } - switch config.NinjaWeightListSource() { - case NINJA_LOG: - if !config.useN2 { + // TODO(b/346806126): implement this for the other ninjaCommand values. + if config.ninjaCommand == NINJA_NINJA { + switch config.NinjaWeightListSource() { + case NINJA_LOG: cmd.Args = append(cmd.Args, "-o", "usesninjalogasweightlist=yes") - } - case EVENLY_DISTRIBUTED: - // pass empty weight list means ninja considers every tasks's weight as 1(default value). - if !config.useN2 { + case EVENLY_DISTRIBUTED: + // pass empty weight list means ninja considers every tasks's weight as 1(default value). cmd.Args = append(cmd.Args, "-o", "usesweightlist=/dev/null") - } - case EXTERNAL_FILE: - fallthrough - case HINT_FROM_SOONG: - // The weight list is already copied/generated. - if !config.useN2 { + case EXTERNAL_FILE: + fallthrough + case HINT_FROM_SOONG: + // The weight list is already copied/generated. ninjaWeightListPath := filepath.Join(config.OutDir(), ninjaWeightListFileName) cmd.Args = append(cmd.Args, "-o", "usesweightlist="+ninjaWeightListPath) } @@ -227,6 +236,8 @@ func runNinjaForBuild(ctx Context, config Config) { // We don't want this build broken flag to cause reanalysis, so allow it through to the // actions. "BUILD_BROKEN_INCORRECT_PARTITION_IMAGES", + // Do not do reanalysis just because we changed ninja commands. + "SOONG_NINJA", "SOONG_USE_N2", "RUST_BACKTRACE", "RUST_LOG", @@ -235,8 +246,11 @@ func runNinjaForBuild(ctx Context, config Config) { cmd.Environment.Set("DIST_DIR", config.DistDir()) cmd.Environment.Set("SHELL", "/bin/bash") - if config.useN2 { + switch config.ninjaCommand { + case NINJA_N2: cmd.Environment.Set("RUST_BACKTRACE", "1") + default: + // Only set RUST_BACKTRACE for n2. } // Print the environment variables that Ninja is operating in. diff --git a/ui/build/soong.go b/ui/build/soong.go index 97bc9971e..eb51022af 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -588,19 +588,11 @@ func runSoong(ctx Context, config Config) { nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo) defer nr.Close() - ninjaArgs := []string{ - "-d", "keepdepfile", - "-d", "stats", - "-o", "usesphonyoutputs=yes", - "-o", "preremoveoutputs=yes", - "-w", "dupbuild=err", - "-w", "outputdir=err", - "-w", "missingoutfile=err", - "-j", strconv.Itoa(config.Parallel()), - "--frontend_file", fifo, - "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"), - } - if config.useN2 { + var ninjaCmd string + var ninjaArgs []string + switch config.ninjaCommand { + case NINJA_N2: + ninjaCmd = config.N2Bin() ninjaArgs = []string{ // TODO: implement these features, or remove them. //"-d", "keepdepfile", @@ -615,6 +607,39 @@ func runSoong(ctx Context, config Config) { "--frontend-file", fifo, "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"), } + case NINJA_SISO: + ninjaCmd = config.SisoBin() + ninjaArgs = []string{ + "ninja", + // TODO: implement these features, or remove them. + //"-d", "keepdepfile", + //"-d", "stats", + //"-o", "usesphonyoutputs=yes", + //"-o", "preremoveoutputs=yes", + //"-w", "dupbuild=err", + //"-w", "outputdir=err", + //"-w", "missingoutfile=err", + "-v", + "-j", strconv.Itoa(config.Parallel()), + //"--frontend-file", fifo, + "--log_dir", config.SoongOutDir(), + "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"), + } + default: + // NINJA_NINJA is the default. + ninjaCmd = config.NinjaBin() + ninjaArgs = []string{ + "-d", "keepdepfile", + "-d", "stats", + "-o", "usesphonyoutputs=yes", + "-o", "preremoveoutputs=yes", + "-w", "dupbuild=err", + "-w", "outputdir=err", + "-w", "missingoutfile=err", + "-j", strconv.Itoa(config.Parallel()), + "--frontend_file", fifo, + "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"), + } } if extra, ok := config.Environment().Get("SOONG_UI_NINJA_ARGS"); ok { @@ -623,10 +648,6 @@ func runSoong(ctx Context, config Config) { } ninjaArgs = append(ninjaArgs, targets...) - ninjaCmd := config.NinjaBin() - if config.useN2 { - ninjaCmd = config.N2Bin() - } cmd := Command(ctx, config, "soong bootstrap", ninjaCmd, ninjaArgs...) |