Introduce module type 'sdk'
This change introduces a new module type named 'sdk'. It is a logical group of prebuilt modules that together provide a context (e.g. APIs) in which Mainline modules (such as APEXes) are built. A prebuilt module (e.g. java_import) can join an sdk by adding it to the sdk module as shown below: sdk { name: "mysdk#20", java_libs: ["myjavalib_mysdk_20"], } java_import { name: "myjavalib_mysdk_20", srcs: ["myjavalib-v20.jar"], sdk_member_name: "myjavalib", } sdk { name: "mysdk#21", java_libs: ["myjavalib_mysdk_21"], } java_import { name: "myjavalib_mysdk_21", srcs: ["myjavalib-v21.jar"], sdk_member_name: "myjavalib", } java_library { name: "myjavalib", srcs: ["**/*/*.java"], } An APEX can specify the SDK(s) that it wants to build with via the new 'uses_sdks' property. apex { name: "myapex", java_libs: ["libX", "libY"], uses_sdks: ["mysdk#20"], } With this, libX, libY, and their transitive dependencies are all built with the version 20 of myjavalib (the first java_import module) instead of the other one (which is for version 21) and java_library having the same name (which is for ToT). Bug: 138182343 Test: m (sdk_test.go added) Change-Id: I7e14c524a7d6a0d9f575fb20822080f39818c01e
This commit is contained in:
parent
1f6c94a3ac
commit
d1063c1586
21
Android.bp
21
Android.bp
|
@ -67,6 +67,7 @@ bootstrap_go_package {
|
|||
"android/proto.go",
|
||||
"android/register.go",
|
||||
"android/rule_builder.go",
|
||||
"android/sdk.go",
|
||||
"android/sh_binary.go",
|
||||
"android/singleton.go",
|
||||
"android/testing.go",
|
||||
|
@ -474,6 +475,26 @@ bootstrap_go_package {
|
|||
pluginFor: ["soong_build"],
|
||||
}
|
||||
|
||||
bootstrap_go_package {
|
||||
name: "soong-sdk",
|
||||
pkgPath: "android/soong/sdk",
|
||||
deps: [
|
||||
"blueprint",
|
||||
"soong",
|
||||
"soong-android",
|
||||
"soong-apex",
|
||||
"soong-cc",
|
||||
"soong-java",
|
||||
],
|
||||
srcs: [
|
||||
"sdk/sdk.go",
|
||||
],
|
||||
testSrcs: [
|
||||
"sdk/sdk_test.go",
|
||||
],
|
||||
pluginFor: ["soong_build"],
|
||||
}
|
||||
|
||||
//
|
||||
// Defaults to enable various configurations of host bionic
|
||||
//
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
// Copyright (C) 2019 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 (
|
||||
"strings"
|
||||
|
||||
"github.com/google/blueprint/proptools"
|
||||
)
|
||||
|
||||
// SdkAware is the interface that must be supported by any module to become a member of SDK or to be
|
||||
// built with SDK
|
||||
type SdkAware interface {
|
||||
Module
|
||||
sdkBase() *SdkBase
|
||||
MakeMemberOf(sdk SdkRef)
|
||||
IsInAnySdk() bool
|
||||
ContainingSdk() SdkRef
|
||||
MemberName() string
|
||||
BuildWithSdks(sdks SdkRefs)
|
||||
RequiredSdks() SdkRefs
|
||||
}
|
||||
|
||||
// SdkRef refers to a version of an SDK
|
||||
type SdkRef struct {
|
||||
Name string
|
||||
Version string
|
||||
}
|
||||
|
||||
const (
|
||||
// currentVersion refers to the in-development version of an SDK
|
||||
currentVersion = "current"
|
||||
)
|
||||
|
||||
// IsCurrentVersion determines if the SdkRef is referencing to an in-development version of an SDK
|
||||
func (s SdkRef) IsCurrentVersion() bool {
|
||||
return s.Version == currentVersion
|
||||
}
|
||||
|
||||
// IsCurrentVersionOf determines if the SdkRef is referencing to an in-development version of the
|
||||
// specified SDK
|
||||
func (s SdkRef) IsCurrentVersionOf(name string) bool {
|
||||
return s.Name == name && s.IsCurrentVersion()
|
||||
}
|
||||
|
||||
// ParseSdkRef parses a `name#version` style string into a corresponding SdkRef struct
|
||||
func ParseSdkRef(ctx BaseModuleContext, str string, property string) SdkRef {
|
||||
tokens := strings.Split(str, "#")
|
||||
if len(tokens) < 1 || len(tokens) > 2 {
|
||||
ctx.PropertyErrorf(property, "%q does not follow name#version syntax", str)
|
||||
return SdkRef{Name: "invalid sdk name", Version: "invalid sdk version"}
|
||||
}
|
||||
|
||||
name := tokens[0]
|
||||
|
||||
version := currentVersion // If version is omitted, defaults to "current"
|
||||
if len(tokens) == 2 {
|
||||
version = tokens[1]
|
||||
}
|
||||
|
||||
return SdkRef{Name: name, Version: version}
|
||||
}
|
||||
|
||||
type SdkRefs []SdkRef
|
||||
|
||||
func (refs SdkRefs) Contains(s SdkRef) bool {
|
||||
for _, r := range refs {
|
||||
if r == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type sdkProperties struct {
|
||||
// The SDK that this module is a member of. nil if it is not a member of any SDK
|
||||
ContainingSdk *SdkRef `blueprint:"mutated"`
|
||||
|
||||
// The list of SDK names and versions that are used to build this module
|
||||
RequiredSdks SdkRefs `blueprint:"mutated"`
|
||||
|
||||
// Name of the module that this sdk member is representing
|
||||
Sdk_member_name *string
|
||||
}
|
||||
|
||||
// SdkBase is a struct that is expected to be included in module types to implement the SdkAware
|
||||
// interface. InitSdkAwareModule should be called to initialize this struct.
|
||||
type SdkBase struct {
|
||||
properties sdkProperties
|
||||
}
|
||||
|
||||
func (s *SdkBase) sdkBase() *SdkBase {
|
||||
return s
|
||||
}
|
||||
|
||||
// MakeMemberof sets this module to be a member of a specific SDK
|
||||
func (s *SdkBase) MakeMemberOf(sdk SdkRef) {
|
||||
s.properties.ContainingSdk = &sdk
|
||||
}
|
||||
|
||||
// IsInAnySdk returns true if this module is a member of any SDK
|
||||
func (s *SdkBase) IsInAnySdk() bool {
|
||||
return s.properties.ContainingSdk != nil
|
||||
}
|
||||
|
||||
// ContainingSdk returns the SDK that this module is a member of
|
||||
func (s *SdkBase) ContainingSdk() SdkRef {
|
||||
if s.properties.ContainingSdk != nil {
|
||||
return *s.properties.ContainingSdk
|
||||
}
|
||||
return SdkRef{Name: "", Version: currentVersion}
|
||||
}
|
||||
|
||||
// Membername returns the name of the module that this SDK member is overriding
|
||||
func (s *SdkBase) MemberName() string {
|
||||
return proptools.String(s.properties.Sdk_member_name)
|
||||
}
|
||||
|
||||
// BuildWithSdks is used to mark that this module has to be built with the given SDK(s).
|
||||
func (s *SdkBase) BuildWithSdks(sdks SdkRefs) {
|
||||
s.properties.RequiredSdks = sdks
|
||||
}
|
||||
|
||||
// RequiredSdks returns the SDK(s) that this module has to be built with
|
||||
func (s *SdkBase) RequiredSdks() SdkRefs {
|
||||
return s.properties.RequiredSdks
|
||||
}
|
||||
|
||||
// InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including
|
||||
// SdkBase.
|
||||
func InitSdkAwareModule(m SdkAware) {
|
||||
base := m.sdkBase()
|
||||
m.AddProperties(&base.properties)
|
||||
}
|
28
apex/apex.go
28
apex/apex.go
|
@ -185,7 +185,7 @@ func init() {
|
|||
pctx.HostBinToolVariable("zipalign", "zipalign")
|
||||
pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
|
||||
|
||||
android.RegisterModuleType("apex", apexBundleFactory)
|
||||
android.RegisterModuleType("apex", BundleFactory)
|
||||
android.RegisterModuleType("apex_test", testApexBundleFactory)
|
||||
android.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
|
||||
android.RegisterModuleType("apex_defaults", defaultsFactory)
|
||||
|
@ -195,12 +195,14 @@ func init() {
|
|||
ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator).Parallel()
|
||||
ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator).Parallel()
|
||||
})
|
||||
android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
||||
android.PostDepsMutators(RegisterPostDepsMutators)
|
||||
}
|
||||
|
||||
func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
|
||||
ctx.TopDown("apex_deps", apexDepsMutator)
|
||||
ctx.BottomUp("apex", apexMutator).Parallel()
|
||||
ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
|
||||
ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -409,6 +411,12 @@ type apexBundleProperties struct {
|
|||
// To distinguish between flattened and non-flattened variants.
|
||||
// if set true, then this variant is flattened variant.
|
||||
Flattened bool `blueprint:"mutated"`
|
||||
|
||||
// List of SDKs that are used to build this APEX. A reference to an SDK should be either
|
||||
// `name#version` or `name` which is an alias for `name#current`. If left empty, `platform#current`
|
||||
// is implied. This value affects all modules included in this APEX. In other words, they are
|
||||
// also built with the SDKs specified here.
|
||||
Uses_sdks []string
|
||||
}
|
||||
|
||||
type apexTargetBundleProperties struct {
|
||||
|
@ -535,6 +543,7 @@ type apexFile struct {
|
|||
type apexBundle struct {
|
||||
android.ModuleBase
|
||||
android.DefaultableModuleBase
|
||||
android.SdkBase
|
||||
|
||||
properties apexBundleProperties
|
||||
targetProperties apexTargetBundleProperties
|
||||
|
@ -737,6 +746,16 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) {
|
|||
if cert != "" {
|
||||
ctx.AddDependency(ctx.Module(), certificateTag, cert)
|
||||
}
|
||||
|
||||
// TODO(jiyong): ensure that all apexes are with non-empty uses_sdks
|
||||
if len(a.properties.Uses_sdks) > 0 {
|
||||
sdkRefs := []android.SdkRef{}
|
||||
for _, str := range a.properties.Uses_sdks {
|
||||
parsed := android.ParseSdkRef(ctx, str, "uses_sdks")
|
||||
sdkRefs = append(sdkRefs, parsed)
|
||||
}
|
||||
a.BuildWithSdks(sdkRefs)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string {
|
||||
|
@ -1706,6 +1725,7 @@ func newApexBundle() *apexBundle {
|
|||
})
|
||||
android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
|
||||
android.InitDefaultableModule(module)
|
||||
android.InitSdkAwareModule(module)
|
||||
return module
|
||||
}
|
||||
|
||||
|
@ -1721,7 +1741,7 @@ func testApexBundleFactory() android.Module {
|
|||
return bundle
|
||||
}
|
||||
|
||||
func apexBundleFactory() android.Module {
|
||||
func BundleFactory() android.Module {
|
||||
return newApexBundle()
|
||||
}
|
||||
|
||||
|
|
|
@ -96,10 +96,10 @@ func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*andr
|
|||
config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER")
|
||||
|
||||
ctx := android.NewTestArchContext()
|
||||
ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory))
|
||||
ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(BundleFactory))
|
||||
ctx.RegisterModuleType("apex_test", android.ModuleFactoryAdaptor(testApexBundleFactory))
|
||||
ctx.RegisterModuleType("apex_vndk", android.ModuleFactoryAdaptor(vndkApexBundleFactory))
|
||||
ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory))
|
||||
ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(ApexKeyFactory))
|
||||
ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
|
||||
ctx.RegisterModuleType("prebuilt_apex", android.ModuleFactoryAdaptor(PrebuiltFactory))
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import (
|
|||
var String = proptools.String
|
||||
|
||||
func init() {
|
||||
android.RegisterModuleType("apex_key", apexKeyFactory)
|
||||
android.RegisterModuleType("apex_key", ApexKeyFactory)
|
||||
android.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ type apexKeyProperties struct {
|
|||
Installable *bool
|
||||
}
|
||||
|
||||
func apexKeyFactory() android.Module {
|
||||
func ApexKeyFactory() android.Module {
|
||||
module := &apexKey{}
|
||||
module.AddProperties(&module.properties)
|
||||
android.InitAndroidArchModule(module, android.HostAndDeviceDefault, android.MultilibCommon)
|
||||
|
|
2
cc/cc.go
2
cc/cc.go
|
@ -407,6 +407,7 @@ type Module struct {
|
|||
android.ModuleBase
|
||||
android.DefaultableModuleBase
|
||||
android.ApexModuleBase
|
||||
android.SdkBase
|
||||
|
||||
Properties BaseProperties
|
||||
VendorProperties VendorProperties
|
||||
|
@ -546,6 +547,7 @@ func (c *Module) Init() android.Module {
|
|||
android.InitDefaultableModule(c)
|
||||
|
||||
android.InitApexModule(c)
|
||||
android.InitSdkAwareModule(c)
|
||||
|
||||
return c
|
||||
}
|
||||
|
|
|
@ -152,6 +152,7 @@ func NewPrebuiltSharedLibrary(hod android.HostOrDeviceSupported) (*Module, *libr
|
|||
|
||||
// Prebuilt libraries can be included in APEXes
|
||||
android.InitApexModule(module)
|
||||
android.InitSdkAwareModule(module)
|
||||
|
||||
return module, library
|
||||
}
|
||||
|
@ -176,6 +177,7 @@ func NewPrebuiltStaticLibrary(hod android.HostOrDeviceSupported) (*Module, *libr
|
|||
module.AddProperties(&prebuilt.properties)
|
||||
|
||||
android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
|
||||
android.InitSdkAwareModule(module)
|
||||
return module, library
|
||||
}
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@ func (j *TestHelperLibrary) AndroidMk() android.AndroidMkData {
|
|||
}
|
||||
|
||||
func (prebuilt *Import) AndroidMk() android.AndroidMkData {
|
||||
if !prebuilt.IsForPlatform() {
|
||||
if !prebuilt.IsForPlatform() || !prebuilt.ContainingSdk().IsCurrentVersion() {
|
||||
return android.AndroidMkData{
|
||||
Disabled: true,
|
||||
}
|
||||
|
|
|
@ -290,6 +290,7 @@ type Module struct {
|
|||
android.ModuleBase
|
||||
android.DefaultableModuleBase
|
||||
android.ApexModuleBase
|
||||
android.SdkBase
|
||||
|
||||
properties CompilerProperties
|
||||
protoProperties android.ProtoProperties
|
||||
|
@ -1632,6 +1633,7 @@ func LibraryFactory() android.Module {
|
|||
|
||||
InitJavaModule(module, android.HostAndDeviceSupported)
|
||||
android.InitApexModule(module)
|
||||
android.InitSdkAwareModule(module)
|
||||
return module
|
||||
}
|
||||
|
||||
|
@ -1912,6 +1914,7 @@ type Import struct {
|
|||
android.DefaultableModuleBase
|
||||
android.ApexModuleBase
|
||||
prebuilt android.Prebuilt
|
||||
android.SdkBase
|
||||
|
||||
properties ImportProperties
|
||||
|
||||
|
@ -2068,6 +2071,7 @@ func ImportFactory() android.Module {
|
|||
android.InitPrebuiltModule(module, &module.properties.Jars)
|
||||
InitJavaModule(module, android.HostAndDeviceSupported)
|
||||
android.InitApexModule(module)
|
||||
android.InitSdkAwareModule(module)
|
||||
return module
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
// Copyright (C) 2019 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 (
|
||||
"github.com/google/blueprint"
|
||||
|
||||
"android/soong/android"
|
||||
// This package doesn't depend on the apex package, but import it to make its mutators to be
|
||||
// registered before mutators in this package. See RegisterPostDepsMutators for more details.
|
||||
_ "android/soong/apex"
|
||||
)
|
||||
|
||||
func init() {
|
||||
android.RegisterModuleType("sdk", ModuleFactory)
|
||||
android.PreDepsMutators(RegisterPreDepsMutators)
|
||||
android.PostDepsMutators(RegisterPostDepsMutators)
|
||||
}
|
||||
|
||||
type sdk struct {
|
||||
android.ModuleBase
|
||||
android.DefaultableModuleBase
|
||||
|
||||
properties sdkProperties
|
||||
}
|
||||
|
||||
type sdkProperties struct {
|
||||
// The list of java_import modules that provide Java stubs for this SDK
|
||||
Java_libs []string
|
||||
Native_shared_libs []string
|
||||
}
|
||||
|
||||
// sdk defines an SDK which is a logical group of modules (e.g. native libs, headers, java libs, etc.)
|
||||
// which Mainline modules like APEX can choose to build with.
|
||||
func ModuleFactory() android.Module {
|
||||
s := &sdk{}
|
||||
s.AddProperties(&s.properties)
|
||||
android.InitAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
|
||||
android.InitDefaultableModule(s)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
// TODO(jiyong): add build rules for creating stubs from members of this SDK
|
||||
}
|
||||
|
||||
// RegisterPreDepsMutators registers pre-deps mutators to support modules implementing SdkAware
|
||||
// interface and the sdk module type. This function has been made public to be called by tests
|
||||
// outside of the sdk package
|
||||
func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
|
||||
ctx.BottomUp("SdkMember", memberMutator).Parallel()
|
||||
ctx.TopDown("SdkMember_deps", memberDepsMutator).Parallel()
|
||||
ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel()
|
||||
}
|
||||
|
||||
// RegisterPostDepshMutators registers post-deps mutators to support modules implementing SdkAware
|
||||
// interface and the sdk module type. This function has been made public to be called by tests
|
||||
// outside of the sdk package
|
||||
func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
|
||||
// These must run AFTER apexMutator. Note that the apex package is imported even though there is
|
||||
// no direct dependency to the package here. sdkDepsMutator sets the SDK requirements from an
|
||||
// APEX to its dependents. Since different versions of the same SDK can be used by different
|
||||
// APEXes, the apex and its dependents (which includes the dependencies to the sdk members)
|
||||
// should have been mutated for the apex before the SDK requirements are set.
|
||||
ctx.TopDown("SdkDepsMutator", sdkDepsMutator).Parallel()
|
||||
ctx.BottomUp("SdkDepsReplaceMutator", sdkDepsReplaceMutator).Parallel()
|
||||
}
|
||||
|
||||
type dependencyTag struct {
|
||||
blueprint.BaseDependencyTag
|
||||
}
|
||||
|
||||
// For dependencies from an SDK module to its members
|
||||
// e.g. mysdk -> libfoo and libbar
|
||||
var sdkMemberDepTag dependencyTag
|
||||
|
||||
// For dependencies from an in-development version of an SDK member to frozen versions of the same member
|
||||
// e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12
|
||||
type sdkMemberVesionedDepTag struct {
|
||||
dependencyTag
|
||||
member string
|
||||
version string
|
||||
}
|
||||
|
||||
// Step 1: create dependencies from an SDK module to its members.
|
||||
func memberMutator(mctx android.BottomUpMutatorContext) {
|
||||
if m, ok := mctx.Module().(*sdk); ok {
|
||||
mctx.AddVariationDependencies(nil, sdkMemberDepTag, m.properties.Java_libs...)
|
||||
|
||||
targets := mctx.MultiTargets()
|
||||
for _, target := range targets {
|
||||
mctx.AddFarVariationDependencies([]blueprint.Variation{
|
||||
{Mutator: "arch", Variation: target.String()},
|
||||
{Mutator: "image", Variation: "core"},
|
||||
{Mutator: "link", Variation: "shared"},
|
||||
}, sdkMemberDepTag, m.properties.Native_shared_libs...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: record that dependencies of SDK modules are members of the SDK modules
|
||||
func memberDepsMutator(mctx android.TopDownMutatorContext) {
|
||||
if _, ok := mctx.Module().(*sdk); ok {
|
||||
mySdkRef := android.ParseSdkRef(mctx, mctx.ModuleName(), "name")
|
||||
mctx.VisitDirectDeps(func(child android.Module) {
|
||||
if member, ok := child.(android.SdkAware); ok {
|
||||
member.MakeMemberOf(mySdkRef)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: create dependencies from the in-development version of an SDK member to frozen versions
|
||||
// of the same member. By having these dependencies, they are mutated for multiple Mainline modules
|
||||
// (apex and apk), each of which might want different sdks to be built with. For example, if both
|
||||
// apex A and B are referencing libfoo which is a member of sdk 'mysdk', the two APEXes can be
|
||||
// built with libfoo.mysdk.11 and libfoo.mysdk.12, respectively depending on which sdk they are
|
||||
// using.
|
||||
func memberInterVersionMutator(mctx android.BottomUpMutatorContext) {
|
||||
if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
|
||||
if !m.ContainingSdk().IsCurrentVersion() {
|
||||
memberName := m.MemberName()
|
||||
tag := sdkMemberVesionedDepTag{member: memberName, version: m.ContainingSdk().Version}
|
||||
mctx.AddReverseDependency(mctx.Module(), tag, memberName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: transitively ripple down the SDK requirements from the root modules like APEX to its
|
||||
// descendants
|
||||
func sdkDepsMutator(mctx android.TopDownMutatorContext) {
|
||||
if m, ok := mctx.Module().(android.SdkAware); ok {
|
||||
// Module types for Mainline modules (e.g. APEX) are expected to implement RequiredSdks()
|
||||
// by reading its own properties like `uses_sdks`.
|
||||
requiredSdks := m.RequiredSdks()
|
||||
if len(requiredSdks) > 0 {
|
||||
mctx.VisitDirectDeps(func(m android.Module) {
|
||||
if dep, ok := m.(android.SdkAware); ok {
|
||||
dep.BuildWithSdks(requiredSdks)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5: if libfoo.mysdk.11 is in the context where version 11 of mysdk is requested, the
|
||||
// versioned module is used instead of the un-versioned (in-development) module libfoo
|
||||
func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) {
|
||||
if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
|
||||
if sdk := m.ContainingSdk(); !sdk.IsCurrentVersion() {
|
||||
if m.RequiredSdks().Contains(sdk) {
|
||||
// Note that this replacement is done only for the modules that have the same
|
||||
// variations as the current module. Since current module is already mutated for
|
||||
// apex references in other APEXes are not affected by this replacement.
|
||||
memberName := m.MemberName()
|
||||
mctx.ReplaceDependencies(memberName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,318 @@
|
|||
// Copyright 2019 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 sdk
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"android/soong/android"
|
||||
"android/soong/apex"
|
||||
"android/soong/cc"
|
||||
"android/soong/java"
|
||||
)
|
||||
|
||||
func testSdkContext(t *testing.T, bp string) (*android.TestContext, android.Config) {
|
||||
config := android.TestArchConfig(buildDir, nil)
|
||||
ctx := android.NewTestArchContext()
|
||||
|
||||
// from android package
|
||||
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
|
||||
ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
|
||||
ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel()
|
||||
})
|
||||
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
||||
ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
|
||||
ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
|
||||
})
|
||||
|
||||
// from java package
|
||||
ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(java.AndroidAppCertificateFactory))
|
||||
ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
|
||||
ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(java.ImportFactory))
|
||||
|
||||
// from cc package
|
||||
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
|
||||
ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory))
|
||||
ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
|
||||
ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(cc.PrebuiltSharedLibraryFactory))
|
||||
ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(cc.PrebuiltStaticLibraryFactory))
|
||||
ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
|
||||
ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
|
||||
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
||||
ctx.BottomUp("image", cc.ImageMutator).Parallel()
|
||||
ctx.BottomUp("link", cc.LinkageMutator).Parallel()
|
||||
ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
|
||||
ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
|
||||
ctx.BottomUp("version", cc.VersionMutator).Parallel()
|
||||
ctx.BottomUp("begin", cc.BeginMutator).Parallel()
|
||||
})
|
||||
|
||||
// from apex package
|
||||
ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apex.BundleFactory))
|
||||
ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apex.ApexKeyFactory))
|
||||
ctx.PostDepsMutators(apex.RegisterPostDepsMutators)
|
||||
|
||||
// from this package
|
||||
ctx.RegisterModuleType("sdk", android.ModuleFactoryAdaptor(ModuleFactory))
|
||||
ctx.PreDepsMutators(RegisterPreDepsMutators)
|
||||
ctx.PostDepsMutators(RegisterPostDepsMutators)
|
||||
|
||||
ctx.Register()
|
||||
|
||||
bp = bp + `
|
||||
apex_key {
|
||||
name: "myapex.key",
|
||||
public_key: "myapex.avbpubkey",
|
||||
private_key: "myapex.pem",
|
||||
}
|
||||
|
||||
android_app_certificate {
|
||||
name: "myapex.cert",
|
||||
certificate: "myapex",
|
||||
}
|
||||
` + cc.GatherRequiredDepsForTest(android.Android)
|
||||
|
||||
ctx.MockFileSystem(map[string][]byte{
|
||||
"Android.bp": []byte(bp),
|
||||
"build/make/target/product/security": nil,
|
||||
"apex_manifest.json": nil,
|
||||
"system/sepolicy/apex/myapex-file_contexts": nil,
|
||||
"system/sepolicy/apex/myapex2-file_contexts": nil,
|
||||
"myapex.avbpubkey": nil,
|
||||
"myapex.pem": nil,
|
||||
"myapex.x509.pem": nil,
|
||||
"myapex.pk8": nil,
|
||||
"Test.java": nil,
|
||||
"Test.cpp": nil,
|
||||
"libfoo.so": nil,
|
||||
})
|
||||
|
||||
return ctx, config
|
||||
}
|
||||
|
||||
func testSdk(t *testing.T, bp string) (*android.TestContext, android.Config) {
|
||||
ctx, config := testSdkContext(t, bp)
|
||||
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
|
||||
android.FailIfErrored(t, errs)
|
||||
_, errs = ctx.PrepareBuildActions(config)
|
||||
android.FailIfErrored(t, errs)
|
||||
return ctx, config
|
||||
}
|
||||
|
||||
// ensure that 'result' contains 'expected'
|
||||
func ensureContains(t *testing.T, result string, expected string) {
|
||||
t.Helper()
|
||||
if !strings.Contains(result, expected) {
|
||||
t.Errorf("%q is not found in %q", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
// ensures that 'result' does not contain 'notExpected'
|
||||
func ensureNotContains(t *testing.T, result string, notExpected string) {
|
||||
t.Helper()
|
||||
if strings.Contains(result, notExpected) {
|
||||
t.Errorf("%q is found in %q", notExpected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func ensureListContains(t *testing.T, result []string, expected string) {
|
||||
t.Helper()
|
||||
if !android.InList(expected, result) {
|
||||
t.Errorf("%q is not found in %v", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func ensureListNotContains(t *testing.T, result []string, notExpected string) {
|
||||
t.Helper()
|
||||
if android.InList(notExpected, result) {
|
||||
t.Errorf("%q is found in %v", notExpected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func pathsToStrings(paths android.Paths) []string {
|
||||
ret := []string{}
|
||||
for _, p := range paths {
|
||||
ret = append(ret, p.String())
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func TestBasicSdkWithJava(t *testing.T) {
|
||||
ctx, _ := testSdk(t, `
|
||||
sdk {
|
||||
name: "mysdk#1",
|
||||
java_libs: ["sdkmember_mysdk_1"],
|
||||
}
|
||||
|
||||
sdk {
|
||||
name: "mysdk#2",
|
||||
java_libs: ["sdkmember_mysdk_2"],
|
||||
}
|
||||
|
||||
java_import {
|
||||
name: "sdkmember",
|
||||
prefer: false,
|
||||
host_supported: true,
|
||||
}
|
||||
|
||||
java_import {
|
||||
name: "sdkmember_mysdk_1",
|
||||
sdk_member_name: "sdkmember",
|
||||
host_supported: true,
|
||||
}
|
||||
|
||||
java_import {
|
||||
name: "sdkmember_mysdk_2",
|
||||
sdk_member_name: "sdkmember",
|
||||
host_supported: true,
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "myjavalib",
|
||||
srcs: ["Test.java"],
|
||||
libs: ["sdkmember"],
|
||||
system_modules: "none",
|
||||
sdk_version: "none",
|
||||
compile_dex: true,
|
||||
host_supported: true,
|
||||
}
|
||||
|
||||
apex {
|
||||
name: "myapex",
|
||||
java_libs: ["myjavalib"],
|
||||
uses_sdks: ["mysdk#1"],
|
||||
key: "myapex.key",
|
||||
certificate: ":myapex.cert",
|
||||
}
|
||||
|
||||
apex {
|
||||
name: "myapex2",
|
||||
java_libs: ["myjavalib"],
|
||||
uses_sdks: ["mysdk#2"],
|
||||
key: "myapex.key",
|
||||
certificate: ":myapex.cert",
|
||||
}
|
||||
`)
|
||||
|
||||
sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_common_myapex").Rule("combineJar").Output
|
||||
sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_common_myapex2").Rule("combineJar").Output
|
||||
|
||||
javalibForMyApex := ctx.ModuleForTests("myjavalib", "android_common_myapex")
|
||||
javalibForMyApex2 := ctx.ModuleForTests("myjavalib", "android_common_myapex2")
|
||||
|
||||
// Depending on the uses_sdks value, different libs are linked
|
||||
ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String())
|
||||
ensureListContains(t, pathsToStrings(javalibForMyApex2.Rule("javac").Implicits), sdkMemberV2.String())
|
||||
}
|
||||
|
||||
func TestBasicSdkWithCc(t *testing.T) {
|
||||
ctx, _ := testSdk(t, `
|
||||
sdk {
|
||||
name: "mysdk#1",
|
||||
native_shared_libs: ["sdkmember_mysdk_1"],
|
||||
}
|
||||
|
||||
sdk {
|
||||
name: "mysdk#2",
|
||||
native_shared_libs: ["sdkmember_mysdk_2"],
|
||||
}
|
||||
|
||||
cc_prebuilt_library_shared {
|
||||
name: "sdkmember",
|
||||
srcs: ["libfoo.so"],
|
||||
prefer: false,
|
||||
system_shared_libs: [],
|
||||
stl: "none",
|
||||
}
|
||||
|
||||
cc_prebuilt_library_shared {
|
||||
name: "sdkmember_mysdk_1",
|
||||
sdk_member_name: "sdkmember",
|
||||
srcs: ["libfoo.so"],
|
||||
system_shared_libs: [],
|
||||
stl: "none",
|
||||
}
|
||||
|
||||
cc_prebuilt_library_shared {
|
||||
name: "sdkmember_mysdk_2",
|
||||
sdk_member_name: "sdkmember",
|
||||
srcs: ["libfoo.so"],
|
||||
system_shared_libs: [],
|
||||
stl: "none",
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "mycpplib",
|
||||
srcs: ["Test.cpp"],
|
||||
shared_libs: ["sdkmember"],
|
||||
system_shared_libs: [],
|
||||
stl: "none",
|
||||
}
|
||||
|
||||
apex {
|
||||
name: "myapex",
|
||||
native_shared_libs: ["mycpplib"],
|
||||
uses_sdks: ["mysdk#1"],
|
||||
key: "myapex.key",
|
||||
certificate: ":myapex.cert",
|
||||
}
|
||||
|
||||
apex {
|
||||
name: "myapex2",
|
||||
native_shared_libs: ["mycpplib"],
|
||||
uses_sdks: ["mysdk#2"],
|
||||
key: "myapex.key",
|
||||
certificate: ":myapex.cert",
|
||||
}
|
||||
`)
|
||||
|
||||
sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_core_shared_myapex").Rule("toc").Output
|
||||
sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_core_shared_myapex2").Rule("toc").Output
|
||||
|
||||
cpplibForMyApex := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex")
|
||||
cpplibForMyApex2 := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex2")
|
||||
|
||||
// Depending on the uses_sdks value, different libs are linked
|
||||
ensureListContains(t, pathsToStrings(cpplibForMyApex.Rule("ld").Implicits), sdkMemberV1.String())
|
||||
ensureListContains(t, pathsToStrings(cpplibForMyApex2.Rule("ld").Implicits), sdkMemberV2.String())
|
||||
}
|
||||
|
||||
var buildDir string
|
||||
|
||||
func setUp() {
|
||||
var err error
|
||||
buildDir, err = ioutil.TempDir("", "soong_sdk_test")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func tearDown() {
|
||||
os.RemoveAll(buildDir)
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
run := func() int {
|
||||
setUp()
|
||||
defer tearDown()
|
||||
|
||||
return m.Run()
|
||||
}
|
||||
|
||||
os.Exit(run())
|
||||
}
|
Loading…
Reference in New Issue