Merge changes I957f3df8,I68986dcc
* changes:
Consolidate the code to resolve a deapexer module dependency.
Propagate the dex jar path as an OptionalPath which is either valid or invalid with a message.
diff --git a/android/Android.bp b/android/Android.bp
index f3a3850..6450a06 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -110,6 +110,7 @@
"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 ddc082b..6add1b1 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -934,6 +934,8 @@
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 bfd0f90..1cd84c9 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -271,12 +271,11 @@
// 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 50b79fa..2241255 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -809,7 +809,16 @@
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/neverallow.go b/android/neverallow.go
index 19b58a7..a91d523 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -152,7 +152,7 @@
javaDeviceForHostProjectsAllowedList := []string{
"external/guava",
"external/robolectric-shadows",
- "framework/layoutlib",
+ "frameworks/layoutlib",
}
return []Rule{
diff --git a/android/sdk.go b/android/sdk.go
index 100f63b..1d63d7a 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -15,6 +15,7 @@
package android
import (
+ "fmt"
"sort"
"strings"
@@ -376,6 +377,224 @@
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 @@
// 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 @@
// 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 @@
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
+// registeredModuleExportsMemberTypes is the set of registered SdkMemberTypes for module_exports
+// modules.
+var registeredModuleExportsMemberTypes = &sdkRegistry{}
- // 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)
+// registeredSdkMemberTypes is the set of registered registeredSdkMemberTypes for sdk modules.
+var registeredSdkMemberTypes = &sdkRegistry{}
- // 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]
-
- return t1.SdkPropertyName() < t2.SdkPropertyName()
- })
-
- // 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
}
+
+ registerables := registry.registeredObjects()
+ types := make([]SdkMemberType, len(registerables))
+ for i, registerable := range registerables {
+ types[i] = registerable.(SdkMemberType)
+ }
+ return registry.uniqueOnceKey(), types
}
-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)
-}
-
-// 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 @@
// 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 0000000..51aeb31
--- /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/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index d731f3e..0bd71c6 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -111,14 +111,20 @@
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 @@
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/bp2build/Android.bp b/bp2build/Android.bp
index 40526a6..1250e92 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -33,6 +33,7 @@
"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/cc_genrule_conversion_test.go b/bp2build/cc_genrule_conversion_test.go
new file mode 100644
index 0000000..a7e9cb2
--- /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/cc/Android.bp b/cc/Android.bp
index bff2761..190d55e 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -63,6 +63,7 @@
"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/cc.go b/cc/cc.go
index d2f8a12..57e7887 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1711,7 +1711,9 @@
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 d4fcf7c..e72efae 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -47,17 +47,29 @@
"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 0ca901e..9df5228 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -21,7 +21,7 @@
)
func init() {
- android.RegisterModuleType("cc_genrule", genRuleFactory)
+ android.RegisterModuleType("cc_genrule", GenRuleFactory)
}
type GenruleExtraProperties struct {
@@ -37,7 +37,7 @@
// 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 @@
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 45b343b..b6afb05 100644
--- a/cc/genrule_test.go
+++ b/cc/genrule_test.go
@@ -23,7 +23,7 @@
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/library_headers.go b/cc/library_headers.go
index 14b90c1..b335035 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -33,6 +33,9 @@
PropertyName: "native_header_libs",
SupportsSdk: true,
HostOsDependent: true,
+ Traits: []android.SdkMemberTrait{
+ nativeBridgeSdkTrait,
+ },
},
prebuiltModuleType: "cc_prebuilt_library_headers",
noOutputFiles: true,
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 559e940..bed7954 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -75,8 +75,33 @@
}
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 {
+ 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
+ }
for _, target := range targets {
name, version := StubsLibNameAndVersion(lib)
if version == "" {
@@ -122,6 +147,10 @@
ccModule := member.Variants()[0].(*Module)
+ if ctx.RequiresTrait(nativeBridgeSdkTrait) {
+ pbm.AddProperty("native_bridge_supported", true)
+ }
+
if proptools.Bool(ccModule.Properties.Recovery_available) {
pbm.AddProperty("recovery_available", true)
}
@@ -436,7 +465,11 @@
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 0000000..1326d57
--- /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 d0dca6b..b0a220c 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -33,7 +33,7 @@
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/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp
index 703a875..e85163e 100644
--- a/cmd/soong_build/Android.bp
+++ b/cmd/soong_build/Android.bp
@@ -22,6 +22,7 @@
"blueprint",
"blueprint-bootstrap",
"golang-protobuf-proto",
+ "golang-protobuf-android",
"soong",
"soong-android",
"soong-bp2build",
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 09a2234..c5e8896 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -23,14 +23,14 @@
"strings"
"time"
+ "android/soong/android"
"android/soong/bp2build"
"android/soong/shared"
"github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/deptools"
"github.com/google/blueprint/pathtools"
-
- "android/soong/android"
+ androidProtobuf "google.golang.org/protobuf/android"
)
var (
@@ -85,6 +85,12 @@
// Flags that probably shouldn't be flags of soong_build but we haven't found
// the time to remove them yet
flag.BoolVar(&runGoTests, "t", false, "build and run go tests during bootstrap")
+
+ // Disable deterministic randomization in the protobuf package, so incremental
+ // builds with unrelated Soong changes don't trigger large rebuilds (since we
+ // write out text protos in command lines, and command line changes trigger
+ // rebuilds).
+ androidProtobuf.DisableRand()
}
func newNameResolver(config android.Config) *android.NameResolver {
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 7733c1b..965b755 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -261,10 +261,18 @@
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 bde6e97..f4bde70 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -69,6 +69,7 @@
})
android.RegisterBp2BuildMutator("genrule", GenruleBp2Build)
+ android.RegisterBp2BuildMutator("cc_genrule", CcGenruleBp2Build)
}
func RegisterGenruleBp2BuildDeps(ctx android.RegisterMutatorsContext) {
@@ -826,6 +827,22 @@
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 @@
}
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 @@
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/droidstubs.go b/java/droidstubs.go
index ec1b04a..7fd88fc 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -156,6 +156,7 @@
// 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) AnnotationsZip() android.Path {
+ return d.annotationsZip
+}
+
func (d *Droidstubs) ApiFilePath() android.Path {
return d.apiFilePath
}
diff --git a/java/robolectric.go b/java/robolectric.go
index a0c9c7f..5d62aee 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -417,10 +417,10 @@
}
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 0c61f94..58180f7 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -550,6 +550,9 @@
// 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) 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 @@
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 @@
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 @@
// 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 @@
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)
@@ -1888,6 +1897,9 @@
// The removed.txt
Removed_api *string `android:"path"`
+
+ // Annotation zip
+ Annotations *string `android:"path"`
}
type sdkLibraryImportProperties struct {
@@ -2194,6 +2206,7 @@
}
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)
}
@@ -2541,6 +2554,7 @@
StubsSrcJar android.Path
CurrentApiFile android.Path
RemovedApiFile android.Path
+ AnnotationsZip android.Path
SdkVersion string
}
@@ -2566,6 +2580,10 @@
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
}
}
@@ -2630,6 +2648,12 @@
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 d6c0946..be23536 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -248,7 +248,7 @@
}
}
-func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) {
+func TestJavaSdkLibrary_AccessOutputFiles(t *testing.T) {
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -258,6 +258,31 @@
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 @@
java_library {
name: "bar",
srcs: ["b.java", ":foo{.public.stubs.source}"],
+ java_resources: [":foo{.public.annotations.zip}"],
}
`)
}
@@ -329,6 +355,7 @@
stub_srcs: ["a.java"],
current_api: "api/current.txt",
removed_api: "api/removed.txt",
+ annotations: "x/annotations.zip",
},
}
@@ -338,6 +365,7 @@
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 a642753..99d55a0 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -300,6 +300,7 @@
"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 221014e..0ee673d 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -50,6 +50,7 @@
"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 7bd9af4..1ce71f6 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -231,6 +231,7 @@
for _, cfg := range compiler.Properties.Cfgs {
flags = append(flags, "--cfg '"+cfg+"'")
}
+
return flags
}
@@ -239,6 +240,24 @@
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 @@
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 @@
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 8c10e29..38dae4d 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -430,15 +430,25 @@
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 c217959..804d79f 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -63,6 +63,12 @@
&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 0000000..cc81938
--- /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 0cd299d..0a7d68d 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -436,6 +436,8 @@
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 @@
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/sdk/Android.bp b/sdk/Android.bp
index 0c9bf27..c6544d6 100644
--- a/sdk/Android.bp
+++ b/sdk/Android.bp
@@ -16,6 +16,7 @@
srcs: [
"bp.go",
"exports.go",
+ "member_trait.go",
"member_type.go",
"sdk.go",
"update.go",
@@ -28,6 +29,7 @@
"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 25e35fc..da90c6d 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -32,6 +32,23 @@
"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)
@@ -1979,6 +1996,91 @@
)
}
+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 TestHostSnapshotWithCcHeadersLibrary(t *testing.T) {
result := testSdkWithCc(t, `
sdk {
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 73ef7ea..2b53739 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -1205,6 +1205,55 @@
)
}
+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 {
diff --git a/sdk/member_trait.go b/sdk/member_trait.go
new file mode 100644
index 0000000..4229ca8
--- /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 0000000..a3db189
--- /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 9aab61d..10669fe 100644
--- a/sdk/member_type.go
+++ b/sdk/member_type.go
@@ -64,14 +64,7 @@
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 6dea752..84c9a96 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -53,6 +53,13 @@
// 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 @@
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 @@
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 @@
}}
}
+// 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 @@
}
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 89a5c92..02e61fb 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -393,10 +393,18 @@
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 @@
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 @@
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 @@
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,11 +1529,55 @@
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
}
@@ -1536,10 +1586,10 @@
// 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.
@@ -1597,8 +1647,9 @@
// 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)
@@ -1608,10 +1659,36 @@
for _, linkInfo := range archInfo.linkInfos {
linkInfo.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 linkTypeSpecificInfo struct {
@@ -1651,6 +1728,9 @@
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 +1749,10 @@
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