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
diff --git a/android/sdk.go b/android/sdk.go
new file mode 100644
index 0000000..52c392f
--- /dev/null
+++ b/android/sdk.go
@@ -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)
+}