diff options
73 files changed, 3014 insertions, 584 deletions
diff --git a/android/Android.bp b/android/Android.bp index f3a385025..6450a06ca 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -110,6 +110,7 @@ bootstrap_go_package { "paths_test.go", "prebuilt_test.go", "rule_builder_test.go", + "sdk_test.go", "singleton_module_test.go", "soong_config_modules_test.go", "util_test.go", diff --git a/android/arch.go b/android/arch.go index ddc082b00..6add1b132 100644 --- a/android/arch.go +++ b/android/arch.go @@ -934,6 +934,8 @@ func filterArchStruct(field reflect.StructField, prefix string) (bool, reflect.S if len(values) > 0 && values[0] != "path" { panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name)) } else if len(values) == 1 { + // FIXME(b/200678898): This assumes that the only tag type when there's + // `android:"arch_variant"` is `android` itself and thus clobbers others field.Tag = reflect.StructTag(`android:"` + strings.Join(values, ",") + `"`) } else { field.Tag = `` diff --git a/android/bazel.go b/android/bazel.go index bfd0f909a..962a8f0eb 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -218,25 +218,14 @@ var ( "libc_ndk", // http://b/187013218, cc_library_static, depends on //bionic/libm:libm (http://b/183064661) "libc_malloc_hooks", // http://b/187016307, cc_library, ld.lld: error: undefined symbol: __malloc_hook - // There are unexported symbols that don't surface on a shared library build, - // from the source static archive - // e.g. _Unwind_{GetRegionStart,GetLanguageSpecificData,GetIP,Set{IP,GR},Resume,{Raise,Delete}Exception}, pthread_atfork - // ... from: cxa_{personality,exception}.o, system_error.o, wrappers_c_bionic.o - // cf. http://b/198403271 - "libc++", - // http://b/186823769: Needs C++ STL support, includes from unconverted standard libraries in //external/libcxx // c++_static "libbase_ndk", // http://b/186826477, cc_library, no such target '//build/bazel/platforms/os:darwin' when --platforms //build/bazel/platforms:android_x86 is added // libcxx "libBionicBenchmarksUtils", // cc_library_static, fatal error: 'map' file not found, from libcxx - "fmtlib", // cc_library_static, fatal error: 'cassert' file not found, from libcxx - "fmtlib_ndk", // cc_library_static, fatal error: 'cassert' file not found - "liblog", // http://b/186822772: cc_library, 'sys/cdefs.h' file not found - "libbase", // Requires liblog. http://b/186826479, cc_library, fatal error: 'memory' file not found, from libcxx. - // Also depends on fmtlib. + "libbase", // Depends on fmtlib via static_libs and also whole_static_libs, which results in bazel errors. - "libfdtrack", // depends on STL + "libfdtrack", // depends on liblzma and libbase "libseccomp_policy", // depends on libbase @@ -271,12 +260,11 @@ var ( // Per-module denylist to opt modules out of mixed builds. Such modules will // still be generated via bp2build. mixedBuildsDisabledList = []string{ - "libbrotli", // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy - "libc++fs", // http://b/198403271, Missing symbols/members in the global namespace when referenced from headers in //external/libcxx/includes - "libc++_experimental", // http://b/198403271, Missing symbols/members in the global namespace when referenced from headers in //external/libcxx/includes - "libc++_static", // http://b/198403271, Missing symbols/members in the global namespace when referenced from headers in //external/libcxx/includes - "libc++abi", // http://b/195970501, cc_library_static, duplicate symbols because it propagates libc objects. - "libc++demangle", // http://b/195970501, cc_library_static, duplicate symbols because it propagates libc objects. + "libbrotli", // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy + "func_to_syscall_nrs", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module. + "libseccomp_policy_app_zygote_sources", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module. + "libseccomp_policy_app_sources", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module. + "libseccomp_policy_system_sources", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module. } // Used for quicker lookups diff --git a/android/bazel_handler.go b/android/bazel_handler.go index 50b79fa15..22412553c 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -809,7 +809,16 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) { cmd := rule.Command() // cd into Bazel's execution root, which is the action cwd. - cmd.Text(fmt.Sprintf("cd %s/execroot/__main__ && ", ctx.Config().BazelContext.OutputBase())) + cmd.Text(fmt.Sprintf("cd %s/execroot/__main__ &&", ctx.Config().BazelContext.OutputBase())) + + // Remove old outputs, as some actions might not rerun if the outputs are detected. + if len(buildStatement.OutputPaths) > 0 { + cmd.Text("rm -f") + for _, outputPath := range buildStatement.OutputPaths { + cmd.Text(PathForBazelOut(ctx, outputPath).String()) + } + cmd.Text("&&") + } for _, pair := range buildStatement.Env { // Set per-action env variables, if any. diff --git a/android/deapexer.go b/android/deapexer.go index 9290481d4..bed657464 100644 --- a/android/deapexer.go +++ b/android/deapexer.go @@ -69,6 +69,8 @@ import ( // The information exported by the `deapexer` module, access it using `DeapxerInfoProvider`. type DeapexerInfo struct { + apexModuleName string + // map from the name of an exported file from a prebuilt_apex to the path to that file. The // exported file name is the apex relative path, e.g. javalib/core-libart.jar. // @@ -76,6 +78,11 @@ type DeapexerInfo struct { exports map[string]WritablePath } +// ApexModuleName returns the name of the APEX module that provided the info. +func (i DeapexerInfo) ApexModuleName() string { + return i.apexModuleName +} + // PrebuiltExportPath provides the path, or nil if not available, of a file exported from the // prebuilt_apex that created this ApexInfo. // @@ -95,9 +102,10 @@ var DeapexerProvider = blueprint.NewProvider(DeapexerInfo{}) // for use with a prebuilt_apex module. // // See apex/deapexer.go for more information. -func NewDeapexerInfo(exports map[string]WritablePath) DeapexerInfo { +func NewDeapexerInfo(apexModuleName string, exports map[string]WritablePath) DeapexerInfo { return DeapexerInfo{ - exports: exports, + apexModuleName: apexModuleName, + exports: exports, } } @@ -133,3 +141,20 @@ type RequiresFilesFromPrebuiltApexTag interface { // Method that differentiates this interface from others. RequiresFilesFromPrebuiltApex() } + +// FindDeapexerProviderForModule searches through the direct dependencies of the current context +// module for a DeapexerTag dependency and returns its DeapexerInfo. If there is an error then it is +// reported with ctx.ModuleErrorf and nil is returned. +func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo { + var di *DeapexerInfo + ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) { + p := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo) + di = &p + }) + if di != nil { + return di + } + ai := ctx.Provider(ApexInfoProvider).(ApexInfo) + ctx.ModuleErrorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName) + return nil +} diff --git a/android/module.go b/android/module.go index 280345576..c9b01a00a 100644 --- a/android/module.go +++ b/android/module.go @@ -15,7 +15,6 @@ package android import ( - "android/soong/bazel" "fmt" "os" "path" @@ -24,6 +23,8 @@ import ( "strings" "text/scanner" + "android/soong/bazel" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -468,6 +469,14 @@ type Module interface { Enabled() bool Target() Target MultiTargets() []Target + + // ImageVariation returns the image variation of this module. + // + // The returned structure has its Mutator field set to "image" and its Variation field set to the + // image variation, e.g. recovery, ramdisk, etc.. The Variation field is "" for host modules and + // device modules that have no image variation. + ImageVariation() blueprint.Variation + Owner() string InstallInData() bool InstallInTestcases() bool diff --git a/android/neverallow.go b/android/neverallow.go index 19b58a775..a91d523b1 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -152,7 +152,7 @@ func createJavaDeviceForHostRules() []Rule { javaDeviceForHostProjectsAllowedList := []string{ "external/guava", "external/robolectric-shadows", - "framework/layoutlib", + "frameworks/layoutlib", } return []Rule{ diff --git a/android/sdk.go b/android/sdk.go index 100f63b0e..1d63d7a94 100644 --- a/android/sdk.go +++ b/android/sdk.go @@ -15,6 +15,7 @@ package android import ( + "fmt" "sort" "strings" @@ -376,6 +377,224 @@ func (b BpPrintableBase) bpPrintable() { var _ BpPrintable = BpPrintableBase{} +// sdkRegisterable defines the interface that must be implemented by objects that can be registered +// in an sdkRegistry. +type sdkRegisterable interface { + // SdkPropertyName returns the name of the corresponding property on an sdk module. + SdkPropertyName() string +} + +// sdkRegistry provides support for registering and retrieving objects that define properties for +// use by sdk and module_exports module types. +type sdkRegistry struct { + // The list of registered objects sorted by property name. + list []sdkRegisterable +} + +// copyAndAppend creates a new sdkRegistry that includes all the traits registered in +// this registry plus the supplied trait. +func (r *sdkRegistry) copyAndAppend(registerable sdkRegisterable) *sdkRegistry { + oldList := r.list + + // Make sure that list does not already contain the property. Uses a simple linear search instead + // of a binary search even though the list is sorted. That is because the number of items in the + // list is small and so not worth the overhead of a binary search. + found := false + newPropertyName := registerable.SdkPropertyName() + for _, r := range oldList { + if r.SdkPropertyName() == newPropertyName { + found = true + break + } + } + if found { + names := []string{} + for _, r := range oldList { + names = append(names, r.SdkPropertyName()) + } + panic(fmt.Errorf("duplicate properties found, %q already exists in %q", newPropertyName, names)) + } + + // Copy the slice just in case this is being read while being modified, e.g. when testing. + list := make([]sdkRegisterable, 0, len(oldList)+1) + list = append(list, oldList...) + list = append(list, registerable) + + // Sort the registered objects by their property name to ensure that registry order has no effect + // on behavior. + sort.Slice(list, func(i1, i2 int) bool { + t1 := list[i1] + t2 := list[i2] + + return t1.SdkPropertyName() < t2.SdkPropertyName() + }) + + // Create a new registry so the pointer uniquely identifies the set of registered types. + return &sdkRegistry{ + list: list, + } +} + +// registeredObjects returns the list of registered instances. +func (r *sdkRegistry) registeredObjects() []sdkRegisterable { + return r.list +} + +// uniqueOnceKey returns a key that uniquely identifies this instance and can be used with +// OncePer.Once +func (r *sdkRegistry) uniqueOnceKey() OnceKey { + // Use the pointer to the registry as the unique key. The pointer is used because it is guaranteed + // to uniquely identify the contained list. The list itself cannot be used as slices are not + // comparable. Using the pointer does mean that two separate registries with identical lists would + // have different keys and so cause whatever information is cached to be created multiple times. + // However, that is not an issue in practice as it should not occur outside tests. Constructing a + // string representation of the list to use instead would avoid that but is an unnecessary + // complication that provides no significant benefit. + return NewCustomOnceKey(r) +} + +// SdkMemberTrait represents a trait that members of an sdk module can contribute to the sdk +// snapshot. +// +// A trait is simply a characteristic of sdk member that is not required by default which may be +// required for some members but not others. Traits can cause additional information to be output +// to the sdk snapshot or replace the default information exported for a member with something else. +// e.g. +// * By default cc libraries only export the default image variants to the SDK. However, for some +// members it may be necessary to export specific image variants, e.g. vendor, or recovery. +// * By default cc libraries export all the configured architecture variants except for the native +// bridge architecture variants. However, for some members it may be necessary to export the +// native bridge architecture variants as well. +// * By default cc libraries export the platform variant (i.e. sdk:). However, for some members it +// may be necessary to export the sdk variant (i.e. sdk:sdk). +// +// A sdk can request a module to provide no traits, one trait or a collection of traits. The exact +// behavior of a trait is determined by how SdkMemberType implementations handle the traits. A trait +// could be specific to one SdkMemberType or many. Some trait combinations could be incompatible. +// +// The sdk module type will create a special traits structure that contains a property for each +// trait registered with RegisterSdkMemberTrait(). The property names are those returned from +// SdkPropertyName(). Each property contains a list of modules that are required to have that trait. +// e.g. something like this: +// +// sdk { +// name: "sdk", +// ... +// traits: { +// recovery_image: ["module1", "module4", "module5"], +// native_bridge: ["module1", "module2"], +// native_sdk: ["module1", "module3"], +// ... +// }, +// ... +// } +type SdkMemberTrait interface { + // SdkPropertyName returns the name of the traits property on an sdk module. + SdkPropertyName() string +} + +var _ sdkRegisterable = (SdkMemberTrait)(nil) + +// SdkMemberTraitBase is the base struct that must be embedded within any type that implements +// SdkMemberTrait. +type SdkMemberTraitBase struct { + // PropertyName is the name of the property + PropertyName string +} + +func (b *SdkMemberTraitBase) SdkPropertyName() string { + return b.PropertyName +} + +// SdkMemberTraitSet is a set of SdkMemberTrait instances. +type SdkMemberTraitSet interface { + // Empty returns true if this set is empty. + Empty() bool + + // Contains returns true if this set contains the specified trait. + Contains(trait SdkMemberTrait) bool + + // Subtract returns a new set containing all elements of this set except for those in the + // other set. + Subtract(other SdkMemberTraitSet) SdkMemberTraitSet + + // String returns a string representation of the set and its contents. + String() string +} + +func NewSdkMemberTraitSet(traits []SdkMemberTrait) SdkMemberTraitSet { + if len(traits) == 0 { + return EmptySdkMemberTraitSet() + } + + m := sdkMemberTraitSet{} + for _, trait := range traits { + m[trait] = true + } + return m +} + +func EmptySdkMemberTraitSet() SdkMemberTraitSet { + return (sdkMemberTraitSet)(nil) +} + +type sdkMemberTraitSet map[SdkMemberTrait]bool + +var _ SdkMemberTraitSet = (sdkMemberTraitSet{}) + +func (s sdkMemberTraitSet) Empty() bool { + return len(s) == 0 +} + +func (s sdkMemberTraitSet) Contains(trait SdkMemberTrait) bool { + return s[trait] +} + +func (s sdkMemberTraitSet) Subtract(other SdkMemberTraitSet) SdkMemberTraitSet { + if other.Empty() { + return s + } + + var remainder []SdkMemberTrait + for trait, _ := range s { + if !other.Contains(trait) { + remainder = append(remainder, trait) + } + } + + return NewSdkMemberTraitSet(remainder) +} + +func (s sdkMemberTraitSet) String() string { + list := []string{} + for trait, _ := range s { + list = append(list, trait.SdkPropertyName()) + } + sort.Strings(list) + return fmt.Sprintf("[%s]", strings.Join(list, ",")) +} + +var registeredSdkMemberTraits = &sdkRegistry{} + +// RegisteredSdkMemberTraits returns a OnceKey and a sorted list of registered traits. +// +// The key uniquely identifies the array of traits and can be used with OncePer.Once() to cache +// information derived from the array of traits. +func RegisteredSdkMemberTraits() (OnceKey, []SdkMemberTrait) { + registerables := registeredSdkMemberTraits.registeredObjects() + traits := make([]SdkMemberTrait, len(registerables)) + for i, registerable := range registerables { + traits[i] = registerable.(SdkMemberTrait) + } + return registeredSdkMemberTraits.uniqueOnceKey(), traits +} + +// RegisterSdkMemberTrait registers an SdkMemberTrait object to allow them to be used in the +// module_exports, module_exports_snapshot, sdk and sdk_snapshot module types. +func RegisterSdkMemberTrait(trait SdkMemberTrait) { + registeredSdkMemberTraits = registeredSdkMemberTraits.copyAndAppend(trait) +} + // SdkMember is an individual member of the SDK. // // It includes all of the variants that the SDK depends upon. @@ -541,12 +760,25 @@ type SdkMemberType interface { // CreateVariantPropertiesStruct creates a structure into which variant specific properties can be // added. CreateVariantPropertiesStruct() SdkMemberProperties + + // SupportedTraits returns the set of traits supported by this member type. + SupportedTraits() SdkMemberTraitSet } +var _ sdkRegisterable = (SdkMemberType)(nil) + // SdkDependencyContext provides access to information needed by the SdkMemberType.AddDependencies() // implementations. type SdkDependencyContext interface { BottomUpMutatorContext + + // RequiredTraits returns the set of SdkMemberTrait instances that the sdk requires the named + // member to provide. + RequiredTraits(name string) SdkMemberTraitSet + + // RequiresTrait returns true if the sdk requires the member with the supplied name to provide the + // supplied trait. + RequiresTrait(name string, trait SdkMemberTrait) bool } // SdkMemberTypeBase is the base type for SdkMemberType implementations and must be embedded in any @@ -565,6 +797,9 @@ type SdkMemberTypeBase struct { // module type in its SdkMemberType.AddPrebuiltModule() method. That prevents the sdk snapshot // code from automatically adding a prefer: true flag. UseSourceModuleTypeInSnapshot bool + + // The list of supported traits. + Traits []SdkMemberTrait } func (b *SdkMemberTypeBase) SdkPropertyName() string { @@ -587,60 +822,52 @@ func (b *SdkMemberTypeBase) UsesSourceModuleTypeInSnapshot() bool { return b.UseSourceModuleTypeInSnapshot } -// SdkMemberTypesRegistry encapsulates the information about registered SdkMemberTypes. -type SdkMemberTypesRegistry struct { - // The list of types sorted by property name. - list []SdkMemberType +func (b *SdkMemberTypeBase) SupportedTraits() SdkMemberTraitSet { + return NewSdkMemberTraitSet(b.Traits) } -func (r *SdkMemberTypesRegistry) copyAndAppend(memberType SdkMemberType) *SdkMemberTypesRegistry { - oldList := r.list - - // Copy the slice just in case this is being read while being modified, e.g. when testing. - list := make([]SdkMemberType, 0, len(oldList)+1) - list = append(list, oldList...) - list = append(list, memberType) - - // Sort the member types by their property name to ensure that registry order has no effect - // on behavior. - sort.Slice(list, func(i1, i2 int) bool { - t1 := list[i1] - t2 := list[i2] +// registeredModuleExportsMemberTypes is the set of registered SdkMemberTypes for module_exports +// modules. +var registeredModuleExportsMemberTypes = &sdkRegistry{} - return t1.SdkPropertyName() < t2.SdkPropertyName() - }) +// registeredSdkMemberTypes is the set of registered registeredSdkMemberTypes for sdk modules. +var registeredSdkMemberTypes = &sdkRegistry{} - // Create a new registry so the pointer uniquely identifies the set of registered types. - return &SdkMemberTypesRegistry{ - list: list, +// RegisteredSdkMemberTypes returns a OnceKey and a sorted list of registered types. +// +// If moduleExports is true then the slice of types includes all registered types that can be used +// with the module_exports and module_exports_snapshot module types. Otherwise, the slice of types +// only includes those registered types that can be used with the sdk and sdk_snapshot module +// types. +// +// The key uniquely identifies the array of types and can be used with OncePer.Once() to cache +// information derived from the array of types. +func RegisteredSdkMemberTypes(moduleExports bool) (OnceKey, []SdkMemberType) { + var registry *sdkRegistry + if moduleExports { + registry = registeredModuleExportsMemberTypes + } else { + registry = registeredSdkMemberTypes } -} - -func (r *SdkMemberTypesRegistry) RegisteredTypes() []SdkMemberType { - return r.list -} -func (r *SdkMemberTypesRegistry) UniqueOnceKey() OnceKey { - // Use the pointer to the registry as the unique key. - return NewCustomOnceKey(r) + registerables := registry.registeredObjects() + types := make([]SdkMemberType, len(registerables)) + for i, registerable := range registerables { + types[i] = registerable.(SdkMemberType) + } + return registry.uniqueOnceKey(), types } -// ModuleExportsMemberTypes is the set of registered SdkMemberTypes for module_exports modules. -var ModuleExportsMemberTypes = &SdkMemberTypesRegistry{} - -// SdkMemberTypes is the set of registered SdkMemberTypes for sdk modules. -var SdkMemberTypes = &SdkMemberTypesRegistry{} - // RegisterSdkMemberType registers an SdkMemberType object to allow them to be used in the // module_exports, module_exports_snapshot and (depending on the value returned from // SdkMemberType.UsableWithSdkAndSdkSnapshot) the sdk and sdk_snapshot module types. func RegisterSdkMemberType(memberType SdkMemberType) { // All member types are usable with module_exports. - ModuleExportsMemberTypes = ModuleExportsMemberTypes.copyAndAppend(memberType) + registeredModuleExportsMemberTypes = registeredModuleExportsMemberTypes.copyAndAppend(memberType) // Only those that explicitly indicate it are usable with sdk. if memberType.UsableWithSdkAndSdkSnapshot() { - SdkMemberTypes = SdkMemberTypes.copyAndAppend(memberType) + registeredSdkMemberTypes = registeredSdkMemberTypes.copyAndAppend(memberType) } } @@ -733,6 +960,9 @@ type SdkMemberContext interface { // Provided for use by sdk members to create a member specific location within the snapshot // into which to copy the prebuilt files. Name() string + + // RequiresTrait returns true if this member is expected to provide the specified trait. + RequiresTrait(trait SdkMemberTrait) bool } // ExportedComponentsInfo contains information about the components that this module exports to an diff --git a/android/sdk_test.go b/android/sdk_test.go new file mode 100644 index 000000000..51aeb314c --- /dev/null +++ b/android/sdk_test.go @@ -0,0 +1,53 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// 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 + +import "testing" + +type testSdkRegisterable struct { + name string +} + +func (t *testSdkRegisterable) SdkPropertyName() string { + return t.name +} + +var _ sdkRegisterable = &testSdkRegisterable{} + +func TestSdkRegistry(t *testing.T) { + alpha := &testSdkRegisterable{"alpha"} + beta := &testSdkRegisterable{"beta"} + betaDup := &testSdkRegisterable{"beta"} + + // Make sure that an empty registry is empty. + emptyRegistry := &sdkRegistry{} + AssertDeepEquals(t, "emptyRegistry should be empty", ([]sdkRegisterable)(nil), emptyRegistry.registeredObjects()) + + // Add beta to the empty registry to create another registry, check that it contains beta and make + // sure that it does not affect the creating registry. + registry1 := emptyRegistry.copyAndAppend(beta) + AssertDeepEquals(t, "emptyRegistry should still be empty", ([]sdkRegisterable)(nil), emptyRegistry.registeredObjects()) + AssertDeepEquals(t, "registry1 should contain beta", []sdkRegisterable{beta}, registry1.registeredObjects()) + + // Add alpha to the registry containing beta to create another registry, check that it contains + // alpha,beta (in order) and make sure that it does not affect the creating registry. + registry2 := registry1.copyAndAppend(alpha) + AssertDeepEquals(t, "registry1 should still contain beta", []sdkRegisterable{beta}, registry1.registeredObjects()) + AssertDeepEquals(t, "registry2 should contain alpha,beta", []sdkRegisterable{alpha, beta}, registry2.registeredObjects()) + + AssertPanicMessageContains(t, "duplicate beta should be detected", `"beta" already exists in ["alpha" "beta"]`, func() { + registry2.copyAndAppend(betaDup) + }) +} diff --git a/android/variable.go b/android/variable.go index a308d2b0b..ef453d7ff 100644 --- a/android/variable.go +++ b/android/variable.go @@ -61,6 +61,8 @@ type variableProperties struct { Shared_libs []string `android:"arch_variant"` Whole_static_libs []string `android:"arch_variant"` Exclude_static_libs []string `android:"arch_variant"` + Srcs []string `android:"arch_variant"` + Header_libs []string `android:"arch_variant"` } `android:"arch_variant"` Malloc_zero_contents struct { diff --git a/apex/apex.go b/apex/apex.go index 2d153e2c0..5294b6c17 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -1545,7 +1545,7 @@ func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.Platform type javaModule interface { android.Module BaseModuleName() string - DexJarBuildPath() android.Path + DexJarBuildPath() java.OptionalDexJarPath JacocoReportClassesFile() android.Path LintDepSets() java.LintDepSets Stem() string @@ -1559,7 +1559,7 @@ var _ javaModule = (*java.SdkLibraryImport)(nil) // apexFileForJavaModule creates an apexFile for a java module's dex implementation jar. func apexFileForJavaModule(ctx android.BaseModuleContext, module javaModule) apexFile { - return apexFileForJavaModuleWithFile(ctx, module, module.DexJarBuildPath()) + return apexFileForJavaModuleWithFile(ctx, module, module.DexJarBuildPath().PathOrNil()) } // apexFileForJavaModuleWithFile creates an apexFile for a java module with the supplied file. diff --git a/apex/apex_test.go b/apex/apex_test.go index 2a2a1f45f..420489e68 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -4799,9 +4799,10 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { transform := android.NullFixturePreparer checkDexJarBuildPath := func(t *testing.T, ctx *android.TestContext, name string) { + t.Helper() // Make sure the import has been given the correct path to the dex jar. p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency) - dexJarBuildPath := p.DexJarBuildPath() + dexJarBuildPath := p.DexJarBuildPath().PathOrNil() stem := android.RemoveOptionalPrebuiltPrefix(name) android.AssertStringEquals(t, "DexJarBuildPath should be apex-related path.", ".intermediates/myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar", @@ -4809,6 +4810,7 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { } checkDexJarInstallPath := func(t *testing.T, ctx *android.TestContext, name string) { + t.Helper() // Make sure the import has been given the correct path to the dex jar. p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency) dexJarBuildPath := p.DexJarInstallPath() @@ -4819,6 +4821,7 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { } ensureNoSourceVariant := func(t *testing.T, ctx *android.TestContext, name string) { + t.Helper() // Make sure that an apex variant is not created for the source module. android.AssertArrayString(t, "Check if there is no source variant", []string{"android_common"}, @@ -4856,8 +4859,11 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { // Make sure that dexpreopt can access dex implementation files from the prebuilt. ctx := testDexpreoptWithApexes(t, bp, "", transform) + deapexerName := deapexerModuleName("myapex") + android.AssertStringEquals(t, "APEX module name from deapexer name", "myapex", apexModuleName(deapexerName)) + // Make sure that the deapexer has the correct input APEX. - deapexer := ctx.ModuleForTests("myapex.deapexer", "android_common") + deapexer := ctx.ModuleForTests(deapexerName, "android_common") rule := deapexer.Rule("deapexer") if expected, actual := []string{"myapex-arm64.apex"}, android.NormalizePathsForTesting(rule.Implicits); !reflect.DeepEqual(expected, actual) { t.Errorf("expected: %q, found: %q", expected, actual) diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go index 3e19014a3..cb7d3d113 100644 --- a/apex/bootclasspath_fragment_test.go +++ b/apex/bootclasspath_fragment_test.go @@ -22,6 +22,7 @@ import ( "android/soong/android" "android/soong/java" + "github.com/google/blueprint/proptools" ) @@ -737,7 +738,7 @@ func TestBootclasspathFragmentContentsNoName(t *testing.T) { func getDexJarPath(result *android.TestResult, name string) string { module := result.Module(name, "android_common") - return module.(java.UsesLibraryDependency).DexJarBuildPath().RelativeToTop().String() + return module.(java.UsesLibraryDependency).DexJarBuildPath().Path().RelativeToTop().String() } // TestBootclasspathFragment_HiddenAPIList checks to make sure that the correct parameters are diff --git a/apex/deapexer.go b/apex/deapexer.go index 2c1835aa4..8c9030a85 100644 --- a/apex/deapexer.go +++ b/apex/deapexer.go @@ -15,6 +15,8 @@ package apex import ( + "strings" + "android/soong/android" ) @@ -75,6 +77,17 @@ type Deapexer struct { inputApex android.Path } +// Returns the name of the deapexer module corresponding to an APEX module with the given name. +func deapexerModuleName(apexModuleName string) string { + return apexModuleName + ".deapexer" +} + +// Returns the name of the APEX module corresponding to an deapexer module with +// the given name. This reverses deapexerModuleName. +func apexModuleName(deapexerModuleName string) string { + return strings.TrimSuffix(deapexerModuleName, ".deapexer") +} + func privateDeapexerFactory() android.Module { module := &Deapexer{} module.AddProperties(&module.properties, &module.selectedApexProperties) @@ -113,7 +126,8 @@ func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) { // apex relative path to extracted file path available for other modules. if len(exports) > 0 { // Make the information available for other modules. - ctx.SetProvider(android.DeapexerProvider, android.NewDeapexerInfo(exports)) + di := android.NewDeapexerInfo(apexModuleName(ctx.ModuleName()), exports) + ctx.SetProvider(android.DeapexerProvider, di) // Create a sorted list of the files that this exports. exportedPaths = android.SortedUniquePaths(exportedPaths) @@ -131,6 +145,6 @@ func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) { for _, p := range exportedPaths { command.Output(p.(android.WritablePath)) } - builder.Build("deapexer", "deapex "+ctx.ModuleName()) + builder.Build("deapexer", "deapex "+apexModuleName(ctx.ModuleName())) } } diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 4833a644b..d59f8bfec 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -176,13 +176,15 @@ func (p *prebuiltCommon) initApexFilesForAndroidMk(ctx android.ModuleContext) { name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child)) if java.IsBootclasspathFragmentContentDepTag(tag) || tag == exportedJavaLibTag { // If the exported java module provides a dex jar path then add it to the list of apexFiles. - path := child.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath() - if path != nil { + path := child.(interface { + DexJarBuildPath() java.OptionalDexJarPath + }).DexJarBuildPath() + if path.IsSet() { af := apexFile{ module: child, moduleDir: ctx.OtherModuleDir(child), androidMkModuleName: name, - builtFile: path, + builtFile: path.Path(), class: javaSharedLib, } if module, ok := child.(java.DexpreopterInterface); ok { @@ -629,10 +631,6 @@ func createDeapexerModuleIfNeeded(ctx android.TopDownMutatorContext, deapexerNam ) } -func deapexerModuleName(baseModuleName string) string { - return baseModuleName + ".deapexer" -} - func apexSelectorModuleName(baseModuleName string) string { return baseModuleName + ".apex.selector" } diff --git a/bazel/Android.bp b/bazel/Android.bp index b68d65bd5..80af2bdca 100644 --- a/bazel/Android.bp +++ b/bazel/Android.bp @@ -14,6 +14,7 @@ bootstrap_go_package { testSrcs: [ "aquery_test.go", "properties_test.go", + "testing.go", ], pluginFor: [ "soong_build", diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go index d731f3e49..0bd71c63a 100644 --- a/bazel/cquery/request_type.go +++ b/bazel/cquery/request_type.go @@ -111,14 +111,20 @@ staticLibraries = [] rootStaticArchives = [] linker_inputs = cc_info.linking_context.linker_inputs.to_list() -for linker_input in linker_inputs: - for library in linker_input.libraries: - for object in library.objects: - ccObjectFiles += [object.path] - if library.static_library: - staticLibraries.append(library.static_library.path) - if linker_input.owner == target.label: - rootStaticArchives.append(library.static_library.path) +static_info_tag = "//build/bazel/rules:cc_library_static.bzl%CcStaticLibraryInfo" +if static_info_tag in providers(target): + static_info = providers(target)[static_info_tag] + ccObjectFiles = [f.path for f in static_info.objects] + rootStaticArchives = [static_info.root_static_archive.path] +else: + for linker_input in linker_inputs: + for library in linker_input.libraries: + for object in library.objects: + ccObjectFiles += [object.path] + if library.static_library: + staticLibraries.append(library.static_library.path) + if linker_input.owner == target.label: + rootStaticArchives.append(library.static_library.path) rootDynamicLibraries = [] @@ -141,9 +147,10 @@ returns = [ system_includes, rootStaticArchives, rootDynamicLibraries, + [toc_file] ] -return "|".join([", ".join(r) for r in returns] + [toc_file])` +return "|".join([", ".join(r) for r in returns])` } // ParseResult returns a value obtained by parsing the result of the request's Starlark function. diff --git a/bazel/properties.go b/bazel/properties.go index d3b40a242..bd8ef0d8d 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -19,6 +19,9 @@ import ( "path/filepath" "regexp" "sort" + "strings" + + "github.com/google/blueprint" ) // BazelTargetModuleProperties contain properties and metadata used for @@ -182,76 +185,6 @@ func SubtractStrings(haystack []string, needle []string) []string { return strings } -// Map a function over all labels in a LabelList. -func MapLabelList(mapOver LabelList, mapFn func(string) string) LabelList { - var includes []Label - for _, inc := range mapOver.Includes { - mappedLabel := Label{Label: mapFn(inc.Label), OriginalModuleName: inc.OriginalModuleName} - includes = append(includes, mappedLabel) - } - // mapFn is not applied over excludes, but they are propagated as-is. - return LabelList{Includes: includes, Excludes: mapOver.Excludes} -} - -// Map a function over all Labels in a LabelListAttribute -func MapLabelListAttribute(mapOver LabelListAttribute, mapFn func(string) string) LabelListAttribute { - var result LabelListAttribute - - result.Value = MapLabelList(mapOver.Value, mapFn) - - for axis, configToLabels := range mapOver.ConfigurableValues { - for config, value := range configToLabels { - result.SetSelectValue(axis, config, MapLabelList(value, mapFn)) - } - } - - return result -} - -// Return all needles in a given haystack, where needleFn is true for needles. -func FilterLabelList(haystack LabelList, needleFn func(string) bool) LabelList { - var includes []Label - for _, inc := range haystack.Includes { - if needleFn(inc.Label) { - includes = append(includes, inc) - } - } - // needleFn is not applied over excludes, but they are propagated as-is. - return LabelList{Includes: includes, Excludes: haystack.Excludes} -} - -// Return all needles in a given haystack, where needleFn is true for needles. -func FilterLabelListAttribute(haystack LabelListAttribute, needleFn func(string) bool) LabelListAttribute { - result := MakeLabelListAttribute(FilterLabelList(haystack.Value, needleFn)) - - for config, selects := range haystack.ConfigurableValues { - newSelects := make(labelListSelectValues, len(selects)) - for k, v := range selects { - newSelects[k] = FilterLabelList(v, needleFn) - } - result.ConfigurableValues[config] = newSelects - } - - return result -} - -// Subtract needle from haystack -func SubtractBazelLabelListAttribute(haystack LabelListAttribute, needle LabelListAttribute) LabelListAttribute { - result := MakeLabelListAttribute(SubtractBazelLabelList(haystack.Value, needle.Value)) - - for config, selects := range haystack.ConfigurableValues { - newSelects := make(labelListSelectValues, len(selects)) - needleSelects := needle.ConfigurableValues[config] - - for k, v := range selects { - newSelects[k] = SubtractBazelLabelList(v, needleSelects[k]) - } - result.ConfigurableValues[config] = newSelects - } - - return result -} - // Subtract needle from haystack func SubtractBazelLabels(haystack []Label, needle []Label) []Label { // This is really a set @@ -624,6 +557,144 @@ func (lla *LabelListAttribute) ResolveExcludes() { } } +// OtherModuleContext is a limited context that has methods with information about other modules. +type OtherModuleContext interface { + ModuleFromName(name string) (blueprint.Module, bool) + OtherModuleType(m blueprint.Module) string + OtherModuleName(m blueprint.Module) string + OtherModuleDir(m blueprint.Module) string + ModuleErrorf(fmt string, args ...interface{}) +} + +// LabelMapper is a function that takes a OtherModuleContext and returns a (potentially changed) +// label and whether it was changed. +type LabelMapper func(OtherModuleContext, string) (string, bool) + +// LabelPartition contains descriptions of a partition for labels +type LabelPartition struct { + // Extensions to include in this partition + Extensions []string + // LabelMapper is a function that can map a label to a new label, and indicate whether to include + // the mapped label in the partition + LabelMapper LabelMapper + // Whether to store files not included in any other partition in a group of LabelPartitions + // Only one partition in a group of LabelPartitions can enabled Keep_remainder + Keep_remainder bool +} + +// LabelPartitions is a map of partition name to a LabelPartition describing the elements of the +// partition +type LabelPartitions map[string]LabelPartition + +// filter returns a pointer to a label if the label should be included in the partition or nil if +// not. +func (lf LabelPartition) filter(ctx OtherModuleContext, label Label) *Label { + if lf.LabelMapper != nil { + if newLabel, changed := lf.LabelMapper(ctx, label.Label); changed { + return &Label{newLabel, label.OriginalModuleName} + } + } + for _, ext := range lf.Extensions { + if strings.HasSuffix(label.Label, ext) { + return &label + } + } + + return nil +} + +// PartitionToLabelListAttribute is map of partition name to a LabelListAttribute +type PartitionToLabelListAttribute map[string]LabelListAttribute + +type partitionToLabelList map[string]*LabelList + +func (p partitionToLabelList) appendIncludes(partition string, label Label) { + if _, ok := p[partition]; !ok { + p[partition] = &LabelList{} + } + p[partition].Includes = append(p[partition].Includes, label) +} + +func (p partitionToLabelList) excludes(partition string, excludes []Label) { + if _, ok := p[partition]; !ok { + p[partition] = &LabelList{} + } + p[partition].Excludes = excludes +} + +// PartitionLabelListAttribute partitions a LabelListAttribute into the requested partitions +func PartitionLabelListAttribute(ctx OtherModuleContext, lla *LabelListAttribute, partitions LabelPartitions) PartitionToLabelListAttribute { + ret := PartitionToLabelListAttribute{} + var partitionNames []string + // Stored as a pointer to distinguish nil (no remainder partition) from empty string partition + var remainderPartition *string + for p, f := range partitions { + partitionNames = append(partitionNames, p) + if f.Keep_remainder { + if remainderPartition != nil { + panic("only one partition can store the remainder") + } + // If we take the address of p in a loop, we'll end up with the last value of p in + // remainderPartition, we want the requested partition + capturePartition := p + remainderPartition = &capturePartition + } + } + + partitionLabelList := func(axis ConfigurationAxis, config string) { + value := lla.SelectValue(axis, config) + partitionToLabels := partitionToLabelList{} + for _, item := range value.Includes { + wasFiltered := false + var inPartition *string + for partition, f := range partitions { + filtered := f.filter(ctx, item) + if filtered == nil { + // did not match this filter, keep looking + continue + } + wasFiltered = true + partitionToLabels.appendIncludes(partition, *filtered) + // don't need to check other partitions if this filter used the item, + // continue checking if mapped to another name + if *filtered == item { + if inPartition != nil { + ctx.ModuleErrorf("%q was found in multiple partitions: %q, %q", item.Label, *inPartition, partition) + } + capturePartition := partition + inPartition = &capturePartition + } + } + + // if not specified in a partition, add to remainder partition if one exists + if !wasFiltered && remainderPartition != nil { + partitionToLabels.appendIncludes(*remainderPartition, item) + } + } + + // ensure empty lists are maintained + if value.Excludes != nil { + for _, partition := range partitionNames { + partitionToLabels.excludes(partition, value.Excludes) + } + } + + for partition, list := range partitionToLabels { + val := ret[partition] + (&val).SetSelectValue(axis, config, *list) + ret[partition] = val + } + } + + partitionLabelList(NoConfigAxis, "") + for axis, configToList := range lla.ConfigurableValues { + for config, _ := range configToList { + partitionLabelList(axis, config) + } + } + return ret +} + // StringListAttribute corresponds to the string_list Bazel attribute type with // support for additional metadata, like configurations. type StringListAttribute struct { diff --git a/bazel/properties_test.go b/bazel/properties_test.go index 85596e291..f53fdc1de 100644 --- a/bazel/properties_test.go +++ b/bazel/properties_test.go @@ -16,7 +16,10 @@ package bazel import ( "reflect" + "strings" "testing" + + "github.com/google/blueprint/proptools" ) func TestUniqueBazelLabels(t *testing.T) { @@ -294,6 +297,222 @@ func TestResolveExcludes(t *testing.T) { } } +// labelAddSuffixForTypeMapper returns a LabelMapper that adds suffix to label name for modules of +// typ +func labelAddSuffixForTypeMapper(suffix, typ string) LabelMapper { + return func(omc OtherModuleContext, label string) (string, bool) { + m, ok := omc.ModuleFromName(label) + if !ok { + return label, false + } + mTyp := omc.OtherModuleType(m) + if typ == mTyp { + return label + suffix, true + } + return label, false + } +} + +func TestPartitionLabelListAttribute(t *testing.T) { + testCases := []struct { + name string + ctx *otherModuleTestContext + labelList LabelListAttribute + filters LabelPartitions + expected PartitionToLabelListAttribute + expectedErrMsg *string + }{ + { + name: "no configurable values", + ctx: &otherModuleTestContext{}, + labelList: LabelListAttribute{ + Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}), + }, + filters: LabelPartitions{ + "A": LabelPartition{Extensions: []string{".a"}}, + "B": LabelPartition{Extensions: []string{".b"}}, + "C": LabelPartition{Extensions: []string{".c"}}, + }, + expected: PartitionToLabelListAttribute{ + "A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})}, + "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})}, + "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})}, + }, + }, + { + name: "no configurable values, remainder partition", + ctx: &otherModuleTestContext{}, + labelList: LabelListAttribute{ + Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}), + }, + filters: LabelPartitions{ + "A": LabelPartition{Extensions: []string{".a"}, Keep_remainder: true}, + "B": LabelPartition{Extensions: []string{".b"}}, + "C": LabelPartition{Extensions: []string{".c"}}, + }, + expected: PartitionToLabelListAttribute{ + "A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "d.d", "e.e"}, []string{})}, + "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})}, + "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})}, + }, + }, + { + name: "no configurable values, empty partition", + ctx: &otherModuleTestContext{}, + labelList: LabelListAttribute{ + Value: makeLabelList([]string{"a.a", "c.c"}, []string{}), + }, + filters: LabelPartitions{ + "A": LabelPartition{Extensions: []string{".a"}}, + "B": LabelPartition{Extensions: []string{".b"}}, + "C": LabelPartition{Extensions: []string{".c"}}, + }, + expected: PartitionToLabelListAttribute{ + "A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})}, + "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})}, + }, + }, + { + name: "no configurable values, has map", + ctx: &otherModuleTestContext{ + modules: []testModuleInfo{testModuleInfo{name: "srcs", typ: "fg", dir: "dir"}}, + }, + labelList: LabelListAttribute{ + Value: makeLabelList([]string{"a.a", "srcs", "b.b", "c.c"}, []string{}), + }, + filters: LabelPartitions{ + "A": LabelPartition{Extensions: []string{".a"}, LabelMapper: labelAddSuffixForTypeMapper("_a", "fg")}, + "B": LabelPartition{Extensions: []string{".b"}}, + "C": LabelPartition{Extensions: []string{".c"}}, + }, + expected: PartitionToLabelListAttribute{ + "A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "srcs_a"}, []string{})}, + "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})}, + "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})}, + }, + }, + { + name: "configurable values, keeps empty if excludes", + ctx: &otherModuleTestContext{}, + labelList: LabelListAttribute{ + ConfigurableValues: configurableLabelLists{ + ArchConfigurationAxis: labelListSelectValues{ + "x86": makeLabelList([]string{"a.a", "c.c"}, []string{}), + "arm": makeLabelList([]string{"b.b"}, []string{}), + "x86_64": makeLabelList([]string{"b.b"}, []string{"d.d"}), + }, + }, + }, + filters: LabelPartitions{ + "A": LabelPartition{Extensions: []string{".a"}}, + "B": LabelPartition{Extensions: []string{".b"}}, + "C": LabelPartition{Extensions: []string{".c"}}, + }, + expected: PartitionToLabelListAttribute{ + "A": LabelListAttribute{ + ConfigurableValues: configurableLabelLists{ + ArchConfigurationAxis: labelListSelectValues{ + "x86": makeLabelList([]string{"a.a"}, []string{}), + "x86_64": makeLabelList([]string{}, []string{"c.c"}), + }, + }, + }, + "B": LabelListAttribute{ + ConfigurableValues: configurableLabelLists{ + ArchConfigurationAxis: labelListSelectValues{ + "arm": makeLabelList([]string{"b.b"}, []string{}), + "x86_64": makeLabelList([]string{"b.b"}, []string{"c.c"}), + }, + }, + }, + "C": LabelListAttribute{ + ConfigurableValues: configurableLabelLists{ + ArchConfigurationAxis: labelListSelectValues{ + "x86": makeLabelList([]string{"c.c"}, []string{}), + "x86_64": makeLabelList([]string{}, []string{"c.c"}), + }, + }, + }, + }, + }, + { + name: "error for multiple partitions same value", + ctx: &otherModuleTestContext{}, + labelList: LabelListAttribute{ + Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}), + }, + filters: LabelPartitions{ + "A": LabelPartition{Extensions: []string{".a"}}, + "other A": LabelPartition{Extensions: []string{".a"}}, + }, + expected: PartitionToLabelListAttribute{}, + expectedErrMsg: proptools.StringPtr(`"a.a" was found in multiple partitions:`), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := PartitionLabelListAttribute(tc.ctx, &tc.labelList, tc.filters) + + if hasErrors, expectsErr := len(tc.ctx.errors) > 0, tc.expectedErrMsg != nil; hasErrors != expectsErr { + t.Errorf("Unexpected error(s): %q, expected: %q", tc.ctx.errors, *tc.expectedErrMsg) + } else if tc.expectedErrMsg != nil { + found := false + for _, err := range tc.ctx.errors { + if strings.Contains(err, *tc.expectedErrMsg) { + found = true + break + } + } + + if !found { + t.Errorf("Expected error message: %q, got %q", *tc.expectedErrMsg, tc.ctx.errors) + } + return + } + + if len(tc.expected) != len(got) { + t.Errorf("Expected %d partitions, got %d partitions", len(tc.expected), len(got)) + } + for partition, expectedLla := range tc.expected { + gotLla, ok := got[partition] + if !ok { + t.Errorf("Expected partition %q, but it was not found %v", partition, got) + continue + } + expectedLabelList := expectedLla.Value + gotLabelList := gotLla.Value + if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) { + t.Errorf("Expected no config includes %v, got %v", expectedLabelList.Includes, gotLabelList.Includes) + } + expectedAxes := expectedLla.SortedConfigurationAxes() + gotAxes := gotLla.SortedConfigurationAxes() + if !reflect.DeepEqual(expectedAxes, gotAxes) { + t.Errorf("Expected axes %v, got %v (%#v)", expectedAxes, gotAxes, gotLla) + } + for _, axis := range expectedLla.SortedConfigurationAxes() { + if _, exists := gotLla.ConfigurableValues[axis]; !exists { + t.Errorf("Expected %s to be a supported axis, but it was not found", axis) + } + if expected, got := expectedLla.ConfigurableValues[axis], gotLla.ConfigurableValues[axis]; len(expected) != len(got) { + t.Errorf("For axis %q: expected configs %v, got %v", axis, expected, got) + } + for config, expectedLabelList := range expectedLla.ConfigurableValues[axis] { + gotLabelList, exists := gotLla.ConfigurableValues[axis][config] + if !exists { + t.Errorf("Expected %s to be a supported config, but config was not found", config) + continue + } + if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) { + t.Errorf("Expected %s %s includes %v, got %v", axis, config, expectedLabelList.Includes, gotLabelList.Includes) + } + } + } + } + }) + } +} + func TestDeduplicateAxesFromBase(t *testing.T) { attr := StringListAttribute{ Value: []string{ diff --git a/bazel/testing.go b/bazel/testing.go new file mode 100644 index 000000000..23c835084 --- /dev/null +++ b/bazel/testing.go @@ -0,0 +1,105 @@ +// 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 bazel + +import ( + "fmt" + + "github.com/google/blueprint" +) + +// testModuleInfo implements blueprint.Module interface with sufficient information to mock a subset of +// a blueprint ModuleContext +type testModuleInfo struct { + name string + typ string + dir string +} + +// Name returns name for testModuleInfo -- required to implement blueprint.Module +func (mi testModuleInfo) Name() string { + return mi.name +} + +// GenerateBuildActions unused, but required to implmeent blueprint.Module +func (mi testModuleInfo) GenerateBuildActions(blueprint.ModuleContext) {} + +func (mi testModuleInfo) equals(other testModuleInfo) bool { + return mi.name == other.name && mi.typ == other.typ && mi.dir == other.dir +} + +// ensure testModuleInfo implements blueprint.Module +var _ blueprint.Module = testModuleInfo{} + +// otherModuleTestContext is a mock context that implements OtherModuleContext +type otherModuleTestContext struct { + modules []testModuleInfo + errors []string +} + +// ModuleFromName retrieves the testModuleInfo corresponding to name, if it exists +func (omc *otherModuleTestContext) ModuleFromName(name string) (blueprint.Module, bool) { + for _, m := range omc.modules { + if m.name == name { + return m, true + } + } + return testModuleInfo{}, false +} + +// testModuleInfo returns the testModuleInfo corresponding to a blueprint.Module if it exists in omc +func (omc *otherModuleTestContext) testModuleInfo(m blueprint.Module) (testModuleInfo, bool) { + mi, ok := m.(testModuleInfo) + if !ok { + return testModuleInfo{}, false + } + for _, other := range omc.modules { + if other.equals(mi) { + return mi, true + } + } + return testModuleInfo{}, false +} + +// OtherModuleType returns type of m if it exists in omc +func (omc *otherModuleTestContext) OtherModuleType(m blueprint.Module) string { + if mi, ok := omc.testModuleInfo(m); ok { + return mi.typ + } + return "" +} + +// OtherModuleName returns name of m if it exists in omc +func (omc *otherModuleTestContext) OtherModuleName(m blueprint.Module) string { + if mi, ok := omc.testModuleInfo(m); ok { + return mi.name + } + return "" +} + +// OtherModuleDir returns dir of m if it exists in omc +func (omc *otherModuleTestContext) OtherModuleDir(m blueprint.Module) string { + if mi, ok := omc.testModuleInfo(m); ok { + return mi.dir + } + return "" +} + +func (omc *otherModuleTestContext) ModuleErrorf(format string, args ...interface{}) { + omc.errors = append(omc.errors, fmt.Sprintf(format, args...)) +} + +// Ensure otherModuleTestContext implements OtherModuleContext +var _ OtherModuleContext = &otherModuleTestContext{} diff --git a/bp2build/Android.bp b/bp2build/Android.bp index 40526a623..1250e92d0 100644 --- a/bp2build/Android.bp +++ b/bp2build/Android.bp @@ -33,6 +33,7 @@ bootstrap_go_package { "apex_key_conversion_test.go", "build_conversion_test.go", "bzl_conversion_test.go", + "cc_genrule_conversion_test.go", "cc_library_conversion_test.go", "cc_library_headers_conversion_test.go", "cc_library_static_conversion_test.go", diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go index b1a6e2c73..4a0eeea51 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -635,6 +635,7 @@ func extractStructProperties(structValue reflect.Value, indent int) map[string]s // Ignore zero-valued fields continue } + // if the struct is embedded (anonymous), flatten the properties into the containing struct if field.Anonymous { if field.Type.Kind() == reflect.Ptr { diff --git a/bp2build/cc_genrule_conversion_test.go b/bp2build/cc_genrule_conversion_test.go new file mode 100644 index 000000000..a7e9cb21a --- /dev/null +++ b/bp2build/cc_genrule_conversion_test.go @@ -0,0 +1,258 @@ +// 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 bp2build + +import ( + "testing" + + "android/soong/android" + "android/soong/cc" + "android/soong/genrule" +) + +var otherCcGenruleBp = map[string]string{ + "other/Android.bp": `cc_genrule { + name: "foo.tool", + out: ["foo_tool.out"], + srcs: ["foo_tool.in"], + cmd: "cp $(in) $(out)", +} +cc_genrule { + name: "other.tool", + out: ["other_tool.out"], + srcs: ["other_tool.in"], + cmd: "cp $(in) $(out)", +}`, +} + +func runCcGenruleTestCase(t *testing.T, tc bp2buildTestCase) { + t.Helper() + runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc) +} + +func TestCliVariableReplacement(t *testing.T) { + runCcGenruleTestCase(t, bp2buildTestCase{ + description: "cc_genrule with command line variable replacements", + moduleTypeUnderTest: "cc_genrule", + moduleTypeUnderTestFactory: cc.GenRuleFactory, + moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build, + blueprint: `cc_genrule { + name: "foo.tool", + out: ["foo_tool.out"], + srcs: ["foo_tool.in"], + cmd: "cp $(in) $(out)", + bazel_module: { bp2build_available: true }, +} + +cc_genrule { + name: "foo", + out: ["foo.out"], + srcs: ["foo.in"], + tools: [":foo.tool"], + cmd: "$(location :foo.tool) --genDir=$(genDir) arg $(in) $(out)", + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{ + `genrule( + name = "foo", + cmd = "$(location :foo.tool) --genDir=$(RULEDIR) arg $(SRCS) $(OUTS)", + outs = ["foo.out"], + srcs = ["foo.in"], + tools = [":foo.tool"], +)`, + `genrule( + name = "foo.tool", + cmd = "cp $(SRCS) $(OUTS)", + outs = ["foo_tool.out"], + srcs = ["foo_tool.in"], +)`, + }, + }) +} + +func TestUsingLocationsLabel(t *testing.T) { + runCcGenruleTestCase(t, bp2buildTestCase{ + description: "cc_genrule using $(locations :label)", + moduleTypeUnderTest: "cc_genrule", + moduleTypeUnderTestFactory: cc.GenRuleFactory, + moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build, + blueprint: `cc_genrule { + name: "foo.tools", + out: ["foo_tool.out", "foo_tool2.out"], + srcs: ["foo_tool.in"], + cmd: "cp $(in) $(out)", + bazel_module: { bp2build_available: true }, +} + +cc_genrule { + name: "foo", + out: ["foo.out"], + srcs: ["foo.in"], + tools: [":foo.tools"], + cmd: "$(locations :foo.tools) -s $(out) $(in)", + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{`genrule( + name = "foo", + cmd = "$(locations :foo.tools) -s $(OUTS) $(SRCS)", + outs = ["foo.out"], + srcs = ["foo.in"], + tools = [":foo.tools"], +)`, + `genrule( + name = "foo.tools", + cmd = "cp $(SRCS) $(OUTS)", + outs = [ + "foo_tool.out", + "foo_tool2.out", + ], + srcs = ["foo_tool.in"], +)`, + }, + }) +} + +func TestUsingLocationsAbsoluteLabel(t *testing.T) { + runCcGenruleTestCase(t, bp2buildTestCase{ + description: "cc_genrule using $(locations //absolute:label)", + moduleTypeUnderTest: "cc_genrule", + moduleTypeUnderTestFactory: cc.GenRuleFactory, + moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build, + blueprint: `cc_genrule { + name: "foo", + out: ["foo.out"], + srcs: ["foo.in"], + tool_files: [":foo.tool"], + cmd: "$(locations :foo.tool) -s $(out) $(in)", + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{`genrule( + name = "foo", + cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)", + outs = ["foo.out"], + srcs = ["foo.in"], + tools = ["//other:foo.tool"], +)`, + }, + filesystem: otherCcGenruleBp, + }) +} + +func TestSrcsUsingAbsoluteLabel(t *testing.T) { + runCcGenruleTestCase(t, bp2buildTestCase{ + description: "cc_genrule srcs using $(locations //absolute:label)", + moduleTypeUnderTest: "cc_genrule", + moduleTypeUnderTestFactory: cc.GenRuleFactory, + moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build, + blueprint: `cc_genrule { + name: "foo", + out: ["foo.out"], + srcs: [":other.tool"], + tool_files: [":foo.tool"], + cmd: "$(locations :foo.tool) -s $(out) $(location :other.tool)", + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{`genrule( + name = "foo", + cmd = "$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)", + outs = ["foo.out"], + srcs = ["//other:other.tool"], + tools = ["//other:foo.tool"], +)`, + }, + filesystem: otherCcGenruleBp, + }) +} + +func TestLocationsLabelUsesFirstToolFile(t *testing.T) { + runCcGenruleTestCase(t, bp2buildTestCase{ + description: "cc_genrule using $(location) label should substitute first tool label automatically", + moduleTypeUnderTest: "cc_genrule", + moduleTypeUnderTestFactory: cc.GenRuleFactory, + moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build, + blueprint: `cc_genrule { + name: "foo", + out: ["foo.out"], + srcs: ["foo.in"], + tool_files: [":foo.tool", ":other.tool"], + cmd: "$(location) -s $(out) $(in)", + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{`genrule( + name = "foo", + cmd = "$(location //other:foo.tool) -s $(OUTS) $(SRCS)", + outs = ["foo.out"], + srcs = ["foo.in"], + tools = [ + "//other:foo.tool", + "//other:other.tool", + ], +)`, + }, + filesystem: otherCcGenruleBp, + }) +} + +func TestLocationsLabelUsesFirstTool(t *testing.T) { + runCcGenruleTestCase(t, bp2buildTestCase{ + description: "cc_genrule using $(locations) label should substitute first tool label automatically", + moduleTypeUnderTest: "cc_genrule", + moduleTypeUnderTestFactory: cc.GenRuleFactory, + moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build, + blueprint: `cc_genrule { + name: "foo", + out: ["foo.out"], + srcs: ["foo.in"], + tools: [":foo.tool", ":other.tool"], + cmd: "$(locations) -s $(out) $(in)", + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{`genrule( + name = "foo", + cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)", + outs = ["foo.out"], + srcs = ["foo.in"], + tools = [ + "//other:foo.tool", + "//other:other.tool", + ], +)`, + }, + filesystem: otherCcGenruleBp, + }) +} + +func TestWithoutToolsOrToolFiles(t *testing.T) { + runCcGenruleTestCase(t, bp2buildTestCase{ + description: "cc_genrule without tools or tool_files can convert successfully", + moduleTypeUnderTest: "cc_genrule", + moduleTypeUnderTestFactory: cc.GenRuleFactory, + moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build, + blueprint: `cc_genrule { + name: "foo", + out: ["foo.out"], + srcs: ["foo.in"], + cmd: "cp $(in) $(out)", + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{`genrule( + name = "foo", + cmd = "cp $(SRCS) $(OUTS)", + outs = ["foo.out"], + srcs = ["foo.in"], +)`, + }, + }) +} diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go index b3a10531e..5952b15e2 100644 --- a/bp2build/cc_library_conversion_test.go +++ b/bp2build/cc_library_conversion_test.go @@ -349,21 +349,21 @@ cc_library { expectedBazelTargets: []string{`cc_library( name = "a", copts = ["bothflag"], - dynamic_deps = [":shared_dep_for_both"], implementation_deps = [":static_dep_for_both"], + implementation_dynamic_deps = [":shared_dep_for_both"], shared = { "copts": ["sharedflag"], - "dynamic_deps": [":shared_dep_for_shared"], + "implementation_deps": [":static_dep_for_shared"], + "implementation_dynamic_deps": [":shared_dep_for_shared"], "srcs": ["sharedonly.cpp"], - "static_deps": [":static_dep_for_shared"], "whole_archive_deps": [":whole_static_lib_for_shared"], }, srcs = ["both.cpp"], static = { "copts": ["staticflag"], - "dynamic_deps": [":shared_dep_for_static"], + "implementation_deps": [":static_dep_for_static"], + "implementation_dynamic_deps": [":shared_dep_for_static"], "srcs": ["staticonly.cpp"], - "static_deps": [":static_dep_for_static"], "whole_archive_deps": [":whole_static_lib_for_static"], }, whole_archive_deps = [":whole_static_lib_for_both"], @@ -371,6 +371,105 @@ cc_library { }) } +func TestCcLibraryDeps(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + description: "cc_library shared/static props", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + filesystem: map[string]string{ + "both.cpp": "", + "sharedonly.cpp": "", + "staticonly.cpp": "", + }, + blueprint: soongCcLibraryPreamble + ` +cc_library { + name: "a", + srcs: ["both.cpp"], + cflags: ["bothflag"], + shared_libs: ["implementation_shared_dep_for_both", "shared_dep_for_both"], + export_shared_lib_headers: ["shared_dep_for_both"], + static_libs: ["implementation_static_dep_for_both", "static_dep_for_both"], + export_static_lib_headers: ["static_dep_for_both", "whole_static_dep_for_both"], + whole_static_libs: ["not_explicitly_exported_whole_static_dep_for_both", "whole_static_dep_for_both"], + static: { + srcs: ["staticonly.cpp"], + cflags: ["staticflag"], + shared_libs: ["implementation_shared_dep_for_static", "shared_dep_for_static"], + export_shared_lib_headers: ["shared_dep_for_static"], + static_libs: ["implementation_static_dep_for_static", "static_dep_for_static"], + export_static_lib_headers: ["static_dep_for_static", "whole_static_dep_for_static"], + whole_static_libs: ["not_explicitly_exported_whole_static_dep_for_static", "whole_static_dep_for_static"], + }, + shared: { + srcs: ["sharedonly.cpp"], + cflags: ["sharedflag"], + shared_libs: ["implementation_shared_dep_for_shared", "shared_dep_for_shared"], + export_shared_lib_headers: ["shared_dep_for_shared"], + static_libs: ["implementation_static_dep_for_shared", "static_dep_for_shared"], + export_static_lib_headers: ["static_dep_for_shared", "whole_static_dep_for_shared"], + whole_static_libs: ["not_explicitly_exported_whole_static_dep_for_shared", "whole_static_dep_for_shared"], + }, + include_build_directory: false, +} +` + simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_shared") + + simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_shared") + + simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_static") + + simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_static") + + simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_both") + + simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_both") + + simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_shared") + + simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_shared") + + simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_static") + + simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_static") + + simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_both") + + simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_both") + + simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_shared") + + simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_shared") + + simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_static") + + simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_static") + + simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_both") + + simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_both"), + expectedBazelTargets: []string{`cc_library( + name = "a", + copts = ["bothflag"], + deps = [":static_dep_for_both"], + dynamic_deps = [":shared_dep_for_both"], + implementation_deps = [":implementation_static_dep_for_both"], + implementation_dynamic_deps = [":implementation_shared_dep_for_both"], + shared = { + "copts": ["sharedflag"], + "deps": [":static_dep_for_shared"], + "dynamic_deps": [":shared_dep_for_shared"], + "implementation_deps": [":implementation_static_dep_for_shared"], + "implementation_dynamic_deps": [":implementation_shared_dep_for_shared"], + "srcs": ["sharedonly.cpp"], + "whole_archive_deps": [ + ":not_explicitly_exported_whole_static_dep_for_shared", + ":whole_static_dep_for_shared", + ], + }, + srcs = ["both.cpp"], + static = { + "copts": ["staticflag"], + "deps": [":static_dep_for_static"], + "dynamic_deps": [":shared_dep_for_static"], + "implementation_deps": [":implementation_static_dep_for_static"], + "implementation_dynamic_deps": [":implementation_shared_dep_for_static"], + "srcs": ["staticonly.cpp"], + "whole_archive_deps": [ + ":not_explicitly_exported_whole_static_dep_for_static", + ":whole_static_dep_for_static", + ], + }, + whole_archive_deps = [ + ":not_explicitly_exported_whole_static_dep_for_both", + ":whole_static_dep_for_both", + ], +)`}, + }) +} + func TestCcLibraryWholeStaticLibsAlwaysLink(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ moduleTypeUnderTest: "cc_library", @@ -506,7 +605,14 @@ cc_library_static { name: "android_dep_for_shared" } "//build/bazel/platforms/os_arch:android_arm": ["-DANDROID_ARM_SHARED"], "//conditions:default": [], }), - "dynamic_deps": select({ + "implementation_deps": [":static_dep_for_shared"] + select({ + "//build/bazel/platforms/arch:arm": [":arm_static_dep_for_shared"], + "//conditions:default": [], + }) + select({ + "//build/bazel/platforms/os:android": [":android_dep_for_shared"], + "//conditions:default": [], + }), + "implementation_dynamic_deps": select({ "//build/bazel/platforms/arch:arm": [":arm_shared_dep_for_shared"], "//conditions:default": [], }), @@ -517,13 +623,6 @@ cc_library_static { name: "android_dep_for_shared" } "//build/bazel/platforms/os:android": ["android_shared.cpp"], "//conditions:default": [], }), - "static_deps": [":static_dep_for_shared"] + select({ - "//build/bazel/platforms/arch:arm": [":arm_static_dep_for_shared"], - "//conditions:default": [], - }) + select({ - "//build/bazel/platforms/os:android": [":android_dep_for_shared"], - "//conditions:default": [], - }), "whole_archive_deps": select({ "//build/bazel/platforms/arch:arm": [":arm_whole_static_dep_for_shared"], "//conditions:default": [], @@ -535,12 +634,12 @@ cc_library_static { name: "android_dep_for_shared" } "//build/bazel/platforms/arch:x86": ["-DX86_STATIC"], "//conditions:default": [], }), - "srcs": ["staticonly.cpp"] + select({ - "//build/bazel/platforms/arch:x86": ["x86_static.cpp"], + "implementation_deps": [":static_dep_for_static"] + select({ + "//build/bazel/platforms/arch:x86": [":x86_dep_for_static"], "//conditions:default": [], }), - "static_deps": [":static_dep_for_static"] + select({ - "//build/bazel/platforms/arch:x86": [":x86_dep_for_static"], + "srcs": ["staticonly.cpp"] + select({ + "//build/bazel/platforms/arch:x86": ["x86_static.cpp"], "//conditions:default": [], }), }, @@ -580,7 +679,7 @@ cc_library { "both_source.c", "both_source.s", "both_source.S", - ":both_filegroup", + ":both_filegroup", ], static: { srcs: [ @@ -633,9 +732,9 @@ filegroup { local_includes = ["."], shared = { "srcs": [ - ":shared_filegroup_cpp_srcs", - "shared_source.cc", "shared_source.cpp", + "shared_source.cc", + ":shared_filegroup_cpp_srcs", ], "srcs_as": [ "shared_source.s", @@ -648,9 +747,9 @@ filegroup { ], }, srcs = [ - ":both_filegroup_cpp_srcs", - "both_source.cc", "both_source.cpp", + "both_source.cc", + ":both_filegroup_cpp_srcs", ], srcs_as = [ "both_source.s", @@ -663,9 +762,9 @@ filegroup { ], static = { "srcs": [ - ":static_filegroup_cpp_srcs", - "static_source.cc", "static_source.cpp", + "static_source.cc", + ":static_filegroup_cpp_srcs", ], "srcs_as": [ "static_source.s", @@ -767,7 +866,7 @@ cc_library { `, expectedBazelTargets: []string{`cc_library( name = "a", - dynamic_deps = [":mylib"], + implementation_dynamic_deps = [":mylib"], )`}, }) } @@ -1013,13 +1112,6 @@ cc_library { expectedBazelTargets: []string{ `cc_library( name = "foo_static", - dynamic_deps = select({ - "//build/bazel/platforms/arch:arm": [], - "//conditions:default": [":arm_shared_lib_excludes"], - }) + select({ - "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_shared_lib"], - "//conditions:default": [], - }), implementation_deps = select({ "//build/bazel/platforms/arch:arm": [], "//conditions:default": [":arm_static_lib_excludes_bp2build_cc_library_static"], @@ -1027,6 +1119,13 @@ cc_library { "//build/bazel/product_variables:malloc_not_svelte": [], "//conditions:default": [":malloc_not_svelte_static_lib_excludes_bp2build_cc_library_static"], }), + implementation_dynamic_deps = select({ + "//build/bazel/platforms/arch:arm": [], + "//conditions:default": [":arm_shared_lib_excludes"], + }) + select({ + "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_shared_lib"], + "//conditions:default": [], + }), srcs_c = ["common.c"], whole_archive_deps = select({ "//build/bazel/platforms/arch:arm": [], diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go index 37d806cb1..e43672bea 100644 --- a/bp2build/cc_library_headers_conversion_test.go +++ b/bp2build/cc_library_headers_conversion_test.go @@ -224,7 +224,10 @@ cc_library_headers { cc_library_headers { name: "foo_headers", target: { - android: { header_libs: ["android-lib"], export_header_lib_headers: ["exported-lib"] }, + android: { + header_libs: ["android-lib", "exported-lib"], + export_header_lib_headers: ["exported-lib"] + }, }, include_build_directory: false, }`, diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go index 52a07cc47..3dcfbd7db 100644 --- a/bp2build/cc_library_shared_conversion_test.go +++ b/bp2build/cc_library_shared_conversion_test.go @@ -149,10 +149,6 @@ cc_library_shared { "-Dflag1", "-Dflag2", ], - dynamic_deps = [ - ":shared_lib_1", - ":shared_lib_2", - ], export_includes = [ "export_include_dir_1", "export_include_dir_2", @@ -161,6 +157,10 @@ cc_library_shared { ":header_lib_1", ":header_lib_2", ], + implementation_dynamic_deps = [ + ":shared_lib_1", + ":shared_lib_2", + ], local_includes = [ "local_include_dir_1", "local_include_dir_2", @@ -201,7 +201,7 @@ cc_library_shared { }`, expectedBazelTargets: []string{`cc_library_shared( name = "foo_shared", - dynamic_deps = select({ + implementation_dynamic_deps = select({ "//build/bazel/platforms/arch:arm64": [":shared_dep"], "//conditions:default": [], }), @@ -232,7 +232,7 @@ cc_library_shared { }`, expectedBazelTargets: []string{`cc_library_shared( name = "foo_shared", - dynamic_deps = select({ + implementation_dynamic_deps = select({ "//build/bazel/platforms/os:android": [":shared_dep"], "//conditions:default": [], }), @@ -269,7 +269,7 @@ cc_library_shared { }`, expectedBazelTargets: []string{`cc_library_shared( name = "foo_shared", - dynamic_deps = [":shared_dep"] + select({ + implementation_dynamic_deps = [":shared_dep"] + select({ "//build/bazel/platforms/arch:arm64": [":shared_dep3"], "//conditions:default": [], }) + select({ diff --git a/bp2build/conversion.go b/bp2build/conversion.go index 354abf6b7..0a86a79c5 100644 --- a/bp2build/conversion.go +++ b/bp2build/conversion.go @@ -142,7 +142,7 @@ func shouldGenerateAttribute(prop string) bool { } func shouldSkipStructField(field reflect.StructField) bool { - if field.PkgPath != "" { + if field.PkgPath != "" && !field.Anonymous { // Skip unexported fields. Some properties are // internal to Soong only, and these fields do not have PkgPath. return true diff --git a/bp2build/testing.go b/bp2build/testing.go index 74084b100..1e7e53c9f 100644 --- a/bp2build/testing.go +++ b/bp2build/testing.go @@ -20,6 +20,7 @@ specific-but-shared functionality among tests in package */ import ( + "fmt" "strings" "testing" @@ -358,3 +359,11 @@ func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) { ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutator) ctx.RegisterForBazelConversion() } + +func simpleModuleDoNotConvertBp2build(typ, name string) string { + return fmt.Sprintf(` +%s { + name: "%s", + bazel_module: { bp2build_available: false }, +}`, typ, name) +} diff --git a/cc/Android.bp b/cc/Android.bp index bff27610b..07aa7cbbe 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -60,9 +60,11 @@ bootstrap_go_package { "binary.go", "binary_sdk_member.go", "fuzz.go", + "image_sdk_traits.go", "library.go", "library_headers.go", "library_sdk_member.go", + "native_bridge_sdk_trait.go", "object.go", "test.go", "toolchain_library.go", diff --git a/cc/bp2build.go b/cc/bp2build.go index e48f757dc..22bd90bb0 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -14,12 +14,12 @@ package cc import ( - "fmt" "path/filepath" "strings" "android/soong/android" "android/soong/bazel" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -33,26 +33,16 @@ type staticOrSharedAttributes struct { Srcs_as bazel.LabelListAttribute Copts bazel.StringListAttribute - Static_deps bazel.LabelListAttribute - Dynamic_deps bazel.LabelListAttribute - Whole_archive_deps bazel.LabelListAttribute + Deps bazel.LabelListAttribute + Implementation_deps bazel.LabelListAttribute + Dynamic_deps bazel.LabelListAttribute + Implementation_dynamic_deps bazel.LabelListAttribute + Whole_archive_deps bazel.LabelListAttribute System_dynamic_deps bazel.LabelListAttribute } func groupSrcsByExtension(ctx android.TopDownMutatorContext, srcs bazel.LabelListAttribute) (cppSrcs, cSrcs, asSrcs bazel.LabelListAttribute) { - // Branch srcs into three language-specific groups. - // C++ is the "catch-all" group, and comprises generated sources because we don't - // know the language of these sources until the genrule is executed. - // TODO(b/190006308): Handle language detection of sources in a Bazel rule. - isCSrcOrFilegroup := func(s string) bool { - return strings.HasSuffix(s, ".c") || strings.HasSuffix(s, "_c_srcs") - } - - isAsmSrcOrFilegroup := func(s string) bool { - return strings.HasSuffix(s, ".S") || strings.HasSuffix(s, ".s") || strings.HasSuffix(s, "_as_srcs") - } - // Check that a module is a filegroup type named <label>. isFilegroupNamed := func(m android.Module, fullLabel string) bool { if ctx.OtherModuleType(m) != "filegroup" { @@ -61,54 +51,39 @@ func groupSrcsByExtension(ctx android.TopDownMutatorContext, srcs bazel.LabelLis labelParts := strings.Split(fullLabel, ":") if len(labelParts) > 2 { // There should not be more than one colon in a label. - panic(fmt.Errorf("%s is not a valid Bazel label for a filegroup", fullLabel)) - } else { - return m.Name() == labelParts[len(labelParts)-1] + ctx.ModuleErrorf("%s is not a valid Bazel label for a filegroup", fullLabel) } + return m.Name() == labelParts[len(labelParts)-1] } - // Convert the filegroup dependencies into the extension-specific filegroups - // filtered in the filegroup.bzl macro. - cppFilegroup := func(label string) string { - m, exists := ctx.ModuleFromName(label) - if exists { - aModule, _ := m.(android.Module) - if isFilegroupNamed(aModule, label) { - label = label + "_cpp_srcs" + // Convert filegroup dependencies into extension-specific filegroups filtered in the filegroup.bzl + // macro. + addSuffixForFilegroup := func(suffix string) bazel.LabelMapper { + return func(ctx bazel.OtherModuleContext, label string) (string, bool) { + m, exists := ctx.ModuleFromName(label) + if !exists { + return label, false } - } - return label - } - cFilegroup := func(label string) string { - m, exists := ctx.ModuleFromName(label) - if exists { aModule, _ := m.(android.Module) - if isFilegroupNamed(aModule, label) { - label = label + "_c_srcs" + if !isFilegroupNamed(aModule, label) { + return label, false } + return label + suffix, true } - return label } - asFilegroup := func(label string) string { - m, exists := ctx.ModuleFromName(label) - if exists { - aModule, _ := m.(android.Module) - if isFilegroupNamed(aModule, label) { - label = label + "_as_srcs" - } - } - return label - } - - cSrcs = bazel.MapLabelListAttribute(srcs, cFilegroup) - cSrcs = bazel.FilterLabelListAttribute(cSrcs, isCSrcOrFilegroup) - - asSrcs = bazel.MapLabelListAttribute(srcs, asFilegroup) - asSrcs = bazel.FilterLabelListAttribute(asSrcs, isAsmSrcOrFilegroup) - cppSrcs = bazel.MapLabelListAttribute(srcs, cppFilegroup) - cppSrcs = bazel.SubtractBazelLabelListAttribute(cppSrcs, cSrcs) - cppSrcs = bazel.SubtractBazelLabelListAttribute(cppSrcs, asSrcs) + // TODO(b/190006308): Handle language detection of sources in a Bazel rule. + partitioned := bazel.PartitionLabelListAttribute(ctx, &srcs, bazel.LabelPartitions{ + "c": bazel.LabelPartition{Extensions: []string{".c"}, LabelMapper: addSuffixForFilegroup("_c_srcs")}, + "as": bazel.LabelPartition{Extensions: []string{".s", ".S"}, LabelMapper: addSuffixForFilegroup("_as_srcs")}, + // C++ is the "catch-all" group, and comprises generated sources because we don't + // know the language of these sources until the genrule is executed. + "cpp": bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true}, + }) + + cSrcs = partitioned["c"] + asSrcs = partitioned["as"] + cppSrcs = partitioned["cpp"] return } @@ -131,16 +106,50 @@ func bp2BuildParseStaticProps(ctx android.TopDownMutatorContext, module *Module) return bp2BuildParseLibProps(ctx, module, true) } +type depsPartition struct { + export bazel.LabelList + implementation bazel.LabelList +} + +type bazelLabelForDepsFn func(android.TopDownMutatorContext, []string) bazel.LabelList + +func partitionExportedAndImplementationsDeps(ctx android.TopDownMutatorContext, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition { + implementation, export := android.FilterList(allDeps, exportedDeps) + + return depsPartition{ + export: fn(ctx, export), + implementation: fn(ctx, implementation), + } +} + +type bazelLabelForDepsExcludesFn func(android.TopDownMutatorContext, []string, []string) bazel.LabelList + +func partitionExportedAndImplementationsDepsExcludes(ctx android.TopDownMutatorContext, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition { + implementation, export := android.FilterList(allDeps, exportedDeps) + + return depsPartition{ + export: fn(ctx, export, excludes), + implementation: fn(ctx, implementation, excludes), + } +} + func bp2buildParseStaticOrSharedProps(ctx android.TopDownMutatorContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes { attrs := staticOrSharedAttributes{} setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) { attrs.Copts.SetSelectValue(axis, config, props.Cflags) attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs)) - attrs.Static_deps.SetSelectValue(axis, config, bazelLabelForStaticDeps(ctx, props.Static_libs)) - attrs.Dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.Shared_libs)) - attrs.Whole_archive_deps.SetSelectValue(axis, config, bazelLabelForWholeDeps(ctx, props.Whole_static_libs)) attrs.System_dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.System_shared_libs)) + + staticDeps := partitionExportedAndImplementationsDeps(ctx, props.Static_libs, props.Export_static_lib_headers, bazelLabelForStaticDeps) + attrs.Deps.SetSelectValue(axis, config, staticDeps.export) + attrs.Implementation_deps.SetSelectValue(axis, config, staticDeps.implementation) + + sharedDeps := partitionExportedAndImplementationsDeps(ctx, props.Shared_libs, props.Export_shared_lib_headers, bazelLabelForSharedDeps) + attrs.Dynamic_deps.SetSelectValue(axis, config, sharedDeps.export) + attrs.Implementation_dynamic_deps.SetSelectValue(axis, config, sharedDeps.implementation) + + attrs.Whole_archive_deps.SetSelectValue(axis, config, bazelLabelForWholeDeps(ctx, props.Whole_static_libs)) } // system_dynamic_deps distinguishes between nil/empty list behavior: // nil -> use default values @@ -217,6 +226,7 @@ type compilerAttributes struct { srcs bazel.LabelListAttribute rtti bazel.BoolAttribute + stl *string localIncludes bazel.StringListAttribute absoluteIncludes bazel.StringListAttribute @@ -312,6 +322,24 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul srcs, cSrcs, asSrcs := groupSrcsByExtension(ctx, srcs) + var stl *string = nil + stlPropsByArch := module.GetArchVariantProperties(ctx, &StlProperties{}) + for _, configToProps := range stlPropsByArch { + for _, props := range configToProps { + if stlProps, ok := props.(*StlProperties); ok { + if stlProps.Stl != nil { + if stl == nil { + stl = stlProps.Stl + } else { + if stl != stlProps.Stl { + ctx.ModuleErrorf("Unsupported conversion: module with different stl for different variants: %s and %s", *stl, stlProps.Stl) + } + } + } + } + } + } + return compilerAttributes{ copts: copts, srcs: srcs, @@ -321,6 +349,7 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul conlyFlags: conlyFlags, cppFlags: cppFlags, rtti: rtti, + stl: stl, localIncludes: localIncludes, absoluteIncludes: absoluteIncludes, } @@ -328,11 +357,13 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul // Convenience struct to hold all attributes parsed from linker properties. type linkerAttributes struct { - deps bazel.LabelListAttribute - dynamicDeps bazel.LabelListAttribute - systemDynamicDeps bazel.LabelListAttribute - wholeArchiveDeps bazel.LabelListAttribute - exportedDeps bazel.LabelListAttribute + deps bazel.LabelListAttribute + implementationDeps bazel.LabelListAttribute + dynamicDeps bazel.LabelListAttribute + implementationDynamicDeps bazel.LabelListAttribute + wholeArchiveDeps bazel.LabelListAttribute + systemDynamicDeps bazel.LabelListAttribute + useLibcrt bazel.BoolAttribute linkopts bazel.StringListAttribute versionScript bazel.LabelAttribute @@ -355,12 +386,16 @@ func getBp2BuildLinkerFlags(linkerProperties *BaseLinkerProperties) []string { // bp2BuildParseLinkerProps parses the linker properties of a module, including // configurable attribute values. func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes { + var headerDeps bazel.LabelListAttribute - var staticDeps bazel.LabelListAttribute - var exportedDeps bazel.LabelListAttribute + var implementationHeaderDeps bazel.LabelListAttribute + var deps bazel.LabelListAttribute + var implementationDeps bazel.LabelListAttribute var dynamicDeps bazel.LabelListAttribute + var implementationDynamicDeps bazel.LabelListAttribute var wholeArchiveDeps bazel.LabelListAttribute systemSharedDeps := bazel.LabelListAttribute{ForceSpecifyEmptyList: true} + var linkopts bazel.StringListAttribute var versionScript bazel.LabelAttribute var useLibcrt bazel.BoolAttribute @@ -386,12 +421,16 @@ func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) for axis, configToProps := range module.GetArchVariantProperties(ctx, &BaseLinkerProperties{}) { for config, props := range configToProps { if baseLinkerProps, ok := props.(*BaseLinkerProperties); ok { + // Excludes to parallel Soong: // https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=247-249;drc=088b53577dde6e40085ffd737a1ae96ad82fc4b0 staticLibs := android.FirstUniqueStrings(baseLinkerProps.Static_libs) - staticDeps.SetSelectValue(axis, config, bazelLabelForStaticDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs)) - wholeArchiveLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs) - wholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs)) + staticDeps := partitionExportedAndImplementationsDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs, baseLinkerProps.Export_static_lib_headers, bazelLabelForStaticDepsExcludes) + deps.SetSelectValue(axis, config, staticDeps.export) + implementationDeps.SetSelectValue(axis, config, staticDeps.implementation) + + wholeStaticLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs) + wholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, wholeStaticLibs, baseLinkerProps.Exclude_static_libs)) systemSharedLibs := baseLinkerProps.System_shared_libs // systemSharedLibs distinguishes between nil/empty list behavior: @@ -403,12 +442,15 @@ func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) systemSharedDeps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, systemSharedLibs)) sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs) - dynamicDeps.SetSelectValue(axis, config, bazelLabelForSharedDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs)) + sharedDeps := partitionExportedAndImplementationsDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs, baseLinkerProps.Export_shared_lib_headers, bazelLabelForSharedDepsExcludes) + dynamicDeps.SetSelectValue(axis, config, sharedDeps.export) + implementationDynamicDeps.SetSelectValue(axis, config, sharedDeps.implementation) headerLibs := android.FirstUniqueStrings(baseLinkerProps.Header_libs) - headerDeps.SetSelectValue(axis, config, bazelLabelForHeaderDeps(ctx, headerLibs)) - exportedLibs := android.FirstUniqueStrings(baseLinkerProps.Export_header_lib_headers) - exportedDeps.SetSelectValue(axis, config, bazelLabelForHeaderDeps(ctx, exportedLibs)) + hDeps := partitionExportedAndImplementationsDeps(ctx, headerLibs, baseLinkerProps.Export_header_lib_headers, bazelLabelForHeaderDeps) + + headerDeps.SetSelectValue(axis, config, hDeps.export) + implementationHeaderDeps.SetSelectValue(axis, config, hDeps.implementation) linkopts.SetSelectValue(axis, config, getBp2BuildLinkerFlags(baseLinkerProps)) if baseLinkerProps.Version_script != nil { @@ -430,8 +472,8 @@ func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) productVarToDepFields := map[string]productVarDep{ // product variables do not support exclude_shared_libs - "Shared_libs": productVarDep{attribute: &dynamicDeps, depResolutionFunc: bazelLabelForSharedDepsExcludes}, - "Static_libs": productVarDep{"Exclude_static_libs", &staticDeps, bazelLabelForStaticDepsExcludes}, + "Shared_libs": productVarDep{attribute: &implementationDynamicDeps, depResolutionFunc: bazelLabelForSharedDepsExcludes}, + "Static_libs": productVarDep{"Exclude_static_libs", &implementationDeps, bazelLabelForStaticDepsExcludes}, "Whole_static_libs": productVarDep{"Exclude_static_libs", &wholeArchiveDeps, bazelLabelForWholeDepsExcludes}, } @@ -471,21 +513,26 @@ func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) } } - staticDeps.ResolveExcludes() + headerDeps.Append(deps) + implementationHeaderDeps.Append(implementationDeps) + + headerDeps.ResolveExcludes() + implementationHeaderDeps.ResolveExcludes() dynamicDeps.ResolveExcludes() + implementationDynamicDeps.ResolveExcludes() wholeArchiveDeps.ResolveExcludes() - headerDeps.Append(staticDeps) - return linkerAttributes{ - deps: headerDeps, - exportedDeps: exportedDeps, - dynamicDeps: dynamicDeps, - systemDynamicDeps: systemSharedDeps, - wholeArchiveDeps: wholeArchiveDeps, - linkopts: linkopts, - useLibcrt: useLibcrt, - versionScript: versionScript, + deps: headerDeps, + implementationDeps: implementationHeaderDeps, + dynamicDeps: dynamicDeps, + implementationDynamicDeps: implementationDynamicDeps, + wholeArchiveDeps: wholeArchiveDeps, + systemDynamicDeps: systemSharedDeps, + + linkopts: linkopts, + useLibcrt: useLibcrt, + versionScript: versionScript, // Strip properties stripKeepSymbols: stripKeepSymbols, @@ -1711,7 +1711,9 @@ func (c *Module) setSubnameProperty(actx android.ModuleContext) { func (c *Module) maybeGenerateBazelActions(actx android.ModuleContext) bool { bazelModuleLabel := c.GetBazelLabel(actx, c) bazelActionsUsed := false - if c.MixedBuildsEnabled(actx) && c.bazelHandler != nil { + // Mixed builds mode is disabled for modules outside of device OS. + // TODO(b/200841190): Support non-device OS in mixed builds. + if c.MixedBuildsEnabled(actx) && c.bazelHandler != nil && actx.Os().Class == android.Device { bazelActionsUsed = c.bazelHandler.GenerateBazelBuildActions(actx, bazelModuleLabel) } return bazelActionsUsed diff --git a/cc/config/vndk.go b/cc/config/vndk.go index d4fcf7cac..e72efae87 100644 --- a/cc/config/vndk.go +++ b/cc/config/vndk.go @@ -47,17 +47,29 @@ var VndkMustUseVendorVariantList = []string{ "android.hardware.power-V1-ndk", "android.hardware.power-V1-ndk_platform", "android.hardware.power-ndk_platform", - "android.hardware.rebootescrow-V1-ndk", - "android.hardware.rebootescrow-V1-ndk_platform", "android.hardware.power.stats-V1-ndk", "android.hardware.power.stats-V1-ndk_platform", "android.hardware.power.stats-ndk_platform", "android.hardware.power.stats-unstable-ndk_platform", + "android.hardware.rebootescrow-V1-ndk", + "android.hardware.rebootescrow-V1-ndk_platform", + "android.hardware.rebootescrow-ndk_platform", "android.hardware.radio-V1-ndk", "android.hardware.radio-V1-ndk_platform", "android.hardware.radio.config-V1-ndk", "android.hardware.radio.config-V1-ndk_platform", - "android.hardware.rebootescrow-ndk_platform", + "android.hardware.radio.data-V1-ndk", + "android.hardware.radio.data-V1-ndk_platform", + "android.hardware.radio.messaging-V1-ndk", + "android.hardware.radio.messaging-V1-ndk_platform", + "android.hardware.radio.modem-V1-ndk", + "android.hardware.radio.modem-V1-ndk_platform", + "android.hardware.radio.network-V1-ndk", + "android.hardware.radio.network-V1-ndk_platform", + "android.hardware.radio.sim-V1-ndk", + "android.hardware.radio.sim-V1-ndk_platform", + "android.hardware.radio.voice-V1-ndk", + "android.hardware.radio.voice-V1-ndk_platform", "android.hardware.security.keymint-V1-ndk", "android.hardware.security.keymint-V1-ndk_platform", "android.hardware.security.keymint-ndk_platform", diff --git a/cc/genrule.go b/cc/genrule.go index 0ca901e61..9df52280e 100644 --- a/cc/genrule.go +++ b/cc/genrule.go @@ -21,7 +21,7 @@ import ( ) func init() { - android.RegisterModuleType("cc_genrule", genRuleFactory) + android.RegisterModuleType("cc_genrule", GenRuleFactory) } type GenruleExtraProperties struct { @@ -37,7 +37,7 @@ type GenruleExtraProperties struct { // cc_genrule is a genrule that can depend on other cc_* objects. // The cmd may be run multiple times, once for each of the different arch/etc // variations. -func genRuleFactory() android.Module { +func GenRuleFactory() android.Module { module := genrule.NewGenRule() extra := &GenruleExtraProperties{} @@ -48,6 +48,7 @@ func genRuleFactory() android.Module { android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibBoth) android.InitApexModule(module) + android.InitBazelModule(module) return module } diff --git a/cc/genrule_test.go b/cc/genrule_test.go index 45b343b5a..b6afb05a7 100644 --- a/cc/genrule_test.go +++ b/cc/genrule_test.go @@ -23,7 +23,7 @@ import ( func testGenruleContext(config android.Config) *android.TestContext { ctx := android.NewTestArchContext(config) - ctx.RegisterModuleType("cc_genrule", genRuleFactory) + ctx.RegisterModuleType("cc_genrule", GenRuleFactory) ctx.Register() return ctx diff --git a/cc/image_sdk_traits.go b/cc/image_sdk_traits.go new file mode 100644 index 000000000..1d282301c --- /dev/null +++ b/cc/image_sdk_traits.go @@ -0,0 +1,40 @@ +// 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 "android/soong/android" + +// This file contains support for the image variant sdk traits. + +func init() { + android.RegisterSdkMemberTrait(ramdiskImageRequiredSdkTrait) + android.RegisterSdkMemberTrait(recoveryImageRequiredSdkTrait) +} + +type imageSdkTraitStruct struct { + android.SdkMemberTraitBase +} + +var ramdiskImageRequiredSdkTrait android.SdkMemberTrait = &imageSdkTraitStruct{ + SdkMemberTraitBase: android.SdkMemberTraitBase{ + PropertyName: "ramdisk_image_required", + }, +} + +var recoveryImageRequiredSdkTrait android.SdkMemberTrait = &imageSdkTraitStruct{ + SdkMemberTraitBase: android.SdkMemberTraitBase{ + PropertyName: "recovery_image_required", + }, +} diff --git a/cc/library.go b/cc/library.go index 8a572f994..de9d01ede 100644 --- a/cc/library.go +++ b/cc/library.go @@ -232,12 +232,15 @@ type bazelCcLibraryAttributes struct { Conlyflags bazel.StringListAttribute Asflags bazel.StringListAttribute - Hdrs bazel.LabelListAttribute - Deps bazel.LabelListAttribute - Implementation_deps bazel.LabelListAttribute - Dynamic_deps bazel.LabelListAttribute - Whole_archive_deps bazel.LabelListAttribute - System_dynamic_deps bazel.LabelListAttribute + Hdrs bazel.LabelListAttribute + + Deps bazel.LabelListAttribute + Implementation_deps bazel.LabelListAttribute + Dynamic_deps bazel.LabelListAttribute + Implementation_dynamic_deps bazel.LabelListAttribute + Whole_archive_deps bazel.LabelListAttribute + System_dynamic_deps bazel.LabelListAttribute + Export_includes bazel.StringListAttribute Export_system_includes bazel.StringListAttribute Local_includes bazel.StringListAttribute @@ -245,6 +248,7 @@ type bazelCcLibraryAttributes struct { Linkopts bazel.StringListAttribute Use_libcrt bazel.BoolAttribute Rtti bazel.BoolAttribute + Stl *string // This is shared only. Version_script bazel.LabelAttribute @@ -306,18 +310,20 @@ func CcLibraryBp2Build(ctx android.TopDownMutatorContext) { Conlyflags: compilerAttrs.conlyFlags, Asflags: asFlags, - Implementation_deps: linkerAttrs.deps, - Deps: linkerAttrs.exportedDeps, - Dynamic_deps: linkerAttrs.dynamicDeps, - Whole_archive_deps: linkerAttrs.wholeArchiveDeps, - System_dynamic_deps: linkerAttrs.systemDynamicDeps, - Export_includes: exportedIncludes.Includes, - Export_system_includes: exportedIncludes.SystemIncludes, - Local_includes: compilerAttrs.localIncludes, - Absolute_includes: compilerAttrs.absoluteIncludes, - Linkopts: linkerAttrs.linkopts, - Use_libcrt: linkerAttrs.useLibcrt, - Rtti: compilerAttrs.rtti, + Implementation_deps: linkerAttrs.implementationDeps, + Deps: linkerAttrs.deps, + Implementation_dynamic_deps: linkerAttrs.implementationDynamicDeps, + Dynamic_deps: linkerAttrs.dynamicDeps, + Whole_archive_deps: linkerAttrs.wholeArchiveDeps, + System_dynamic_deps: linkerAttrs.systemDynamicDeps, + Export_includes: exportedIncludes.Includes, + Export_system_includes: exportedIncludes.SystemIncludes, + Local_includes: compilerAttrs.localIncludes, + Absolute_includes: compilerAttrs.absoluteIncludes, + Linkopts: linkerAttrs.linkopts, + Use_libcrt: linkerAttrs.useLibcrt, + Rtti: compilerAttrs.rtti, + Stl: compilerAttrs.stl, Version_script: linkerAttrs.versionScript, @@ -2349,9 +2355,11 @@ func ccSharedOrStaticBp2BuildMutatorInternal(ctx android.TopDownMutatorContext, compilerAttrs.cSrcs.Append(libSharedOrStaticAttrs.Srcs_c) compilerAttrs.asSrcs.Append(libSharedOrStaticAttrs.Srcs_as) compilerAttrs.copts.Append(libSharedOrStaticAttrs.Copts) - linkerAttrs.exportedDeps.Append(libSharedOrStaticAttrs.Static_deps) + + linkerAttrs.deps.Append(libSharedOrStaticAttrs.Deps) + linkerAttrs.implementationDeps.Append(libSharedOrStaticAttrs.Implementation_deps) linkerAttrs.dynamicDeps.Append(libSharedOrStaticAttrs.Dynamic_deps) - linkerAttrs.wholeArchiveDeps.Append(libSharedOrStaticAttrs.Whole_archive_deps) + linkerAttrs.implementationDynamicDeps.Append(libSharedOrStaticAttrs.Implementation_dynamic_deps) linkerAttrs.systemDynamicDeps.Append(libSharedOrStaticAttrs.System_dynamic_deps) asFlags := compilerAttrs.asFlags @@ -2360,44 +2368,42 @@ func ccSharedOrStaticBp2BuildMutatorInternal(ctx android.TopDownMutatorContext, asFlags = bazel.MakeStringListAttribute(nil) } + commonAttrs := staticOrSharedAttributes{ + Srcs: compilerAttrs.srcs, + Srcs_c: compilerAttrs.cSrcs, + Srcs_as: compilerAttrs.asSrcs, + Copts: compilerAttrs.copts, + + Deps: linkerAttrs.deps, + Implementation_deps: linkerAttrs.implementationDeps, + Dynamic_deps: linkerAttrs.dynamicDeps, + Implementation_dynamic_deps: linkerAttrs.implementationDynamicDeps, + Whole_archive_deps: linkerAttrs.wholeArchiveDeps, + System_dynamic_deps: linkerAttrs.systemDynamicDeps, + } + var attrs interface{} if isStatic { attrs = &bazelCcLibraryStaticAttributes{ - Copts: compilerAttrs.copts, - Srcs: compilerAttrs.srcs, - Implementation_deps: linkerAttrs.deps, - Deps: linkerAttrs.exportedDeps, - Whole_archive_deps: linkerAttrs.wholeArchiveDeps, - Dynamic_deps: linkerAttrs.dynamicDeps, - System_dynamic_deps: linkerAttrs.systemDynamicDeps, + staticOrSharedAttributes: commonAttrs, Linkopts: linkerAttrs.linkopts, Use_libcrt: linkerAttrs.useLibcrt, Rtti: compilerAttrs.rtti, + Stl: compilerAttrs.stl, Export_includes: exportedIncludes.Includes, Export_system_includes: exportedIncludes.SystemIncludes, Local_includes: compilerAttrs.localIncludes, Absolute_includes: compilerAttrs.absoluteIncludes, Cppflags: compilerAttrs.cppFlags, - Srcs_c: compilerAttrs.cSrcs, Conlyflags: compilerAttrs.conlyFlags, - Srcs_as: compilerAttrs.asSrcs, Asflags: asFlags, } } else { attrs = &bazelCcLibrarySharedAttributes{ - Srcs: compilerAttrs.srcs, - Srcs_c: compilerAttrs.cSrcs, - Srcs_as: compilerAttrs.asSrcs, - - Implementation_deps: linkerAttrs.deps, - Deps: linkerAttrs.exportedDeps, - Whole_archive_deps: linkerAttrs.wholeArchiveDeps, - Dynamic_deps: linkerAttrs.dynamicDeps, - System_dynamic_deps: linkerAttrs.systemDynamicDeps, + staticOrSharedAttributes: commonAttrs, - Copts: compilerAttrs.copts, Cppflags: compilerAttrs.cppFlags, Conlyflags: compilerAttrs.conlyFlags, Asflags: asFlags, @@ -2405,6 +2411,7 @@ func ccSharedOrStaticBp2BuildMutatorInternal(ctx android.TopDownMutatorContext, Use_libcrt: linkerAttrs.useLibcrt, Rtti: compilerAttrs.rtti, + Stl: compilerAttrs.stl, Export_includes: exportedIncludes.Includes, Export_system_includes: exportedIncludes.SystemIncludes, @@ -2432,16 +2439,13 @@ func ccSharedOrStaticBp2BuildMutatorInternal(ctx android.TopDownMutatorContext, // TODO(b/199902614): Can this be factored to share with the other Attributes? type bazelCcLibraryStaticAttributes struct { - Copts bazel.StringListAttribute - Srcs bazel.LabelListAttribute - Implementation_deps bazel.LabelListAttribute - Deps bazel.LabelListAttribute - Whole_archive_deps bazel.LabelListAttribute - Dynamic_deps bazel.LabelListAttribute - System_dynamic_deps bazel.LabelListAttribute - Linkopts bazel.StringListAttribute - Use_libcrt bazel.BoolAttribute - Rtti bazel.BoolAttribute + staticOrSharedAttributes + + Linkopts bazel.StringListAttribute + Use_libcrt bazel.BoolAttribute + Rtti bazel.BoolAttribute + Stl *string + Export_includes bazel.StringListAttribute Export_system_includes bazel.StringListAttribute Local_includes bazel.StringListAttribute @@ -2449,9 +2453,7 @@ type bazelCcLibraryStaticAttributes struct { Hdrs bazel.LabelListAttribute Cppflags bazel.StringListAttribute - Srcs_c bazel.LabelListAttribute Conlyflags bazel.StringListAttribute - Srcs_as bazel.LabelListAttribute Asflags bazel.StringListAttribute } @@ -2461,29 +2463,22 @@ func CcLibraryStaticBp2Build(ctx android.TopDownMutatorContext) { // TODO(b/199902614): Can this be factored to share with the other Attributes? type bazelCcLibrarySharedAttributes struct { - Srcs bazel.LabelListAttribute - Srcs_c bazel.LabelListAttribute - Srcs_as bazel.LabelListAttribute - - Implementation_deps bazel.LabelListAttribute - Deps bazel.LabelListAttribute - Whole_archive_deps bazel.LabelListAttribute - Dynamic_deps bazel.LabelListAttribute - System_dynamic_deps bazel.LabelListAttribute + staticOrSharedAttributes Linkopts bazel.StringListAttribute Use_libcrt bazel.BoolAttribute Rtti bazel.BoolAttribute - Strip stripAttributes + Stl *string Export_includes bazel.StringListAttribute Export_system_includes bazel.StringListAttribute Local_includes bazel.StringListAttribute Absolute_includes bazel.StringListAttribute Hdrs bazel.LabelListAttribute - Version_script bazel.LabelAttribute - Copts bazel.StringListAttribute + Strip stripAttributes + Version_script bazel.LabelAttribute + Cppflags bazel.StringListAttribute Conlyflags bazel.StringListAttribute Asflags bazel.StringListAttribute diff --git a/cc/library_headers.go b/cc/library_headers.go index 14b90c1e5..cabeb0156 100644 --- a/cc/library_headers.go +++ b/cc/library_headers.go @@ -33,6 +33,11 @@ var headersLibrarySdkMemberType = &librarySdkMemberType{ PropertyName: "native_header_libs", SupportsSdk: true, HostOsDependent: true, + Traits: []android.SdkMemberTrait{ + nativeBridgeSdkTrait, + ramdiskImageRequiredSdkTrait, + recoveryImageRequiredSdkTrait, + }, }, prebuiltModuleType: "cc_prebuilt_library_headers", noOutputFiles: true, @@ -132,8 +137,8 @@ func CcLibraryHeadersBp2Build(ctx android.TopDownMutatorContext) { attrs := &bazelCcLibraryHeadersAttributes{ Export_includes: exportedIncludes.Includes, Export_system_includes: exportedIncludes.SystemIncludes, - Implementation_deps: linkerAttrs.deps, - Deps: linkerAttrs.exportedDeps, + Implementation_deps: linkerAttrs.implementationDeps, + Deps: linkerAttrs.deps, System_dynamic_deps: linkerAttrs.systemDynamicDeps, } diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go index 559e94004..8988de2e5 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -75,29 +75,112 @@ type librarySdkMemberType struct { } func (mt *librarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) { - targets := ctx.MultiTargets() + // The base set of targets which does not include native bridge targets. + defaultTargets := ctx.MultiTargets() + + // The lazily created list of native bridge targets. + var includeNativeBridgeTargets []android.Target + for _, lib := range names { - for _, target := range targets { - name, version := StubsLibNameAndVersion(lib) - if version == "" { - version = "latest" + targets := defaultTargets + + // If native bridge support is required in the sdk snapshot then add native bridge targets to + // the basic list of targets that are required. + nativeBridgeSupport := ctx.RequiresTrait(lib, nativeBridgeSdkTrait) + if nativeBridgeSupport && ctx.Device() { + // If not already computed then compute the list of native bridge targets. + if includeNativeBridgeTargets == nil { + includeNativeBridgeTargets = append([]android.Target{}, defaultTargets...) + allAndroidTargets := ctx.Config().Targets[android.Android] + for _, possibleNativeBridgeTarget := range allAndroidTargets { + if possibleNativeBridgeTarget.NativeBridge == android.NativeBridgeEnabled { + includeNativeBridgeTargets = append(includeNativeBridgeTargets, possibleNativeBridgeTarget) + } + } + } + + // Include the native bridge targets as well. + targets = includeNativeBridgeTargets + } + + // memberDependency encapsulates information about the dependencies to add for this member. + type memberDependency struct { + // The targets to depend upon. + targets []android.Target + + // Additional image variations to depend upon, is either nil for no image variation or + // contains a single image variation. + imageVariations []blueprint.Variation + } + + // Extract the name and version from the module name. + name, version := StubsLibNameAndVersion(lib) + if version == "" { + version = "latest" + } + + // Compute the set of dependencies to add. + var memberDependencies []memberDependency + if ctx.Host() { + // Host does not support image variations so add a dependency without any. + memberDependencies = append(memberDependencies, memberDependency{ + targets: targets, + }) + } else { + // Otherwise, this is targeting the device so add a dependency on the core image variation + // (image:""). + memberDependencies = append(memberDependencies, memberDependency{ + imageVariations: []blueprint.Variation{{Mutator: "image", Variation: android.CoreVariation}}, + targets: targets, + }) + + // If required add additional dependencies on the image:ramdisk variants. + if ctx.RequiresTrait(lib, ramdiskImageRequiredSdkTrait) { + memberDependencies = append(memberDependencies, memberDependency{ + imageVariations: []blueprint.Variation{{Mutator: "image", Variation: android.RamdiskVariation}}, + // Only add a dependency on the first target as that is the only one which will have an + // image:ramdisk variant. + targets: targets[:1], + }) } - variations := target.Variations() - if ctx.Device() { - variations = append(variations, - blueprint.Variation{Mutator: "image", Variation: android.CoreVariation}) + + // If required add additional dependencies on the image:recovery variants. + if ctx.RequiresTrait(lib, recoveryImageRequiredSdkTrait) { + memberDependencies = append(memberDependencies, memberDependency{ + imageVariations: []blueprint.Variation{{Mutator: "image", Variation: android.RecoveryVariation}}, + // Only add a dependency on the first target as that is the only one which will have an + // image:recovery variant. + targets: targets[:1], + }) } - if mt.linkTypes == nil { - ctx.AddFarVariationDependencies(variations, dependencyTag, name) - } else { - for _, linkType := range mt.linkTypes { - libVariations := append(variations, - blueprint.Variation{Mutator: "link", Variation: linkType}) - if ctx.Device() && linkType == "shared" { - libVariations = append(libVariations, - blueprint.Variation{Mutator: "version", Variation: version}) + } + + // For each dependency in the list add dependencies on the targets with the correct variations. + for _, dependency := range memberDependencies { + // For each target add a dependency on the target with any additional dependencies. + for _, target := range dependency.targets { + // Get the variations for the target. + variations := target.Variations() + + // Add any additional dependencies needed. + variations = append(variations, dependency.imageVariations...) + + if mt.linkTypes == nil { + // No link types are supported so add a dependency directly. + ctx.AddFarVariationDependencies(variations, dependencyTag, name) + } else { + // Otherwise, add a dependency on each supported link type in turn. + for _, linkType := range mt.linkTypes { + libVariations := append(variations, + blueprint.Variation{Mutator: "link", Variation: linkType}) + // If this is for the device and a shared link type then add a dependency onto the + // appropriate version specific variant of the module. + if ctx.Device() && linkType == "shared" { + libVariations = append(libVariations, + blueprint.Variation{Mutator: "version", Variation: version}) + } + ctx.AddFarVariationDependencies(libVariations, dependencyTag, name) } - ctx.AddFarVariationDependencies(libVariations, dependencyTag, name) } } } @@ -122,7 +205,15 @@ func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, ccModule := member.Variants()[0].(*Module) - if proptools.Bool(ccModule.Properties.Recovery_available) { + if ctx.RequiresTrait(nativeBridgeSdkTrait) { + pbm.AddProperty("native_bridge_supported", true) + } + + if ctx.RequiresTrait(ramdiskImageRequiredSdkTrait) { + pbm.AddProperty("ramdisk_available", true) + } + + if ctx.RequiresTrait(recoveryImageRequiredSdkTrait) { pbm.AddProperty("recovery_available", true) } @@ -436,7 +527,11 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate( exportedInfo.IncludeDirs, isGeneratedHeaderDirectory) - p.archSubDir = ccModule.Target().Arch.ArchType.String() + target := ccModule.Target() + p.archSubDir = target.Arch.ArchType.String() + if target.NativeBridge == android.NativeBridgeEnabled { + p.archSubDir += "_native_bridge" + } // Make sure that the include directories are unique. p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs) diff --git a/cc/native_bridge_sdk_trait.go b/cc/native_bridge_sdk_trait.go new file mode 100644 index 000000000..1326d5750 --- /dev/null +++ b/cc/native_bridge_sdk_trait.go @@ -0,0 +1,33 @@ +// 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 "android/soong/android" + +// This file contains support for the native bridge sdk trait. + +func init() { + android.RegisterSdkMemberTrait(nativeBridgeSdkTrait) +} + +type nativeBridgeSdkTraitStruct struct { + android.SdkMemberTraitBase +} + +var nativeBridgeSdkTrait android.SdkMemberTrait = &nativeBridgeSdkTraitStruct{ + SdkMemberTraitBase: android.SdkMemberTraitBase{ + PropertyName: "native_bridge_support", + }, +} diff --git a/cc/testing.go b/cc/testing.go index d0dca6b53..b0a220cff 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -33,7 +33,7 @@ func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { ctx.RegisterModuleType("toolchain_library", ToolchainLibraryFactory) ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory) ctx.RegisterModuleType("cc_object", ObjectFactory) - ctx.RegisterModuleType("cc_genrule", genRuleFactory) + ctx.RegisterModuleType("cc_genrule", GenRuleFactory) ctx.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory) ctx.RegisterModuleType("ndk_prebuilt_static_stl", NdkPrebuiltStaticStlFactory) ctx.RegisterModuleType("ndk_prebuilt_object", NdkPrebuiltObjectFactory) diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index 7733c1b43..965b7552d 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -261,10 +261,18 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g clcTarget = append(clcTarget, GetSystemServerDexLocation(global, lib)) } - // Copy the system server jar to a predefined location where dex2oat will find it. - dexPathHost := SystemServerDexJarHostPath(ctx, module.Name) - rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String())) - rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost) + if DexpreoptRunningInSoong { + // Copy the system server jar to a predefined location where dex2oat will find it. + dexPathHost := SystemServerDexJarHostPath(ctx, module.Name) + rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String())) + rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost) + } else { + // For Make modules the copy rule is generated in the makefiles, not in dexpreopt.sh. + // This is necessary to expose the rule to Ninja, otherwise it has rules that depend on + // the jar (namely, dexpreopt commands for all subsequent system server jars that have + // this one in their class loader context), but no rule that creates it (because Ninja + // cannot see the rule in the generated dexpreopt.sh script). + } checkSystemServerOrder(ctx, jarIndex) diff --git a/genrule/genrule.go b/genrule/genrule.go index bde6e9772..f4bde703a 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -69,6 +69,7 @@ func RegisterGenruleBuildComponents(ctx android.RegistrationContext) { }) android.RegisterBp2BuildMutator("genrule", GenruleBp2Build) + android.RegisterBp2BuildMutator("cc_genrule", CcGenruleBp2Build) } func RegisterGenruleBp2BuildDeps(ctx android.RegisterMutatorsContext) { @@ -826,6 +827,22 @@ type bazelGenruleAttributes struct { Cmd string } +// CcGenruleBp2Build is for cc_genrule. +func CcGenruleBp2Build(ctx android.TopDownMutatorContext) { + m, ok := ctx.Module().(*Module) + if !ok || !m.ConvertWithBp2build(ctx) { + return + } + + if ctx.ModuleType() != "cc_genrule" { + // Not a cc_genrule. + return + } + + genruleBp2Build(ctx) +} + +// GenruleBp2Build is used for genrule. func GenruleBp2Build(ctx android.TopDownMutatorContext) { m, ok := ctx.Module().(*Module) if !ok || !m.ConvertWithBp2build(ctx) { @@ -833,10 +850,15 @@ func GenruleBp2Build(ctx android.TopDownMutatorContext) { } if ctx.ModuleType() != "genrule" { - // Not a regular genrule. Could be a cc_genrule or java_genrule. + // Not a regular genrule. return } + genruleBp2Build(ctx) +} + +func genruleBp2Build(ctx android.TopDownMutatorContext) { + m, _ := ctx.Module().(*Module) // Bazel only has the "tools" attribute. tools_prop := android.BazelLabelForModuleDeps(ctx, m.properties.Tools) tool_files_prop := android.BazelLabelForModuleSrc(ctx, m.properties.Tool_files) @@ -854,7 +876,11 @@ func GenruleBp2Build(ctx android.TopDownMutatorContext) { if m.properties.Cmd != nil { cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1) cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1) - cmd = strings.Replace(cmd, "$(genDir)", "$(GENDIR)", -1) + genDir := "$(GENDIR)" + if ctx.ModuleType() == "cc_genrule" { + genDir = "$(RULEDIR)" + } + cmd = strings.Replace(cmd, "$(genDir)", genDir, -1) if len(tools.Value.Includes) > 0 { cmd = strings.Replace(cmd, "$(location)", fmt.Sprintf("$(location %s)", tools.Value.Includes[0].Label), -1) cmd = strings.Replace(cmd, "$(locations)", fmt.Sprintf("$(locations %s)", tools.Value.Includes[0].Label), -1) diff --git a/java/androidmk.go b/java/androidmk.go index 71370c9b1..1914595dc 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -29,8 +29,8 @@ func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries { if hostDexNeeded { var output android.Path - if library.dexJarFile != nil { - output = library.dexJarFile + if library.dexJarFile.IsSet() { + output = library.dexJarFile.Path() } else { output = library.implementationAndResourcesJar } @@ -44,8 +44,8 @@ func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries { func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.SetBool("LOCAL_IS_HOST_MODULE", true) entries.SetPath("LOCAL_PREBUILT_MODULE_FILE", output) - if library.dexJarFile != nil { - entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile) + if library.dexJarFile.IsSet() { + entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile.Path()) } entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar) @@ -106,8 +106,8 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { if library.installFile == nil { entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true) } - if library.dexJarFile != nil { - entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile) + if library.dexJarFile.IsSet() { + entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile.Path()) } if len(library.dexpreopter.builtInstalled) > 0 { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", library.dexpreopter.builtInstalled) @@ -207,8 +207,8 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries { ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable)) - if prebuilt.dexJarFile != nil { - entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile) + if prebuilt.dexJarFile.IsSet() { + entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile.Path()) } entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile) @@ -227,12 +227,12 @@ func (prebuilt *DexImport) AndroidMkEntries() []android.AndroidMkEntries { } return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", - OutputFile: android.OptionalPathForPath(prebuilt.dexJarFile), + OutputFile: android.OptionalPathForPath(prebuilt.dexJarFile.Path()), Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - if prebuilt.dexJarFile != nil { - entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile) + if prebuilt.dexJarFile.IsSet() { + entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile.Path()) } if len(prebuilt.dexpreopter.builtInstalled) > 0 { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", prebuilt.dexpreopter.builtInstalled) @@ -279,8 +279,8 @@ func (binary *Binary) AndroidMkEntries() []android.AndroidMkEntries { func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.SetPath("LOCAL_SOONG_HEADER_JAR", binary.headerJarFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", binary.implementationAndResourcesJar) - if binary.dexJarFile != nil { - entries.SetPath("LOCAL_SOONG_DEX_JAR", binary.dexJarFile) + if binary.dexJarFile.IsSet() { + entries.SetPath("LOCAL_SOONG_DEX_JAR", binary.dexJarFile.Path()) } if len(binary.dexpreopter.builtInstalled) > 0 { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", binary.dexpreopter.builtInstalled) @@ -336,8 +336,8 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { entries.SetString("LOCAL_MODULE", app.installApkName) entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", app.appProperties.PreventInstall) entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", app.exportPackage) - if app.dexJarFile != nil { - entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile) + if app.dexJarFile.IsSet() { + entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile.Path()) } if app.implementationAndResourcesJar != nil { entries.SetPath("LOCAL_SOONG_CLASSES_JAR", app.implementationAndResourcesJar) diff --git a/java/app.go b/java/app.go index a62e442ac..2fd646322 100755 --- a/java/app.go +++ b/java/app.go @@ -476,7 +476,7 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { a.Module.compile(ctx, a.aaptSrcJar) } - return a.dexJarFile + return a.dexJarFile.PathOrNil() } func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath { @@ -1305,7 +1305,8 @@ func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext replaceInList(u.usesLibraryProperties.Optional_uses_libs, dep, libName) } clcMap.AddContext(ctx, tag.sdkVersion, libName, tag.optional, tag.implicit, - lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ClassLoaderContexts()) + lib.DexJarBuildPath().PathOrNil(), lib.DexJarInstallPath(), + lib.ClassLoaderContexts()) } else if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{dep}) } else { diff --git a/java/base.go b/java/base.go index 78aaa19cf..579085b8a 100644 --- a/java/base.go +++ b/java/base.go @@ -276,6 +276,87 @@ func (e *embeddableInModuleAndImport) depIsInSameApex(ctx android.BaseModuleCont return false } +// OptionalDexJarPath can be either unset, hold a valid path to a dex jar file, +// or an invalid path describing the reason it is invalid. +// +// It is unset if a dex jar isn't applicable, i.e. no build rule has been +// requested to create one. +// +// If a dex jar has been requested to be built then it is set, and it may be +// either a valid android.Path, or invalid with a reason message. The latter +// happens if the source that should produce the dex file isn't able to. +// +// E.g. it is invalid with a reason message if there is a prebuilt APEX that +// could produce the dex jar through a deapexer module, but the APEX isn't +// installable so doing so wouldn't be safe. +type OptionalDexJarPath struct { + isSet bool + path android.OptionalPath +} + +// IsSet returns true if a path has been set, either invalid or valid. +func (o OptionalDexJarPath) IsSet() bool { + return o.isSet +} + +// Valid returns true if there is a path that is valid. +func (o OptionalDexJarPath) Valid() bool { + return o.isSet && o.path.Valid() +} + +// Path returns the valid path, or panics if it's either not set or is invalid. +func (o OptionalDexJarPath) Path() android.Path { + if !o.isSet { + panic("path isn't set") + } + return o.path.Path() +} + +// PathOrNil returns the path if it's set and valid, or else nil. +func (o OptionalDexJarPath) PathOrNil() android.Path { + if o.Valid() { + return o.Path() + } + return nil +} + +// InvalidReason returns the reason for an invalid path, which is never "". It +// returns "" for an unset or valid path. +func (o OptionalDexJarPath) InvalidReason() string { + if !o.isSet { + return "" + } + return o.path.InvalidReason() +} + +func (o OptionalDexJarPath) String() string { + if !o.isSet { + return "<unset>" + } + return o.path.String() +} + +// makeUnsetDexJarPath returns an unset OptionalDexJarPath. +func makeUnsetDexJarPath() OptionalDexJarPath { + return OptionalDexJarPath{isSet: false} +} + +// makeDexJarPathFromOptionalPath returns an OptionalDexJarPath that is set with +// the given OptionalPath, which may be valid or invalid. +func makeDexJarPathFromOptionalPath(path android.OptionalPath) OptionalDexJarPath { + return OptionalDexJarPath{isSet: true, path: path} +} + +// makeDexJarPathFromPath returns an OptionalDexJarPath that is set with the +// valid given path. It returns an unset OptionalDexJarPath if the given path is +// nil. +func makeDexJarPathFromPath(path android.Path) OptionalDexJarPath { + if path == nil { + return makeUnsetDexJarPath() + } + return makeDexJarPathFromOptionalPath(android.OptionalPathForPath(path)) +} + // Module contains the properties and members used by all java module types type Module struct { android.ModuleBase @@ -310,7 +391,7 @@ type Module struct { implementationAndResourcesJar android.Path // output file containing classes.dex and resources - dexJarFile android.Path + dexJarFile OptionalDexJarPath // output file containing uninstrumented classes that will be instrumented by jacoco jacocoReportClassesFile android.Path @@ -1265,12 +1346,13 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } // Initialize the hiddenapi structure. - j.initHiddenAPI(ctx, dexOutputFile, j.implementationJarFile, j.dexProperties.Uncompress_dex) + + j.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), j.implementationJarFile, j.dexProperties.Uncompress_dex) // Encode hidden API flags in dex file, if needed. dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile) - j.dexJarFile = dexOutputFile + j.dexJarFile = makeDexJarPathFromPath(dexOutputFile) // Dexpreopting j.dexpreopt(ctx, dexOutputFile) @@ -1280,7 +1362,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // There is no code to compile into a dex jar, make sure the resources are propagated // to the APK if this is an app. outputFile = implementationAndResourcesJar - j.dexJarFile = j.resourceJar + j.dexJarFile = makeDexJarPathFromPath(j.resourceJar) } if ctx.Failed() { @@ -1470,7 +1552,7 @@ func (j *Module) ImplementationJars() android.Paths { return android.Paths{j.implementationJarFile} } -func (j *Module) DexJarBuildPath() android.Path { +func (j *Module) DexJarBuildPath() OptionalDexJarPath { return j.dexJarFile } diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index b13e2dba4..79c73ca87 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -954,23 +954,11 @@ func (module *prebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx and return nil } - var deapexerModule android.Module - ctx.VisitDirectDeps(func(module android.Module) { - tag := ctx.OtherModuleDependencyTag(module) - // Save away the `deapexer` module on which this depends, if any. - if tag == android.DeapexerTag { - deapexerModule = module - } - }) - - if deapexerModule == nil { - // This should never happen as a variant for a prebuilt_apex is only created if the - // deapexer module has been configured to export the dex implementation jar for this module. - ctx.ModuleErrorf("internal error: module does not depend on a `deapexer` module") - return nil + di := android.FindDeapexerProviderForModule(ctx) + if di == nil { + return nil // An error has been reported by FindDeapexerProviderForModule. } - di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo) files := bootImageFilesByArch{} for _, variant := range imageConfig.apexVariants() { arch := variant.target.Arch.ArchType diff --git a/java/droidstubs.go b/java/droidstubs.go index ec1b04a06..7fd88fceb 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -156,6 +156,7 @@ type ApiStubsSrcProvider interface { // Provider of information about API stubs, used by java_sdk_library. type ApiStubsProvider interface { + AnnotationsZip() android.Path ApiFilePath RemovedApiFilePath() android.Path @@ -210,6 +211,10 @@ func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) { } } +func (d *Droidstubs) AnnotationsZip() android.Path { + return d.annotationsZip +} + func (d *Droidstubs) ApiFilePath() android.Path { return d.apiFilePath } diff --git a/java/hiddenapi.go b/java/hiddenapi.go index 30683daa0..7c8be1e6e 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -30,14 +30,14 @@ type hiddenAPI struct { // that information encoded within it. active bool - // The path to the dex jar that is in the boot class path. If this is nil then the associated + // The path to the dex jar that is in the boot class path. If this is unset then the associated // module is not a boot jar, but could be one of the <x>-hiddenapi modules that provide additional // annotations for the <x> boot dex jar but which do not actually provide a boot dex jar // themselves. // // This must be the path to the unencoded dex jar as the encoded dex jar indirectly depends on // this file so using the encoded dex jar here would result in a cycle in the ninja rules. - bootDexJarPath android.Path + bootDexJarPath OptionalDexJarPath // The paths to the classes jars that contain classes and class members annotated with // the UnsupportedAppUsage annotation that need to be extracted as part of the hidden API @@ -49,7 +49,7 @@ type hiddenAPI struct { uncompressDexState *bool } -func (h *hiddenAPI) bootDexJar() android.Path { +func (h *hiddenAPI) bootDexJar() OptionalDexJarPath { return h.bootDexJarPath } @@ -68,7 +68,7 @@ type hiddenAPIModule interface { } type hiddenAPIIntf interface { - bootDexJar() android.Path + bootDexJar() OptionalDexJarPath classesJars() android.Paths uncompressDex() *bool } @@ -79,7 +79,7 @@ var _ hiddenAPIIntf = (*hiddenAPI)(nil) // // uncompressedDexState should be nil when the module is a prebuilt and so does not require hidden // API encoding. -func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar, classesJar android.Path, uncompressedDexState *bool) { +func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar OptionalDexJarPath, classesJar android.Path, uncompressedDexState *bool) { // Save the classes jars even if this is not active as they may be used by modular hidden API // processing. diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index 1c6fbac72..b9a1ca74d 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -19,6 +19,7 @@ import ( "strings" "android/soong/android" + "github.com/google/blueprint" ) @@ -277,7 +278,7 @@ func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, apiScop // hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if // available, or reports an error. func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path { - var dexJar android.Path + var dexJar OptionalDexJarPath if sdkLibrary, ok := module.(SdkLibraryDependency); ok { dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind) } else if j, ok := module.(UsesLibraryDependency); ok { @@ -287,10 +288,11 @@ func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android. return nil } - if dexJar == nil { - ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module) + if !dexJar.Valid() { + ctx.ModuleErrorf("dependency %s does not provide a dex jar: %s", module, dexJar.InvalidReason()) + return nil } - return dexJar + return dexJar.Path() } // buildRuleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file. @@ -1159,18 +1161,17 @@ func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android // retrieveBootDexJarFromHiddenAPIModule retrieves the boot dex jar from the hiddenAPIModule. // -// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is nil, then that -// create a fake path and either report an error immediately or defer reporting of the error until -// the path is actually used. +// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is unset or +// invalid, then create a fake path and either report an error immediately or defer reporting of the +// error until the path is actually used. func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path { bootDexJar := module.bootDexJar() - if bootDexJar == nil { + if !bootDexJar.Valid() { fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name())) - bootDexJar = fake - - handleMissingDexBootFile(ctx, module, fake) + handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason()) + return fake } - return bootDexJar + return bootDexJar.Path() } // extractClassesJarsFromModules extracts the class jars from the supplied modules. @@ -1264,7 +1265,7 @@ func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.M // handleMissingDexBootFile will either log a warning or create an error rule to create the fake // file depending on the value returned from deferReportingMissingBootDexJar. -func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath) { +func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath, reason string) { if deferReportingMissingBootDexJar(ctx, module) { // Create an error rule that pretends to create the output file but will actually fail if it // is run. @@ -1272,11 +1273,11 @@ func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, Rule: android.ErrorRule, Output: fake, Args: map[string]string{ - "error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module), + "error": fmt.Sprintf("missing boot dex jar dependency for %s: %s", module, reason), }, }) } else { - ctx.ModuleErrorf("module %s does not provide a dex jar", module) + ctx.ModuleErrorf("module %s does not provide a dex jar: %s", module, reason) } } @@ -1287,14 +1288,13 @@ func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, // However, under certain conditions, e.g. errors, or special build configurations it will return // a path to a fake file. func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path { - bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath() - if bootDexJar == nil { + bootDexJar := module.(interface{ DexJarBuildPath() OptionalDexJarPath }).DexJarBuildPath() + if !bootDexJar.Valid() { fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name())) - bootDexJar = fake - - handleMissingDexBootFile(ctx, module, fake) + handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason()) + return fake } - return bootDexJar + return bootDexJar.Path() } // extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules. diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go index dcd363c2c..75b7bb7c8 100644 --- a/java/hiddenapi_singleton_test.go +++ b/java/hiddenapi_singleton_test.go @@ -20,6 +20,7 @@ import ( "testing" "android/soong/android" + "github.com/google/blueprint/proptools" ) @@ -306,7 +307,7 @@ func TestHiddenAPIEncoding_JavaSdkLibrary(t *testing.T) { android.AssertStringEquals(t, "encode embedded java_library", unencodedDexJar, actualUnencodedDexJar.String()) // Make sure that the encoded dex jar is the exported one. - exportedDexJar := moduleForTests.Module().(UsesLibraryDependency).DexJarBuildPath() + exportedDexJar := moduleForTests.Module().(UsesLibraryDependency).DexJarBuildPath().Path() android.AssertPathRelativeToTopEquals(t, "encode embedded java_library", encodedDexJar, exportedDexJar) } diff --git a/java/java.go b/java/java.go index a007ccbee..94c12bdbb 100644 --- a/java/java.go +++ b/java/java.go @@ -219,7 +219,7 @@ type ApexDependency interface { // Provides build path and install path to DEX jars. type UsesLibraryDependency interface { - DexJarBuildPath() android.Path + DexJarBuildPath() OptionalDexJarPath DexJarInstallPath() android.Path ClassLoaderContexts() dexpreopt.ClassLoaderContextMap } @@ -1214,7 +1214,7 @@ type Import struct { properties ImportProperties // output file containing classes.dex and resources - dexJarFile android.Path + dexJarFile OptionalDexJarPath dexJarInstallFile android.Path combinedClasspathFile android.Path @@ -1318,7 +1318,6 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap) var flags javaBuilderFlags - var deapexerModule android.Module ctx.VisitDirectDeps(func(module android.Module) { tag := ctx.OtherModuleDependencyTag(module) @@ -1339,11 +1338,6 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } addCLCFromDep(ctx, module, j.classLoaderContexts) - - // Save away the `deapexer` module on which this depends, if any. - if tag == android.DeapexerTag { - deapexerModule = module - } }) if Bool(j.properties.Installable) { @@ -1358,26 +1352,22 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { // obtained from the associated deapexer module. ai := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if ai.ForPrebuiltApex { - if deapexerModule == nil { - // This should never happen as a variant for a prebuilt_apex is only created if the - // deapexer module has been configured to export the dex implementation jar for this module. - ctx.ModuleErrorf("internal error: module %q does not depend on a `deapexer` module for prebuilt_apex %q", - j.Name(), ai.ApexVariationName) - return - } - // Get the path of the dex implementation jar from the `deapexer` module. - di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo) + di := android.FindDeapexerProviderForModule(ctx) + if di == nil { + return // An error has been reported by FindDeapexerProviderForModule. + } if dexOutputPath := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(j.BaseModuleName())); dexOutputPath != nil { - j.dexJarFile = dexOutputPath + dexJarFile := makeDexJarPathFromPath(dexOutputPath) + j.dexJarFile = dexJarFile j.dexJarInstallFile = android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(j.BaseModuleName())) // Initialize the hiddenapi structure. - j.initHiddenAPI(ctx, dexOutputPath, outputFile, nil) + j.initHiddenAPI(ctx, dexJarFile, outputFile, nil) } else { // This should never happen as a variant for a prebuilt_apex is only created if the // prebuilt_apex has been configured to export the java library dex file. - ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt_apex %q", deapexerModule.Name()) + ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName()) } } else if Bool(j.dexProperties.Compile_dex) { sdkDep := decodeSdkDep(ctx, android.SdkContext(j)) @@ -1406,12 +1396,12 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } // Initialize the hiddenapi structure. - j.initHiddenAPI(ctx, dexOutputFile, outputFile, j.dexProperties.Uncompress_dex) + j.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), outputFile, j.dexProperties.Uncompress_dex) // Encode hidden API flags in dex file. dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile) - j.dexJarFile = dexOutputFile + j.dexJarFile = makeDexJarPathFromPath(dexOutputFile) j.dexJarInstallFile = android.PathForModuleInstall(ctx, "framework", jarName) } } @@ -1449,7 +1439,7 @@ func (j *Import) ImplementationAndResourcesJars() android.Paths { return android.Paths{j.combinedClasspathFile} } -func (j *Import) DexJarBuildPath() android.Path { +func (j *Import) DexJarBuildPath() OptionalDexJarPath { return j.dexJarFile } @@ -1594,7 +1584,7 @@ type DexImport struct { properties DexImportProperties - dexJarFile android.Path + dexJarFile OptionalDexJarPath dexpreopter @@ -1685,7 +1675,7 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { }) } - j.dexJarFile = dexOutputFile + j.dexJarFile = makeDexJarPathFromPath(dexOutputFile) j.dexpreopt(ctx, dexOutputFile) @@ -1695,7 +1685,7 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } -func (j *DexImport) DexJarBuildPath() android.Path { +func (j *DexImport) DexJarBuildPath() OptionalDexJarPath { return j.dexJarFile } @@ -1864,7 +1854,7 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, // from its CLC should be added to the current CLC. if sdkLib != nil { clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, false, true, - dep.DexJarBuildPath(), dep.DexJarInstallPath(), dep.ClassLoaderContexts()) + dep.DexJarBuildPath().PathOrNil(), dep.DexJarInstallPath(), dep.ClassLoaderContexts()) } else { clcMap.AddContextMap(dep.ClassLoaderContexts(), depName) } diff --git a/java/java_test.go b/java/java_test.go index 8bb017f0b..bc9b40964 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -600,8 +600,8 @@ func TestPrebuilts(t *testing.T) { } barDexJar := barModule.Module().(*Import).DexJarBuildPath() - if barDexJar != nil { - t.Errorf("bar dex jar build path expected to be nil, got %q", barDexJar) + if barDexJar.IsSet() { + t.Errorf("bar dex jar build path expected to be set, got %s", barDexJar) } if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) { @@ -612,7 +612,7 @@ func TestPrebuilts(t *testing.T) { t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String()) } - bazDexJar := bazModule.Module().(*Import).DexJarBuildPath() + bazDexJar := bazModule.Module().(*Import).DexJarBuildPath().Path() expectedDexJar := "out/soong/.intermediates/baz/android_common/dex/baz.jar" android.AssertPathRelativeToTopEquals(t, "baz dex jar build path", expectedDexJar, bazDexJar) diff --git a/java/robolectric.go b/java/robolectric.go index a0c9c7fcd..a3603adf8 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -212,7 +212,13 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) installDeps = append(installDeps, installedData) } - ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...) + installed := ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...) + + if r.ExportedToMake() { + // Soong handles installation here, but Make is usually what creates the phony rule that atest + // uses to build the module. Create it here for now. + ctx.Phony(ctx.ModuleName(), installed) + } } func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath, @@ -417,10 +423,10 @@ func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleCont } runtimeFromSourceJar := android.OutputFileForModule(ctx, runtimeFromSourceModule, "") - // TODO(murj) Update this to ctx.Config().PlatformSdkCodename() once the platform - // classes like android.os.Build are updated to S. - runtimeName := fmt.Sprintf("android-all-%s-robolectric-r0.jar", - "R") + // "TREE" name is essential here because it hooks into the "TREE" name in + // Robolectric's SdkConfig.java that will always correspond to the NEWEST_SDK + // in Robolectric configs. + runtimeName := "android-all-current-robolectric-r0.jar" installedRuntime := ctx.InstallFile(androidAllDir, runtimeName, runtimeFromSourceJar) r.runtimes = append(r.runtimes, installedRuntime) } diff --git a/java/sdk_library.go b/java/sdk_library.go index db7217181..273efec13 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -540,7 +540,7 @@ type scopePaths struct { // The dex jar for the stubs. // // This is not the implementation jar, it still only contains stubs. - stubsDexJarPath android.Path + stubsDexJarPath OptionalDexJarPath // The API specification file, e.g. system_current.txt. currentApiFilePath android.OptionalPath @@ -550,6 +550,9 @@ type scopePaths struct { // The stubs source jar. stubsSrcJar android.OptionalPath + + // Extracted annotations. + annotationsZip android.OptionalPath } func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { @@ -585,6 +588,7 @@ func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, actio } func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) { + paths.annotationsZip = android.OptionalPathForPath(provider.AnnotationsZip()) paths.currentApiFilePath = android.OptionalPathForPath(provider.ApiFilePath()) paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath()) } @@ -739,6 +743,8 @@ const ( apiTxtComponentName = "api.txt" removedApiTxtComponentName = "removed-api.txt" + + annotationsComponentName = "annotations.zip" ) // A regular expression to match tags that reference a specific stubs component. @@ -757,7 +763,7 @@ var tagSplitter = func() *regexp.Regexp { scopesRegexp := choice(allScopeNames...) // Regular expression to match one of the components. - componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName) + componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName, annotationsComponentName) // Regular expression to match any combination of one scope and one component. return regexp.MustCompile(fmt.Sprintf(`^\.(%s)\.(%s)$`, scopesRegexp, componentsRegexp)) @@ -765,9 +771,7 @@ var tagSplitter = func() *regexp.Regexp { // For OutputFileProducer interface // -// .<scope>.stubs.source -// .<scope>.api.txt -// .<scope>.removed-api.txt +// .<scope>.<component name>, for all ComponentNames (for example: .public.removed-api.txt) func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Paths, error) { if groups := tagSplitter.FindStringSubmatch(tag); groups != nil { scopeName := groups[1] @@ -794,6 +798,11 @@ func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Pat if paths.removedApiFilePath.Valid() { return android.Paths{paths.removedApiFilePath.Path()}, nil } + + case annotationsComponentName: + if paths.annotationsZip.Valid() { + return android.Paths{paths.annotationsZip.Path()}, nil + } } return nil, fmt.Errorf("%s not available for api scope %s", component, scopeName) @@ -906,10 +915,10 @@ func sdkKindToApiScope(kind android.SdkKind) *apiScope { } // to satisfy SdkLibraryDependency interface -func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path { +func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath { paths := c.selectScopePaths(ctx, kind) if paths == nil { - return nil + return makeUnsetDexJarPath() } return paths.stubsDexJarPath @@ -1035,7 +1044,7 @@ type SdkLibraryDependency interface { // SdkApiStubDexJar returns the dex jar for the stubs. It is needed by the hiddenapi processing // tool which processes dex files. - SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path + SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath // SdkRemovedTxtFile returns the optional path to the removed.txt file for the specified sdk kind. SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath @@ -1888,6 +1897,9 @@ type sdkLibraryScopeProperties struct { // The removed.txt Removed_api *string `android:"path"` + + // Annotation zip + Annotations *string `android:"path"` } type sdkLibraryImportProperties struct { @@ -1928,7 +1940,7 @@ type SdkLibraryImport struct { xmlPermissionsFileModule *sdkLibraryXml // Build path to the dex implementation jar obtained from the prebuilt_apex, if any. - dexJarFile android.Path + dexJarFile OptionalDexJarPath // Expected install file path of the source module(sdk_library) // or dex implementation jar obtained from the prebuilt_apex, if any. @@ -2156,8 +2168,6 @@ func (module *SdkLibraryImport) OutputFiles(tag string) (android.Paths, error) { func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { module.generateCommonBuildActions(ctx) - var deapexerModule android.Module - // Assume that source module(sdk_library) is installed in /<sdk_library partition>/framework module.installFile = android.PathForModuleInstall(ctx, "framework", module.Stem()+".jar") @@ -2186,11 +2196,6 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo ctx.ModuleErrorf("xml permissions file module must be of type *sdkLibraryXml but was %T", to) } } - - // Save away the `deapexer` module on which this depends, if any. - if tag == android.DeapexerTag { - deapexerModule = to - } }) // Populate the scope paths with information from the properties. @@ -2200,6 +2205,7 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo } paths := module.getScopePathsCreateIfNeeded(apiScope) + paths.annotationsZip = android.OptionalPathForModuleSrc(ctx, scopeProperties.Annotations) paths.currentApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Current_api) paths.removedApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Removed_api) } @@ -2209,21 +2215,18 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo // obtained from the associated deapexer module. ai := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if ai.ForPrebuiltApex { - if deapexerModule == nil { - // This should never happen as a variant for a prebuilt_apex is only created if the - // deapxer module has been configured to export the dex implementation jar for this module. - ctx.ModuleErrorf("internal error: module %q does not depend on a `deapexer` module for prebuilt_apex %q", - module.Name(), ai.ApexVariationName) - } - // Get the path of the dex implementation jar from the `deapexer` module. - di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo) + di := android.FindDeapexerProviderForModule(ctx) + if di == nil { + return // An error has been reported by FindDeapexerProviderForModule. + } if dexOutputPath := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(module.BaseModuleName())); dexOutputPath != nil { - module.dexJarFile = dexOutputPath + dexJarFile := makeDexJarPathFromPath(dexOutputPath) + module.dexJarFile = dexJarFile installPath := android.PathForModuleInPartitionInstall( ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(module.BaseModuleName())) module.installFile = installPath - module.initHiddenAPI(ctx, dexOutputPath, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil) + module.initHiddenAPI(ctx, dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil) // Dexpreopting. module.dexpreopter.installPath = module.dexpreopter.getInstallPath(ctx, installPath) @@ -2233,7 +2236,7 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo } else { // This should never happen as a variant for a prebuilt_apex is only created if the // prebuilt_apex has been configured to export the java library dex file. - ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt_apex %q", deapexerModule.Name()) + ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName()) } } } @@ -2268,14 +2271,14 @@ func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleCont } // to satisfy UsesLibraryDependency interface -func (module *SdkLibraryImport) DexJarBuildPath() android.Path { +func (module *SdkLibraryImport) DexJarBuildPath() OptionalDexJarPath { // The dex implementation jar extracted from the .apex file should be used in preference to the // source. - if module.dexJarFile != nil { + if module.dexJarFile.IsSet() { return module.dexJarFile } if module.implLibraryModule == nil { - return nil + return makeUnsetDexJarPath() } else { return module.implLibraryModule.DexJarBuildPath() } @@ -2550,6 +2553,7 @@ type scopeProperties struct { StubsSrcJar android.Path CurrentApiFile android.Path RemovedApiFile android.Path + AnnotationsZip android.Path SdkVersion string } @@ -2575,6 +2579,10 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe if paths.removedApiFilePath.Valid() { properties.RemovedApiFile = paths.removedApiFilePath.Path() } + // The annotations zip is only available for modules that set annotations_enabled: true. + if paths.annotationsZip.Valid() { + properties.AnnotationsZip = paths.annotationsZip.Path() + } s.Scopes[apiScope] = properties } } @@ -2639,6 +2647,12 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo scopeSet.AddProperty("removed_api", removedApiSnapshotPath) } + if properties.AnnotationsZip != nil { + annotationsSnapshotPath := filepath.Join(scopeDir, ctx.Name()+"_annotations.zip") + ctx.SnapshotBuilder().CopyToSnapshot(properties.AnnotationsZip, annotationsSnapshotPath) + scopeSet.AddProperty("annotations", annotationsSnapshotPath) + } + if properties.SdkVersion != "" { scopeSet.AddProperty("sdk_version", properties.SdkVersion) } diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index d6c0946b1..be23536ea 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -248,7 +248,7 @@ func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) { } } -func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) { +func TestJavaSdkLibrary_AccessOutputFiles(t *testing.T) { android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -258,6 +258,31 @@ func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) { name: "foo", srcs: ["a.java"], api_packages: ["foo"], + annotations_enabled: true, + public: { + enabled: true, + }, + } + java_library { + name: "bar", + srcs: ["b.java", ":foo{.public.stubs.source}"], + java_resources: [":foo{.public.annotations.zip}"], + } + `) +} + +func TestJavaSdkLibrary_AccessOutputFiles_NoAnnotations(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo"), + ). + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "bar" variant "android_common": path dependency ":foo{.public.annotations.zip}": annotations.zip not available for api scope public`)). + RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + api_packages: ["foo"], public: { enabled: true, }, @@ -266,6 +291,7 @@ func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) { java_library { name: "bar", srcs: ["b.java", ":foo{.public.stubs.source}"], + java_resources: [":foo{.public.annotations.zip}"], } `) } @@ -329,6 +355,7 @@ func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) { stub_srcs: ["a.java"], current_api: "api/current.txt", removed_api: "api/removed.txt", + annotations: "x/annotations.zip", }, } @@ -338,6 +365,7 @@ func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) { java_resources: [ ":foo{.public.api.txt}", ":foo{.public.removed-api.txt}", + ":foo{.public.annotations.zip}", ], } `) diff --git a/java/testing.go b/java/testing.go index a642753c4..99d55a054 100644 --- a/java/testing.go +++ b/java/testing.go @@ -300,6 +300,7 @@ func gatherRequiredDepsForTest() string { "kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8", "kotlin-annotations", + "stub-annotations", } for _, extra := range extraModules { diff --git a/rust/Android.bp b/rust/Android.bp index 221014e5c..0ee673de4 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -50,6 +50,7 @@ bootstrap_go_package { "fuzz_test.go", "image_test.go", "library_test.go", + "proc_macro_test.go", "project_json_test.go", "protobuf_test.go", "rust_test.go", diff --git a/rust/compiler.go b/rust/compiler.go index 7bd9af4a8..1ce71f60b 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -231,6 +231,7 @@ func (compiler *baseCompiler) cfgsToFlags() []string { for _, cfg := range compiler.Properties.Cfgs { flags = append(flags, "--cfg '"+cfg+"'") } + return flags } @@ -239,6 +240,24 @@ func (compiler *baseCompiler) featuresToFlags() []string { for _, feature := range compiler.Properties.Features { flags = append(flags, "--cfg 'feature=\""+feature+"\"'") } + + return flags +} + +func (compiler *baseCompiler) featureFlags(ctx ModuleContext, flags Flags) Flags { + flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags()...) + flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags()...) + + return flags +} + +func (compiler *baseCompiler) cfgFlags(ctx ModuleContext, flags Flags) Flags { + if ctx.RustModule().UseVndk() { + compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_vndk") + } + + flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...) + flags.RustdocFlags = append(flags.RustdocFlags, compiler.cfgsToFlags()...) return flags } @@ -269,10 +288,6 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flag flags.RustFlags = append(flags.RustFlags, lintFlags) flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...) - flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...) - flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags()...) - flags.RustdocFlags = append(flags.RustdocFlags, compiler.cfgsToFlags()...) - flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags()...) flags.RustFlags = append(flags.RustFlags, "--edition="+compiler.edition()) flags.RustdocFlags = append(flags.RustdocFlags, "--edition="+compiler.edition()) flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...) @@ -296,10 +311,6 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flag flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpathPrefix+"../"+rpath) } - if ctx.RustModule().UseVndk() { - flags.RustFlags = append(flags.RustFlags, "--cfg 'android_vndk'") - } - return flags } diff --git a/rust/library.go b/rust/library.go index 8c10e298b..38dae4d33 100644 --- a/rust/library.go +++ b/rust/library.go @@ -430,15 +430,25 @@ func (library *libraryDecorator) sharedLibFilename(ctx ModuleContext) string { return library.getStem(ctx) + ctx.toolchain().SharedLibSuffix() } -func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { - flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName()) +func (library *libraryDecorator) cfgFlags(ctx ModuleContext, flags Flags) Flags { + flags = library.baseCompiler.cfgFlags(ctx, flags) if library.dylib() { // We need to add a dependency on std in order to link crates as dylibs. // The hack to add this dependency is guarded by the following cfg so // that we don't force a dependency when it isn't needed. library.baseCompiler.Properties.Cfgs = append(library.baseCompiler.Properties.Cfgs, "android_dylib") } + + flags.RustFlags = append(flags.RustFlags, library.baseCompiler.cfgsToFlags()...) + flags.RustdocFlags = append(flags.RustdocFlags, library.baseCompiler.cfgsToFlags()...) + + return flags +} + +func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = library.baseCompiler.compilerFlags(ctx, flags) + + flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName()) if library.shared() || library.static() { library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...) } diff --git a/rust/proc_macro.go b/rust/proc_macro.go index c217959cd..804d79fe9 100644 --- a/rust/proc_macro.go +++ b/rust/proc_macro.go @@ -63,6 +63,12 @@ func (procMacro *procMacroDecorator) compilerProps() []interface{} { &procMacro.Properties) } +func (procMacro *procMacroDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { + flags = procMacro.baseCompiler.compilerFlags(ctx, flags) + flags.RustFlags = append(flags.RustFlags, "--extern proc_macro") + return flags +} + func (procMacro *procMacroDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { fileName := procMacro.getStem(ctx) + ctx.toolchain().ProcMacroSuffix() outputFile := android.PathForModuleOut(ctx, fileName) diff --git a/rust/proc_macro_test.go b/rust/proc_macro_test.go new file mode 100644 index 000000000..cc8193858 --- /dev/null +++ b/rust/proc_macro_test.go @@ -0,0 +1,36 @@ +// Copyright 2021 The Android Open Source Project +// +// 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 rust + +import ( + "strings" + "testing" +) + +func TestRustProcMacro(t *testing.T) { + ctx := testRust(t, ` + rust_proc_macro { + name: "libprocmacro", + srcs: ["foo.rs"], + crate_name: "procmacro", + } + `) + + libprocmacro := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Rule("rustc") + + if !strings.Contains(libprocmacro.Args["rustcFlags"], "--extern proc_macro") { + t.Errorf("--extern proc_macro flag not being passed to rustc for proc macro %#v", libprocmacro.Args["rustcFlags"]) + } +} diff --git a/rust/rust.go b/rust/rust.go index 0cd299dc1..0a7d68dee 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -436,6 +436,8 @@ type RustLibrary struct { type compiler interface { initialize(ctx ModuleContext) compilerFlags(ctx ModuleContext, flags Flags) Flags + cfgFlags(ctx ModuleContext, flags Flags) Flags + featureFlags(ctx ModuleContext, flags Flags) Flags compilerProps() []interface{} compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path compilerDeps(ctx DepsContext, deps Deps) Deps @@ -847,8 +849,11 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { Toolchain: toolchain, } + // Calculate rustc flags if mod.compiler != nil { flags = mod.compiler.compilerFlags(ctx, flags) + flags = mod.compiler.cfgFlags(ctx, flags) + flags = mod.compiler.featureFlags(ctx, flags) } if mod.coverage != nil { flags, deps = mod.coverage.flags(ctx, flags, deps) diff --git a/rust/test.go b/rust/test.go index e95b47cff..56da509b5 100644 --- a/rust/test.go +++ b/rust/test.go @@ -59,6 +59,10 @@ type TestProperties struct { // Test options. Test_options TestOptions + + // Add RootTargetPreparer to auto generated test config. This guarantees the test to run + // with root permission. + Require_root *bool } // A test module is a binary module with extra --test compiler flag @@ -109,12 +113,27 @@ func (test *testDecorator) compilerProps() []interface{} { } func (test *testDecorator) install(ctx ModuleContext) { + testInstallBase := "/data/local/tests/unrestricted" + if ctx.RustModule().InVendor() || ctx.RustModule().UseVndk() { + testInstallBase = "/data/local/tests/vendor" + } + + var configs []tradefed.Config + if Bool(test.Properties.Require_root) { + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil}) + } else { + var options []tradefed.Option + options = append(options, tradefed.Option{Name: "force-root", Value: "false"}) + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options}) + } + test.testConfig = tradefed.AutoGenRustTestConfig(ctx, test.Properties.Test_config, test.Properties.Test_config_template, test.Properties.Test_suites, - nil, - test.Properties.Auto_gen_config) + configs, + test.Properties.Auto_gen_config, + testInstallBase) dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data) diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt index 942f26a5c..9aae2a97e 100644 --- a/scripts/check_boot_jars/package_allowed_list.txt +++ b/scripts/check_boot_jars/package_allowed_list.txt @@ -70,6 +70,7 @@ javax\.xml\.transform\.stream javax\.xml\.validation javax\.xml\.xpath jdk\.internal\.math +jdk\.internal\.misc jdk\.internal\.util jdk\.internal\.vm\.annotation jdk\.net diff --git a/sdk/Android.bp b/sdk/Android.bp index 0c9bf27fd..c6544d68a 100644 --- a/sdk/Android.bp +++ b/sdk/Android.bp @@ -16,6 +16,7 @@ bootstrap_go_package { srcs: [ "bp.go", "exports.go", + "member_trait.go", "member_type.go", "sdk.go", "update.go", @@ -28,6 +29,7 @@ bootstrap_go_package { "exports_test.go", "java_sdk_test.go", "license_sdk_test.go", + "member_trait_test.go", "sdk_test.go", "testing.go", ], diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go index 25e35fcdb..cd63dac8c 100644 --- a/sdk/cc_sdk_test.go +++ b/sdk/cc_sdk_test.go @@ -15,6 +15,7 @@ package sdk import ( + "fmt" "testing" "android/soong/android" @@ -32,6 +33,23 @@ var ccTestFs = android.MockFS{ "some/where/stubslib.map.txt": nil, } +// Adds a native bridge target to the configured list of targets. +var prepareForTestWithNativeBridgeTarget = android.FixtureModifyConfig(func(config android.Config) { + config.Targets[android.Android] = append(config.Targets[android.Android], android.Target{ + Os: android.Android, + Arch: android.Arch{ + ArchType: android.Arm64, + ArchVariant: "armv8-a", + CpuVariant: "cpu", + Abi: nil, + ArchFeatures: nil, + }, + NativeBridge: android.NativeBridgeEnabled, + NativeBridgeHostArchName: "x86_64", + NativeBridgeRelativePath: "native_bridge", + }) +}) + func testSdkWithCc(t *testing.T, bp string) *android.TestResult { t.Helper() return testSdkWithFs(t, bp, ccTestFs) @@ -1754,7 +1772,6 @@ cc_prebuilt_library { prefer: false, visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], - recovery_available: true, vendor_available: true, stl: "none", compile_multilib: "both", @@ -1789,7 +1806,6 @@ cc_prebuilt_library { visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], installable: false, - recovery_available: true, vendor_available: true, stl: "none", compile_multilib: "both", @@ -1979,6 +1995,146 @@ myinclude/Test.h -> include/myinclude/Test.h ) } +func TestSnapshotWithCcHeadersLibraryAndNativeBridgeSupport(t *testing.T) { + result := android.GroupFixturePreparers( + cc.PrepareForTestWithCcDefaultModules, + PrepareForTestWithSdkBuildComponents, + ccTestFs.AddToFixture(), + prepareForTestWithNativeBridgeTarget, + ).RunTestWithBp(t, ` + sdk { + name: "mysdk", + native_header_libs: ["mynativeheaders"], + traits: { + native_bridge_support: ["mynativeheaders"], + }, + } + + cc_library_headers { + name: "mynativeheaders", + export_include_dirs: ["myinclude"], + stl: "none", + system_shared_libs: [], + native_bridge_supported: true, + } + `) + + CheckSnapshot(t, result, "mysdk", "", + checkUnversionedAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +cc_prebuilt_library_headers { + name: "mynativeheaders", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + native_bridge_supported: true, + stl: "none", + compile_multilib: "both", + system_shared_libs: [], + export_include_dirs: ["include/myinclude"], +} +`), + checkAllCopyRules(` +myinclude/Test.h -> include/myinclude/Test.h +`), + ) +} + +// TestSnapshotWithCcHeadersLibrary_DetectsNativeBridgeSpecificProperties verifies that when a +// module that has different output files for a native bridge target requests the native bridge +// variants are copied into the sdk snapshot that it reports an error. +func TestSnapshotWithCcHeadersLibrary_DetectsNativeBridgeSpecificProperties(t *testing.T) { + android.GroupFixturePreparers( + cc.PrepareForTestWithCcDefaultModules, + PrepareForTestWithSdkBuildComponents, + ccTestFs.AddToFixture(), + prepareForTestWithNativeBridgeTarget, + ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + `\QArchitecture variant "arm64_native_bridge" of sdk member "mynativeheaders" has properties distinct from other variants; this is not yet supported. The properties are: + export_include_dirs: [ + "arm64_native_bridge/include/myinclude_nativebridge", + "arm64_native_bridge/include/myinclude", + ],\E`)). + RunTestWithBp(t, ` + sdk { + name: "mysdk", + native_header_libs: ["mynativeheaders"], + traits: { + native_bridge_support: ["mynativeheaders"], + }, + } + + cc_library_headers { + name: "mynativeheaders", + export_include_dirs: ["myinclude"], + stl: "none", + system_shared_libs: [], + native_bridge_supported: true, + target: { + native_bridge: { + export_include_dirs: ["myinclude_nativebridge"], + }, + }, + } + `) +} + +func TestSnapshotWithCcHeadersLibraryAndImageVariants(t *testing.T) { + testImageVariant := func(t *testing.T, property, trait string) { + result := android.GroupFixturePreparers( + cc.PrepareForTestWithCcDefaultModules, + PrepareForTestWithSdkBuildComponents, + ccTestFs.AddToFixture(), + ).RunTestWithBp(t, fmt.Sprintf(` + sdk { + name: "mysdk", + native_header_libs: ["mynativeheaders"], + traits: { + %s: ["mynativeheaders"], + }, + } + + cc_library_headers { + name: "mynativeheaders", + export_include_dirs: ["myinclude"], + stl: "none", + system_shared_libs: [], + %s: true, + } + `, trait, property)) + + CheckSnapshot(t, result, "mysdk", "", + checkUnversionedAndroidBpContents(fmt.Sprintf(` +// This is auto-generated. DO NOT EDIT. + +cc_prebuilt_library_headers { + name: "mynativeheaders", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + %s: true, + stl: "none", + compile_multilib: "both", + system_shared_libs: [], + export_include_dirs: ["include/myinclude"], +} +`, property)), + checkAllCopyRules(` +myinclude/Test.h -> include/myinclude/Test.h +`), + ) + } + + t.Run("ramdisk", func(t *testing.T) { + testImageVariant(t, "ramdisk_available", "ramdisk_image_required") + }) + + t.Run("recovery", func(t *testing.T) { + testImageVariant(t, "recovery_available", "recovery_image_required") + }) +} + func TestHostSnapshotWithCcHeadersLibrary(t *testing.T) { result := testSdkWithCc(t, ` sdk { diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index 9efb3a49a..2b537398a 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -1205,6 +1205,55 @@ java_sdk_library_import { ) } +func TestSnapshotWithJavaSdkLibrary_AnnotationsZip(t *testing.T) { + result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, ` + sdk { + name: "mysdk", + java_sdk_libs: ["myjavalib"], + } + + java_sdk_library { + name: "myjavalib", + srcs: ["Test.java"], + sdk_version: "current", + shared_library: false, + annotations_enabled: true, + public: { + enabled: true, + }, + } + `) + + CheckSnapshot(t, result, "mysdk", "", + checkUnversionedAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +java_sdk_library_import { + name: "myjavalib", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + shared_library: false, + 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", + annotations: "sdk_library/public/myjavalib_annotations.zip", + sdk_version: "current", + }, +} + `), + checkAllCopyRules(` +.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar +.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt +.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt +.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_annotations.zip -> sdk_library/public/myjavalib_annotations.zip + `), + checkMergeZips(".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip"), + ) +} + func TestSnapshotWithJavaSdkLibrary_CompileDex(t *testing.T) { result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, ` sdk { @@ -1258,7 +1307,7 @@ java_sdk_library_import { ctx := android.ModuleInstallPathContextForTesting(result.Config) dexJarBuildPath := func(name string, kind android.SdkKind) string { dep := result.Module(name, "android_common").(java.SdkLibraryDependency) - path := dep.SdkApiStubDexJar(ctx, kind) + path := dep.SdkApiStubDexJar(ctx, kind).Path() return path.RelativeToTop().String() } diff --git a/sdk/member_trait.go b/sdk/member_trait.go new file mode 100644 index 000000000..4229ca82b --- /dev/null +++ b/sdk/member_trait.go @@ -0,0 +1,126 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// 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 sdk + +import ( + "reflect" + + "android/soong/android" + "github.com/google/blueprint/proptools" +) + +// Contains information about the sdk properties that list sdk members by trait, e.g. +// native_bridge. +type sdkMemberTraitListProperty struct { + // getter for the list of member names + getter func(properties interface{}) []string + + // the trait of member referenced in the list + memberTrait android.SdkMemberTrait +} + +// Cache of dynamically generated dynamicSdkMemberTraits objects. The key is the pointer +// to a slice of SdkMemberTrait instances returned by android.RegisteredSdkMemberTraits(). +var dynamicSdkMemberTraitsMap android.OncePer + +// A dynamically generated set of member list properties and associated structure type. +// +// Instances of this are created by createDynamicSdkMemberTraits. +type dynamicSdkMemberTraits struct { + // The dynamically generated structure type. + // + // Contains one []string exported field for each SdkMemberTrait returned by android.RegisteredSdkMemberTraits(). The name of + // the field is the exported form of the value returned by SdkMemberTrait.SdkPropertyName(). + propertiesStructType reflect.Type + + // Information about each of the member trait specific list properties. + memberTraitListProperties []*sdkMemberTraitListProperty +} + +func (d *dynamicSdkMemberTraits) createMemberTraitListProperties() interface{} { + return reflect.New(d.propertiesStructType).Interface() +} + +func getDynamicSdkMemberTraits(key android.OnceKey, registeredTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits { + // Get the cached value, creating new instance if necessary. + return dynamicSdkMemberTraitsMap.Once(key, func() interface{} { + return createDynamicSdkMemberTraits(registeredTraits) + }).(*dynamicSdkMemberTraits) +} + +// Create the dynamicSdkMemberTraits from the list of registered member traits. +// +// A struct is created which contains one exported field per member trait corresponding to +// the SdkMemberTrait.SdkPropertyName() value. +// +// A list of sdkMemberTraitListProperty instances is created, one per member trait that provides: +// * a reference to the member trait. +// * a getter for the corresponding field in the properties struct. +// +func createDynamicSdkMemberTraits(sdkMemberTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits { + + var listProperties []*sdkMemberTraitListProperty + memberTraitToProperty := map[android.SdkMemberTrait]*sdkMemberTraitListProperty{} + var fields []reflect.StructField + + // Iterate over the member traits creating StructField and sdkMemberTraitListProperty objects. + nextFieldIndex := 0 + for _, memberTrait := range sdkMemberTraits { + + p := memberTrait.SdkPropertyName() + + var getter func(properties interface{}) []string + + // Create a dynamic exported field for the member trait's property. + fields = append(fields, reflect.StructField{ + Name: proptools.FieldNameForProperty(p), + Type: reflect.TypeOf([]string{}), + }) + + // Copy the field index for use in the getter func as using the loop variable directly will + // cause all funcs to use the last value. + fieldIndex := nextFieldIndex + nextFieldIndex += 1 + + getter = func(properties interface{}) []string { + // The properties is expected to be of the following form (where + // <Module_traits> is the name of an SdkMemberTrait.SdkPropertyName(). + // properties *struct {<Module_traits> []string, ....} + // + // Although it accesses the field by index the following reflection code is equivalent to: + // *properties.<Module_traits> + // + list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string) + return list + } + + // Create an sdkMemberTraitListProperty for the member trait. + memberListProperty := &sdkMemberTraitListProperty{ + getter: getter, + memberTrait: memberTrait, + } + + memberTraitToProperty[memberTrait] = memberListProperty + listProperties = append(listProperties, memberListProperty) + } + + // Create a dynamic struct from the collated fields. + propertiesStructType := reflect.StructOf(fields) + + return &dynamicSdkMemberTraits{ + memberTraitListProperties: listProperties, + propertiesStructType: propertiesStructType, + } +} diff --git a/sdk/member_trait_test.go b/sdk/member_trait_test.go new file mode 100644 index 000000000..a3db189b2 --- /dev/null +++ b/sdk/member_trait_test.go @@ -0,0 +1,287 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// 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 sdk + +import ( + "fmt" + "path/filepath" + "testing" + + "android/soong/android" + "android/soong/java" + "github.com/google/blueprint" +) + +type fakeMemberTrait struct { + android.SdkMemberTraitBase +} + +type fakeMemberType struct { + android.SdkMemberTypeBase +} + +func (t *fakeMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) { + for _, name := range names { + ctx.AddVariationDependencies(nil, dependencyTag, name) + + if ctx.RequiresTrait(name, extraTrait) { + ctx.AddVariationDependencies(nil, dependencyTag, name+"_extra") + } + if ctx.RequiresTrait(name, specialTrait) { + ctx.AddVariationDependencies(nil, dependencyTag, name+"_special") + } + } +} + +func (t *fakeMemberType) IsInstance(module android.Module) bool { + return true +} + +func (t *fakeMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { + moduleType := "java_import" + if ctx.RequiresTrait(extraTrait) { + moduleType = "java_test_import" + } + return ctx.SnapshotBuilder().AddPrebuiltModule(member, moduleType) +} + +func (t *fakeMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties { + return &fakeMemberTypeProperties{} +} + +type fakeMemberTypeProperties struct { + android.SdkMemberPropertiesBase + + path android.Path +} + +func (t *fakeMemberTypeProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { + headerJars := variant.(java.ApexDependency).HeaderJars() + if len(headerJars) != 1 { + panic(fmt.Errorf("there must be only one header jar from %q", variant.Name())) + } + + t.path = headerJars[0] +} + +func (t *fakeMemberTypeProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { + if t.path != nil { + relative := filepath.Join("javalibs", t.path.Base()) + ctx.SnapshotBuilder().CopyToSnapshot(t.path, relative) + propertySet.AddProperty("jars", []string{relative}) + } +} + +var ( + extraTrait = &fakeMemberTrait{ + SdkMemberTraitBase: android.SdkMemberTraitBase{ + PropertyName: "extra", + }, + } + + specialTrait = &fakeMemberTrait{ + SdkMemberTraitBase: android.SdkMemberTraitBase{ + PropertyName: "special", + }, + } + + fakeType = &fakeMemberType{ + SdkMemberTypeBase: android.SdkMemberTypeBase{ + PropertyName: "fake_members", + SupportsSdk: true, + Traits: []android.SdkMemberTrait{ + extraTrait, + specialTrait, + }, + }, + } +) + +func init() { + android.RegisterSdkMemberTrait(extraTrait) + android.RegisterSdkMemberTrait(specialTrait) + android.RegisterSdkMemberType(fakeType) +} + +func TestBasicTrait_WithoutTrait(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForSdkTestWithJava, + android.FixtureWithRootAndroidBp(` + sdk { + name: "mysdk", + fake_members: ["myjavalib"], + } + + java_library { + name: "myjavalib", + srcs: ["Test.java"], + system_modules: "none", + sdk_version: "none", + } + `), + ).RunTest(t) + + CheckSnapshot(t, result, "mysdk", "", + checkUnversionedAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +java_import { + name: "myjavalib", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + jars: ["javalibs/myjavalib.jar"], +} +`), + checkVersionedAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +java_import { + name: "mysdk_myjavalib@current", + sdk_member_name: "myjavalib", + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + jars: ["javalibs/myjavalib.jar"], +} + +sdk_snapshot { + name: "mysdk@current", + visibility: ["//visibility:public"], + fake_members: ["mysdk_myjavalib@current"], +} +`), + ) +} + +func TestBasicTrait_MultipleTraits(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForSdkTestWithJava, + android.FixtureWithRootAndroidBp(` + sdk { + name: "mysdk", + fake_members: ["myjavalib", "anotherjavalib"], + traits: { + extra: ["myjavalib"], + special: ["myjavalib", "anotherjavalib"], + }, + } + + java_library { + name: "myjavalib", + srcs: ["Test.java"], + system_modules: "none", + sdk_version: "none", + } + + java_library { + name: "myjavalib_extra", + srcs: ["Test.java"], + system_modules: "none", + sdk_version: "none", + } + + java_library { + name: "myjavalib_special", + srcs: ["Test.java"], + system_modules: "none", + sdk_version: "none", + } + + java_library { + name: "anotherjavalib", + srcs: ["Test.java"], + system_modules: "none", + sdk_version: "none", + } + + java_library { + name: "anotherjavalib_special", + srcs: ["Test.java"], + system_modules: "none", + sdk_version: "none", + } + `), + ).RunTest(t) + + CheckSnapshot(t, result, "mysdk", "", + checkUnversionedAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +java_test_import { + name: "myjavalib", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + jars: ["javalibs/myjavalib.jar"], +} + +java_import { + name: "myjavalib_extra", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + jars: ["javalibs/myjavalib_extra.jar"], +} + +java_import { + name: "myjavalib_special", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + jars: ["javalibs/myjavalib_special.jar"], +} + +java_import { + name: "anotherjavalib", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + jars: ["javalibs/anotherjavalib.jar"], +} + +java_import { + name: "anotherjavalib_special", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["//apex_available:platform"], + jars: ["javalibs/anotherjavalib_special.jar"], +} +`), + ) +} + +func TestTraitUnsupportedByMemberType(t *testing.T) { + android.GroupFixturePreparers( + prepareForSdkTestWithJava, + android.FixtureWithRootAndroidBp(` + sdk { + name: "mysdk", + java_header_libs: ["myjavalib"], + traits: { + extra: ["myjavalib"], + }, + } + + java_library { + name: "myjavalib", + srcs: ["Test.java"], + system_modules: "none", + sdk_version: "none", + } + `), + ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + `\Qsdk member "myjavalib" has traits [extra] that are unsupported by its member type "java_header_libs"\E`)). + RunTest(t) +} diff --git a/sdk/member_type.go b/sdk/member_type.go index 9aab61dd0..10669fe23 100644 --- a/sdk/member_type.go +++ b/sdk/member_type.go @@ -64,14 +64,7 @@ func (d *dynamicSdkMemberTypes) createMemberTypeListProperties() interface{} { return reflect.New(d.propertiesStructType).Interface() } -func getDynamicSdkMemberTypes(registry *android.SdkMemberTypesRegistry) *dynamicSdkMemberTypes { - - // Get a key that uniquely identifies the registry contents. - key := registry.UniqueOnceKey() - - // Get the registered types. - registeredTypes := registry.RegisteredTypes() - +func getDynamicSdkMemberTypes(key android.OnceKey, registeredTypes []android.SdkMemberType) *dynamicSdkMemberTypes { // Get the cached value, creating new instance if necessary. return dynamicSdkMemberTypesMap.Once(key, func() interface{} { return createDynamicSdkMemberTypes(registeredTypes) diff --git a/sdk/sdk.go b/sdk/sdk.go index 6dea752b3..84c9a96e4 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -53,6 +53,13 @@ type sdk struct { // list properties, e.g. java_libs. dynamicMemberTypeListProperties interface{} + // The dynamically generated information about the registered SdkMemberTrait + dynamicSdkMemberTraits *dynamicSdkMemberTraits + + // The dynamically created instance of the properties struct containing the sdk member trait + // list properties. + dynamicMemberTraitListProperties interface{} + // Information about the OsType specific member variants depended upon by this variant. // // Set by OsType specific variants in the collectMembers() method and used by the @@ -104,17 +111,25 @@ func newSdkModule(moduleExports bool) *sdk { s := &sdk{} s.properties.Module_exports = moduleExports // Get the dynamic sdk member type data for the currently registered sdk member types. - var typeRegistry *android.SdkMemberTypesRegistry - if moduleExports { - typeRegistry = android.ModuleExportsMemberTypes - } else { - typeRegistry = android.SdkMemberTypes - } - s.dynamicSdkMemberTypes = getDynamicSdkMemberTypes(typeRegistry) + sdkMemberTypeKey, sdkMemberTypes := android.RegisteredSdkMemberTypes(moduleExports) + s.dynamicSdkMemberTypes = getDynamicSdkMemberTypes(sdkMemberTypeKey, sdkMemberTypes) // Create an instance of the dynamically created struct that contains all the // properties for the member type specific list properties. s.dynamicMemberTypeListProperties = s.dynamicSdkMemberTypes.createMemberTypeListProperties() - s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties) + + sdkMemberTraitsKey, sdkMemberTraits := android.RegisteredSdkMemberTraits() + s.dynamicSdkMemberTraits = getDynamicSdkMemberTraits(sdkMemberTraitsKey, sdkMemberTraits) + // Create an instance of the dynamically created struct that contains all the properties for the + // member trait specific list properties. + s.dynamicMemberTraitListProperties = s.dynamicSdkMemberTraits.createMemberTraitListProperties() + + // Create a wrapper around the dynamic trait specific properties so that they have to be + // specified within a traits:{} section in the .bp file. + traitsWrapper := struct { + Traits interface{} + }{s.dynamicMemberTraitListProperties} + + 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) @@ -145,6 +160,11 @@ func (s *sdk) memberTypeListProperty(memberType android.SdkMemberType) *sdkMembe return s.dynamicSdkMemberTypes.memberTypeToProperty[memberType] } +// memberTraitListProperties returns the list of *sdkMemberTraitListProperty instances for this sdk. +func (s *sdk) memberTraitListProperties() []*sdkMemberTraitListProperty { + return s.dynamicSdkMemberTraits.memberTraitListProperties +} + func (s *sdk) snapshot() bool { return s.properties.Snapshot } @@ -198,15 +218,53 @@ func (s *sdk) AndroidMkEntries() []android.AndroidMkEntries { }} } +// gatherTraits gathers the traits from the dynamically generated trait specific properties. +// +// Returns a map from member name to the set of required traits. +func (s *sdk) gatherTraits() map[string]android.SdkMemberTraitSet { + traitListByMember := map[string][]android.SdkMemberTrait{} + for _, memberListProperty := range s.memberTraitListProperties() { + names := memberListProperty.getter(s.dynamicMemberTraitListProperties) + for _, name := range names { + traitListByMember[name] = append(traitListByMember[name], memberListProperty.memberTrait) + } + } + + traitSetByMember := map[string]android.SdkMemberTraitSet{} + for name, list := range traitListByMember { + traitSetByMember[name] = android.NewSdkMemberTraitSet(list) + } + + return traitSetByMember +} + // newDependencyContext creates a new SdkDependencyContext for this sdk. func (s *sdk) newDependencyContext(mctx android.BottomUpMutatorContext) android.SdkDependencyContext { + traits := s.gatherTraits() + return &dependencyContext{ BottomUpMutatorContext: mctx, + requiredTraits: traits, } } type dependencyContext struct { android.BottomUpMutatorContext + + // Map from member name to the set of traits that the sdk requires the member provides. + requiredTraits map[string]android.SdkMemberTraitSet +} + +func (d *dependencyContext) RequiredTraits(name string) android.SdkMemberTraitSet { + if s, ok := d.requiredTraits[name]; ok { + return s + } else { + return android.EmptySdkMemberTraitSet() + } +} + +func (d *dependencyContext) RequiresTrait(name string, trait android.SdkMemberTrait) bool { + return d.RequiredTraits(name).Contains(trait) } var _ android.SdkDependencyContext = (*dependencyContext)(nil) @@ -287,8 +345,21 @@ func memberMutator(mctx android.BottomUpMutatorContext) { } names := memberListProperty.getter(s.dynamicMemberTypeListProperties) if len(names) > 0 { + memberType := memberListProperty.memberType + + // Verify that the member type supports the specified traits. + supportedTraits := memberType.SupportedTraits() + for _, name := range names { + requiredTraits := ctx.RequiredTraits(name) + unsupportedTraits := requiredTraits.Subtract(supportedTraits) + if !unsupportedTraits.Empty() { + ctx.ModuleErrorf("sdk member %q has traits %s that are unsupported by its member type %q", name, unsupportedTraits, memberType.SdkPropertyName()) + } + } + + // Add dependencies using the appropriate tag. tag := memberListProperty.dependencyTag - memberListProperty.memberType.AddDependencies(ctx, tag, names) + memberType.AddDependencies(ctx, tag, names) } } } diff --git a/sdk/update.go b/sdk/update.go index 89a5c9269..3246832d4 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -393,10 +393,18 @@ be unnecessary as every module in the sdk already has its own licenses property. members := s.groupMemberVariantsByMemberThenType(ctx, memberVariantDeps) // Create the prebuilt modules for each of the member modules. + traits := s.gatherTraits() for _, member := range members { memberType := member.memberType - memberCtx := &memberContext{ctx, builder, memberType, member.name} + name := member.name + requiredTraits := traits[name] + if requiredTraits == nil { + requiredTraits = android.EmptySdkMemberTraitSet() + } + + // Create the snapshot for the member. + memberCtx := &memberContext{ctx, builder, memberType, name, requiredTraits} prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member) s.createMemberSnapshot(memberCtx, member, prebuiltModule.(*bpModule)) @@ -1385,19 +1393,19 @@ func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, osInfo.Properties = osSpecificVariantPropertiesFactory() // Group the variants by arch type. - var variantsByArchName = make(map[string][]android.Module) - var archTypes []android.ArchType + var variantsByArchId = make(map[archId][]android.Module) + var archIds []archId for _, variant := range osTypeVariants { - archType := variant.Target().Arch.ArchType - archTypeName := archType.Name - if _, ok := variantsByArchName[archTypeName]; !ok { - archTypes = append(archTypes, archType) + target := variant.Target() + id := archIdFromTarget(target) + if _, ok := variantsByArchId[id]; !ok { + archIds = append(archIds, id) } - variantsByArchName[archTypeName] = append(variantsByArchName[archTypeName], variant) + variantsByArchId[id] = append(variantsByArchId[id], variant) } - if commonVariants, ok := variantsByArchName["common"]; ok { + if commonVariants, ok := variantsByArchId[commonArchId]; ok { if len(osTypeVariants) != 1 { panic(fmt.Errorf("Expected to only have 1 variant when arch type is common but found %d", len(osTypeVariants))) } @@ -1407,11 +1415,9 @@ func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, osInfo.Properties.PopulateFromVariant(ctx, commonVariants[0]) } else { // Create an arch specific info for each supported architecture type. - for _, archType := range archTypes { - archTypeName := archType.Name - - archVariants := variantsByArchName[archTypeName] - archInfo := newArchSpecificInfo(ctx, archType, osType, osSpecificVariantPropertiesFactory, archVariants) + for _, id := range archIds { + archVariants := variantsByArchId[id] + archInfo := newArchSpecificInfo(ctx, id, osType, osSpecificVariantPropertiesFactory, archVariants) osInfo.archInfos = append(osInfo.archInfos, archInfo) } @@ -1430,7 +1436,7 @@ func (osInfo *osTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonV multilib := multilibNone for _, archInfo := range osInfo.archInfos { - multilib = multilib.addArchType(archInfo.archType) + multilib = multilib.addArchType(archInfo.archId.archType) // Optimize the arch properties first. archInfo.optimizeProperties(ctx, commonValueExtractor) @@ -1523,23 +1529,67 @@ func (osInfo *osTypeSpecificInfo) String() string { return fmt.Sprintf("OsType{%s}", osInfo.osType) } +// archId encapsulates the information needed to identify a combination of arch type and native +// bridge support. +// +// Conceptually, native bridge support is a facet of an android.Target, not an android.Arch as it is +// essentially using one android.Arch to implement another. However, in terms of the handling of +// the variants native bridge is treated as part of the arch variation. See the ArchVariation method +// on android.Target. +// +// So, it makes sense when optimizing the variants to combine native bridge with the arch type. +type archId struct { + // The arch type of the variant's target. + archType android.ArchType + + // True if the variants is for the native bridge, false otherwise. + nativeBridge bool +} + +// propertyName returns the name of the property corresponding to use for this arch id. +func (i *archId) propertyName() string { + name := i.archType.Name + if i.nativeBridge { + // Note: This does not result in a valid property because there is no architecture specific + // native bridge property, only a generic "native_bridge" property. However, this will be used + // in error messages if there is an attempt to use this in a generated bp file. + name += "_native_bridge" + } + return name +} + +func (i *archId) String() string { + return fmt.Sprintf("ArchType{%s}, NativeBridge{%t}", i.archType, i.nativeBridge) +} + +// archIdFromTarget returns an archId initialized from information in the supplied target. +func archIdFromTarget(target android.Target) archId { + return archId{ + archType: target.Arch.ArchType, + nativeBridge: target.NativeBridge == android.NativeBridgeEnabled, + } +} + +// commonArchId is the archId for the common architecture. +var commonArchId = archId{archType: android.Common} + type archTypeSpecificInfo struct { baseInfo - archType android.ArchType - osType android.OsType + archId archId + osType android.OsType - linkInfos []*linkTypeSpecificInfo + imageVariantInfos []*imageVariantSpecificInfo } var _ propertiesContainer = (*archTypeSpecificInfo)(nil) // Create a new archTypeSpecificInfo for the specified arch type and its properties // structures populated with information from the variants. -func newArchSpecificInfo(ctx android.SdkMemberContext, archType android.ArchType, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo { +func newArchSpecificInfo(ctx android.SdkMemberContext, archId archId, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo { // Create an arch specific info into which the variant properties can be copied. - archInfo := &archTypeSpecificInfo{archType: archType, osType: osType} + archInfo := &archTypeSpecificInfo{archId: archId, osType: osType} // Create the properties into which the arch type specific properties will be // added. @@ -1548,17 +1598,17 @@ func newArchSpecificInfo(ctx android.SdkMemberContext, archType android.ArchType if len(archVariants) == 1 { archInfo.Properties.PopulateFromVariant(ctx, archVariants[0]) } else { - // There is more than one variant for this arch type which must be differentiated - // by link type. - for _, linkVariant := range archVariants { - linkType := getLinkType(linkVariant) - if linkType == "" { - panic(fmt.Errorf("expected one arch specific variant as it is not identified by link type but found %d", len(archVariants))) - } else { - linkInfo := newLinkSpecificInfo(ctx, linkType, variantPropertiesFactory, linkVariant) + // Group the variants by image type. + variantsByImage := make(map[string][]android.Module) + for _, variant := range archVariants { + image := variant.ImageVariation().Variation + variantsByImage[image] = append(variantsByImage[image], variant) + } - archInfo.linkInfos = append(archInfo.linkInfos, linkInfo) - } + // Create the image variant info in a fixed order. + for _, imageVariantName := range android.SortedStringKeys(variantsByImage) { + variants := variantsByImage[imageVariantName] + archInfo.imageVariantInfos = append(archInfo.imageVariantInfos, newImageVariantSpecificInfo(ctx, imageVariantName, variantPropertiesFactory, variants)) } } @@ -1588,30 +1638,136 @@ func getLinkType(variant android.Module) string { // Optimize the properties by extracting common properties from link type specific // properties into arch type specific properties. func (archInfo *archTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) { - if len(archInfo.linkInfos) == 0 { + if len(archInfo.imageVariantInfos) == 0 { return } - extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, archInfo.Properties, archInfo.linkInfos) + // Optimize the image variant properties first. + for _, imageVariantInfo := range archInfo.imageVariantInfos { + imageVariantInfo.optimizeProperties(ctx, commonValueExtractor) + } + + extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, archInfo.Properties, archInfo.imageVariantInfos) } // Add the properties for an arch type to a property set. func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) { - archTypeName := archInfo.archType.Name - archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName) + archPropertySuffix := archInfo.archId.propertyName() + propertySetName := archOsPrefix + archPropertySuffix + archTypePropertySet := archPropertySet.AddPropertySet(propertySetName) // Enable the <os>_<arch> variant explicitly when we've disabled it by default on host. if ctx.memberType.IsHostOsDependent() && archInfo.osType.Class == android.Host { archTypePropertySet.AddProperty("enabled", true) } addSdkMemberPropertiesToSet(ctx, archInfo.Properties, archTypePropertySet) - for _, linkInfo := range archInfo.linkInfos { - linkInfo.addToPropertySet(ctx, archTypePropertySet) + for _, imageVariantInfo := range archInfo.imageVariantInfos { + imageVariantInfo.addToPropertySet(ctx, archTypePropertySet) + } + + // If this is for a native bridge architecture then make sure that the property set does not + // contain any properties as providing native bridge specific properties is not currently + // supported. + if archInfo.archId.nativeBridge { + propertySetContents := getPropertySetContents(archTypePropertySet) + if propertySetContents != "" { + ctx.SdkModuleContext().ModuleErrorf("Architecture variant %q of sdk member %q has properties distinct from other variants; this is not yet supported. The properties are:\n%s", + propertySetName, ctx.name, propertySetContents) + } + } +} + +// getPropertySetContents returns the string representation of the contents of a property set, after +// recursively pruning any empty nested property sets. +func getPropertySetContents(propertySet android.BpPropertySet) string { + set := propertySet.(*bpPropertySet) + set.transformContents(pruneEmptySetTransformer{}) + if len(set.properties) != 0 { + contents := &generatedContents{} + contents.Indent() + outputPropertySet(contents, set) + setAsString := contents.content.String() + return setAsString } + return "" } func (archInfo *archTypeSpecificInfo) String() string { - return fmt.Sprintf("ArchType{%s}", archInfo.archType) + return archInfo.archId.String() +} + +type imageVariantSpecificInfo struct { + baseInfo + + imageVariant string + + linkInfos []*linkTypeSpecificInfo +} + +func newImageVariantSpecificInfo(ctx android.SdkMemberContext, imageVariant string, variantPropertiesFactory variantPropertiesFactoryFunc, imageVariants []android.Module) *imageVariantSpecificInfo { + + // Create an image variant specific info into which the variant properties can be copied. + imageInfo := &imageVariantSpecificInfo{imageVariant: imageVariant} + + // Create the properties into which the image variant specific properties will be added. + imageInfo.Properties = variantPropertiesFactory() + + if len(imageVariants) == 1 { + imageInfo.Properties.PopulateFromVariant(ctx, imageVariants[0]) + } else { + // There is more than one variant for this image variant which must be differentiated by link + // type. + for _, linkVariant := range imageVariants { + linkType := getLinkType(linkVariant) + if linkType == "" { + panic(fmt.Errorf("expected one arch specific variant as it is not identified by link type but found %d", len(imageVariants))) + } else { + linkInfo := newLinkSpecificInfo(ctx, linkType, variantPropertiesFactory, linkVariant) + + imageInfo.linkInfos = append(imageInfo.linkInfos, linkInfo) + } + } + } + + return imageInfo +} + +// Optimize the properties by extracting common properties from link type specific +// properties into arch type specific properties. +func (imageInfo *imageVariantSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) { + if len(imageInfo.linkInfos) == 0 { + return + } + + extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, imageInfo.Properties, imageInfo.linkInfos) +} + +// Add the properties for an arch type to a property set. +func (imageInfo *imageVariantSpecificInfo) addToPropertySet(ctx *memberContext, propertySet android.BpPropertySet) { + if imageInfo.imageVariant != android.CoreVariation { + propertySet = propertySet.AddPropertySet(imageInfo.imageVariant) + } + + addSdkMemberPropertiesToSet(ctx, imageInfo.Properties, propertySet) + + for _, linkInfo := range imageInfo.linkInfos { + linkInfo.addToPropertySet(ctx, propertySet) + } + + // If this is for a non-core image variant then make sure that the property set does not contain + // any properties as providing non-core image variant specific properties for prebuilts is not + // currently supported. + if imageInfo.imageVariant != android.CoreVariation { + propertySetContents := getPropertySetContents(propertySet) + if propertySetContents != "" { + ctx.SdkModuleContext().ModuleErrorf("Image variant %q of sdk member %q has properties distinct from other variants; this is not yet supported. The properties are:\n%s", + imageInfo.imageVariant, ctx.name, propertySetContents) + } + } +} + +func (imageInfo *imageVariantSpecificInfo) String() string { + return imageInfo.imageVariant } type linkTypeSpecificInfo struct { @@ -1651,6 +1807,9 @@ type memberContext struct { builder *snapshotBuilder memberType android.SdkMemberType name string + + // The set of traits required of this member. + requiredTraits android.SdkMemberTraitSet } func (m *memberContext) SdkModuleContext() android.ModuleContext { @@ -1669,6 +1828,10 @@ func (m *memberContext) Name() string { return m.name } +func (m *memberContext) RequiresTrait(trait android.SdkMemberTrait) bool { + return m.requiredTraits.Contains(trait) +} + func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) { memberType := member.memberType diff --git a/tradefed/autogen.go b/tradefed/autogen.go index 3d96c8457..da5582973 100644 --- a/tradefed/autogen.go +++ b/tradefed/autogen.go @@ -227,17 +227,17 @@ func AutoGenPythonBinaryHostTestConfig(ctx android.ModuleContext, testConfigProp } func AutoGenRustTestConfig(ctx android.ModuleContext, testConfigProp *string, - testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path { + testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool, testInstallBase string) android.Path { path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp) if autogenPath != nil { templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) if templatePath.Valid() { - autogenTemplate(ctx, autogenPath, templatePath.String(), config, "") + autogenTemplate(ctx, autogenPath, templatePath.String(), config, testInstallBase) } else { if ctx.Device() { - autogenTemplate(ctx, autogenPath, "${RustDeviceTestConfigTemplate}", config, "") + autogenTemplate(ctx, autogenPath, "${RustDeviceTestConfigTemplate}", config, testInstallBase) } else { - autogenTemplate(ctx, autogenPath, "${RustHostTestConfigTemplate}", config, "") + autogenTemplate(ctx, autogenPath, "${RustHostTestConfigTemplate}", config, testInstallBase) } } return autogenPath |