Merge "Replace stringly-typed API levels."
This commit is contained in:
@@ -24,6 +24,192 @@ func init() {
|
|||||||
RegisterSingletonType("api_levels", ApiLevelsSingleton)
|
RegisterSingletonType("api_levels", ApiLevelsSingleton)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An API level, which may be a finalized (numbered) API, a preview (codenamed)
|
||||||
|
// API, or the future API level (10000). Can be parsed from a string with
|
||||||
|
// ApiLevelFromUser or ApiLevelOrPanic.
|
||||||
|
//
|
||||||
|
// The different *types* of API levels are handled separately. Currently only
|
||||||
|
// Java has these, and they're managed with the sdkKind enum of the sdkSpec. A
|
||||||
|
// future cleanup should be to migrate sdkSpec to using ApiLevel instead of its
|
||||||
|
// sdkVersion int, and to move sdkSpec into this package.
|
||||||
|
type ApiLevel struct {
|
||||||
|
// The string representation of the API level.
|
||||||
|
value string
|
||||||
|
|
||||||
|
// A number associated with the API level. The exact value depends on
|
||||||
|
// whether this API level is a preview or final API.
|
||||||
|
//
|
||||||
|
// For final API levels, this is the assigned version number.
|
||||||
|
//
|
||||||
|
// For preview API levels, this value has no meaning except to index known
|
||||||
|
// previews to determine ordering.
|
||||||
|
number int
|
||||||
|
|
||||||
|
// Identifies this API level as either a preview or final API level.
|
||||||
|
isPreview bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the canonical name for this API level. For a finalized API level
|
||||||
|
// this will be the API number as a string. For a preview API level this
|
||||||
|
// will be the codename, or "current".
|
||||||
|
func (this ApiLevel) String() string {
|
||||||
|
return this.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if this is a non-final API level.
|
||||||
|
func (this ApiLevel) IsPreview() bool {
|
||||||
|
return this.isPreview
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if this is the unfinalized "current" API level. This means
|
||||||
|
// different things across Java and native. Java APIs do not use explicit
|
||||||
|
// codenames, so all non-final codenames are grouped into "current". For native
|
||||||
|
// explicit codenames are typically used, and current is the union of all
|
||||||
|
// non-final APIs, including those that may not yet be in any codename.
|
||||||
|
//
|
||||||
|
// Note that in a build where the platform is final, "current" will not be a
|
||||||
|
// preview API level but will instead be canonicalized to the final API level.
|
||||||
|
func (this ApiLevel) IsCurrent() bool {
|
||||||
|
return this.value == "current"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns -1 if the current API level is less than the argument, 0 if they
|
||||||
|
// are equal, and 1 if it is greater than the argument.
|
||||||
|
func (this ApiLevel) CompareTo(other ApiLevel) int {
|
||||||
|
if this.IsPreview() && !other.IsPreview() {
|
||||||
|
return 1
|
||||||
|
} else if !this.IsPreview() && other.IsPreview() {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if this.number < other.number {
|
||||||
|
return -1
|
||||||
|
} else if this.number == other.number {
|
||||||
|
return 0
|
||||||
|
} else {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this ApiLevel) EqualTo(other ApiLevel) bool {
|
||||||
|
return this.CompareTo(other) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this ApiLevel) GreaterThan(other ApiLevel) bool {
|
||||||
|
return this.CompareTo(other) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this ApiLevel) GreaterThanOrEqualTo(other ApiLevel) bool {
|
||||||
|
return this.CompareTo(other) >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this ApiLevel) LessThan(other ApiLevel) bool {
|
||||||
|
return this.CompareTo(other) < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this ApiLevel) LessThanOrEqualTo(other ApiLevel) bool {
|
||||||
|
return this.CompareTo(other) <= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func uncheckedFinalApiLevel(num int) ApiLevel {
|
||||||
|
return ApiLevel{
|
||||||
|
value: strconv.Itoa(num),
|
||||||
|
number: num,
|
||||||
|
isPreview: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Merge with FutureApiLevel
|
||||||
|
var CurrentApiLevel = ApiLevel{
|
||||||
|
value: "current",
|
||||||
|
number: 10000,
|
||||||
|
isPreview: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
var NoneApiLevel = ApiLevel{
|
||||||
|
value: "(no version)",
|
||||||
|
// Not 0 because we don't want this to compare equal with the first preview.
|
||||||
|
number: -1,
|
||||||
|
isPreview: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first version that introduced 64-bit ABIs.
|
||||||
|
var FirstLp64Version = uncheckedFinalApiLevel(21)
|
||||||
|
|
||||||
|
// The first API level that does not require NDK code to link
|
||||||
|
// libandroid_support.
|
||||||
|
var FirstNonLibAndroidSupportVersion = uncheckedFinalApiLevel(21)
|
||||||
|
|
||||||
|
// If the `raw` input is the codename of an API level has been finalized, this
|
||||||
|
// function returns the API level number associated with that API level. If the
|
||||||
|
// input is *not* a finalized codename, the input is returned unmodified.
|
||||||
|
//
|
||||||
|
// For example, at the time of writing, R has been finalized as API level 30,
|
||||||
|
// but S is in development so it has no number assigned. For the following
|
||||||
|
// inputs:
|
||||||
|
//
|
||||||
|
// * "30" -> "30"
|
||||||
|
// * "R" -> "30"
|
||||||
|
// * "S" -> "S"
|
||||||
|
func ReplaceFinalizedCodenames(ctx EarlyModuleContext, raw string) string {
|
||||||
|
num, ok := getFinalCodenamesMap(ctx.Config())[raw]
|
||||||
|
if !ok {
|
||||||
|
return raw
|
||||||
|
}
|
||||||
|
|
||||||
|
return strconv.Itoa(num)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts the given string `raw` to an ApiLevel, possibly returning an error.
|
||||||
|
//
|
||||||
|
// `raw` must be non-empty. Passing an empty string results in a panic.
|
||||||
|
//
|
||||||
|
// "current" will return CurrentApiLevel, which is the ApiLevel associated with
|
||||||
|
// an arbitrary future release (often referred to as API level 10000).
|
||||||
|
//
|
||||||
|
// Finalized codenames will be interpreted as their final API levels, not the
|
||||||
|
// preview of the associated releases. R is now API 30, not the R preview.
|
||||||
|
//
|
||||||
|
// Future codenames return a preview API level that has no associated integer.
|
||||||
|
//
|
||||||
|
// Inputs that are not "current", known previews, or convertible to an integer
|
||||||
|
// will return an error.
|
||||||
|
func ApiLevelFromUser(ctx EarlyModuleContext, raw string) (ApiLevel, error) {
|
||||||
|
if raw == "" {
|
||||||
|
panic("API level string must be non-empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if raw == "current" {
|
||||||
|
return CurrentApiLevel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, preview := range ctx.Config().PreviewApiLevels() {
|
||||||
|
if raw == preview.String() {
|
||||||
|
return preview, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canonical := ReplaceFinalizedCodenames(ctx, raw)
|
||||||
|
asInt, err := strconv.Atoi(canonical)
|
||||||
|
if err != nil {
|
||||||
|
return NoneApiLevel, fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", canonical)
|
||||||
|
}
|
||||||
|
|
||||||
|
apiLevel := uncheckedFinalApiLevel(asInt)
|
||||||
|
return apiLevel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts an API level string `raw` into an ApiLevel in the same method as
|
||||||
|
// `ApiLevelFromUser`, but the input is assumed to have no errors and any errors
|
||||||
|
// will panic instead of returning an error.
|
||||||
|
func ApiLevelOrPanic(ctx EarlyModuleContext, raw string) ApiLevel {
|
||||||
|
value, err := ApiLevelFromUser(ctx, raw)
|
||||||
|
if err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
func ApiLevelsSingleton() Singleton {
|
func ApiLevelsSingleton() Singleton {
|
||||||
return &apiLevelsSingleton{}
|
return &apiLevelsSingleton{}
|
||||||
}
|
}
|
||||||
@@ -52,6 +238,36 @@ func GetApiLevelsJson(ctx PathContext) WritablePath {
|
|||||||
return PathForOutput(ctx, "api_levels.json")
|
return PathForOutput(ctx, "api_levels.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var finalCodenamesMapKey = NewOnceKey("FinalCodenamesMap")
|
||||||
|
|
||||||
|
func getFinalCodenamesMap(config Config) map[string]int {
|
||||||
|
return config.Once(finalCodenamesMapKey, func() interface{} {
|
||||||
|
apiLevelsMap := map[string]int{
|
||||||
|
"G": 9,
|
||||||
|
"I": 14,
|
||||||
|
"J": 16,
|
||||||
|
"J-MR1": 17,
|
||||||
|
"J-MR2": 18,
|
||||||
|
"K": 19,
|
||||||
|
"L": 21,
|
||||||
|
"L-MR1": 22,
|
||||||
|
"M": 23,
|
||||||
|
"N": 24,
|
||||||
|
"N-MR1": 25,
|
||||||
|
"O": 26,
|
||||||
|
"O-MR1": 27,
|
||||||
|
"P": 28,
|
||||||
|
"Q": 29,
|
||||||
|
}
|
||||||
|
|
||||||
|
if Bool(config.productVariables.Platform_sdk_final) {
|
||||||
|
apiLevelsMap["current"] = config.PlatformSdkVersionInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiLevelsMap
|
||||||
|
}).(map[string]int)
|
||||||
|
}
|
||||||
|
|
||||||
var apiLevelsMapKey = NewOnceKey("ApiLevelsMap")
|
var apiLevelsMapKey = NewOnceKey("ApiLevelsMap")
|
||||||
|
|
||||||
func getApiLevelsMap(config Config) map[string]int {
|
func getApiLevelsMap(config Config) map[string]int {
|
||||||
|
@@ -642,8 +642,34 @@ func (c *config) PlatformBaseOS() string {
|
|||||||
return String(c.productVariables.Platform_base_os)
|
return String(c.productVariables.Platform_base_os)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) MinSupportedSdkVersion() int {
|
func (c *config) MinSupportedSdkVersion() ApiLevel {
|
||||||
return 16
|
return uncheckedFinalApiLevel(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *config) FinalApiLevels() []ApiLevel {
|
||||||
|
var levels []ApiLevel
|
||||||
|
for i := 1; i <= c.PlatformSdkVersionInt(); i++ {
|
||||||
|
levels = append(levels, uncheckedFinalApiLevel(i))
|
||||||
|
}
|
||||||
|
return levels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *config) PreviewApiLevels() []ApiLevel {
|
||||||
|
var levels []ApiLevel
|
||||||
|
for i, codename := range c.PlatformVersionActiveCodenames() {
|
||||||
|
levels = append(levels, ApiLevel{
|
||||||
|
value: codename,
|
||||||
|
number: i,
|
||||||
|
isPreview: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return levels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *config) AllSupportedApiLevels() []ApiLevel {
|
||||||
|
var levels []ApiLevel
|
||||||
|
levels = append(levels, c.FinalApiLevels()...)
|
||||||
|
return append(levels, c.PreviewApiLevels()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) DefaultAppTargetSdkInt() int {
|
func (c *config) DefaultAppTargetSdkInt() int {
|
||||||
|
@@ -18,7 +18,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/blueprint"
|
"github.com/google/blueprint"
|
||||||
@@ -31,7 +30,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func androidMakeVarsProvider(ctx MakeVarsContext) {
|
func androidMakeVarsProvider(ctx MakeVarsContext) {
|
||||||
ctx.Strict("MIN_SUPPORTED_SDK_VERSION", strconv.Itoa(ctx.Config().MinSupportedSdkVersion()))
|
ctx.Strict("MIN_SUPPORTED_SDK_VERSION", ctx.Config().MinSupportedSdkVersion().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@@ -13,6 +13,7 @@ bootstrap_go_package {
|
|||||||
],
|
],
|
||||||
srcs: [
|
srcs: [
|
||||||
"androidmk.go",
|
"androidmk.go",
|
||||||
|
"api_level.go",
|
||||||
"builder.go",
|
"builder.go",
|
||||||
"cc.go",
|
"cc.go",
|
||||||
"ccdeps.go",
|
"ccdeps.go",
|
||||||
|
@@ -451,7 +451,7 @@ func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
|
func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
|
||||||
entries.SubName = ndkLibrarySuffix + "." + c.properties.ApiLevel
|
entries.SubName = ndkLibrarySuffix + "." + c.apiLevel.String()
|
||||||
entries.Class = "SHARED_LIBRARIES"
|
entries.Class = "SHARED_LIBRARIES"
|
||||||
|
|
||||||
entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
|
entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
|
||||||
|
71
cc/api_level.go
Normal file
71
cc/api_level.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2020 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 (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"android/soong/android"
|
||||||
|
)
|
||||||
|
|
||||||
|
func minApiForArch(ctx android.BaseModuleContext,
|
||||||
|
arch android.ArchType) android.ApiLevel {
|
||||||
|
|
||||||
|
switch arch {
|
||||||
|
case android.Arm, android.X86:
|
||||||
|
return ctx.Config().MinSupportedSdkVersion()
|
||||||
|
case android.Arm64, android.X86_64:
|
||||||
|
return android.FirstLp64Version
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("Unknown arch %q", arch))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nativeApiLevelFromUser(ctx android.BaseModuleContext,
|
||||||
|
raw string) (android.ApiLevel, error) {
|
||||||
|
|
||||||
|
min := minApiForArch(ctx, ctx.Arch().ArchType)
|
||||||
|
if raw == "minimum" {
|
||||||
|
return min, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := android.ApiLevelFromUser(ctx, raw)
|
||||||
|
if err != nil {
|
||||||
|
return android.NoneApiLevel, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.LessThan(min) {
|
||||||
|
return min, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func nativeApiLevelFromUserWithDefault(ctx android.BaseModuleContext,
|
||||||
|
raw string, defaultValue string) (android.ApiLevel, error) {
|
||||||
|
if raw == "" {
|
||||||
|
raw = defaultValue
|
||||||
|
}
|
||||||
|
return nativeApiLevelFromUser(ctx, raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
func nativeApiLevelOrPanic(ctx android.BaseModuleContext,
|
||||||
|
raw string) android.ApiLevel {
|
||||||
|
value, err := nativeApiLevelFromUser(ctx, raw)
|
||||||
|
if err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
15
cc/cc.go
15
cc/cc.go
@@ -629,7 +629,7 @@ func (c *Module) Toc() android.OptionalPath {
|
|||||||
func (c *Module) ApiLevel() string {
|
func (c *Module) ApiLevel() string {
|
||||||
if c.linker != nil {
|
if c.linker != nil {
|
||||||
if stub, ok := c.linker.(*stubDecorator); ok {
|
if stub, ok := c.linker.(*stubDecorator); ok {
|
||||||
return stub.properties.ApiLevel
|
return stub.apiLevel.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic(fmt.Errorf("ApiLevel() called on non-stub library module: %q", c.BaseModuleName()))
|
panic(fmt.Errorf("ApiLevel() called on non-stub library module: %q", c.BaseModuleName()))
|
||||||
@@ -1682,11 +1682,13 @@ func (c *Module) begin(ctx BaseModuleContext) {
|
|||||||
feature.begin(ctx)
|
feature.begin(ctx)
|
||||||
}
|
}
|
||||||
if ctx.useSdk() && c.IsSdkVariant() {
|
if ctx.useSdk() && c.IsSdkVariant() {
|
||||||
version, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch())
|
version, err := nativeApiLevelFromUser(ctx, ctx.sdkVersion())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.PropertyErrorf("sdk_version", err.Error())
|
ctx.PropertyErrorf("sdk_version", err.Error())
|
||||||
|
c.Properties.Sdk_version = nil
|
||||||
|
} else {
|
||||||
|
c.Properties.Sdk_version = StringPtr(version.String())
|
||||||
}
|
}
|
||||||
c.Properties.Sdk_version = StringPtr(version)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3119,13 +3121,6 @@ func (c *Module) IsSdkVariant() bool {
|
|||||||
return c.Properties.IsSdkVariant || c.AlwaysSdk()
|
return c.Properties.IsSdkVariant || c.AlwaysSdk()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCurrentNdkPrebuiltVersion(ctx DepsContext) string {
|
|
||||||
if ctx.Config().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt {
|
|
||||||
return strconv.Itoa(config.NdkMaxPrebuiltVersionInt)
|
|
||||||
}
|
|
||||||
return ctx.Config().PlatformSdkVersion()
|
|
||||||
}
|
|
||||||
|
|
||||||
func kytheExtractAllFactory() android.Singleton {
|
func kytheExtractAllFactory() android.Singleton {
|
||||||
return &kytheExtractAllSingleton{}
|
return &kytheExtractAllSingleton{}
|
||||||
}
|
}
|
||||||
|
@@ -126,8 +126,6 @@ var (
|
|||||||
ExperimentalCStdVersion = "gnu11"
|
ExperimentalCStdVersion = "gnu11"
|
||||||
ExperimentalCppStdVersion = "gnu++2a"
|
ExperimentalCppStdVersion = "gnu++2a"
|
||||||
|
|
||||||
NdkMaxPrebuiltVersionInt = 27
|
|
||||||
|
|
||||||
// prebuilts/clang default settings.
|
// prebuilts/clang default settings.
|
||||||
ClangDefaultBase = "prebuilts/clang/host"
|
ClangDefaultBase = "prebuilts/clang/host"
|
||||||
ClangDefaultVersion = "clang-r383902b"
|
ClangDefaultVersion = "clang-r383902b"
|
||||||
|
@@ -16,7 +16,6 @@ package cc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -52,6 +51,10 @@ var (
|
|||||||
ndkKnownLibsLock sync.Mutex
|
ndkKnownLibsLock sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The First_version and Unversioned_until properties of this struct should not
|
||||||
|
// be used directly, but rather through the ApiLevel returning methods
|
||||||
|
// firstVersion() and unversionedUntil().
|
||||||
|
|
||||||
// Creates a stub shared library based on the provided version file.
|
// Creates a stub shared library based on the provided version file.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
@@ -77,9 +80,7 @@ type libraryProperties struct {
|
|||||||
// https://github.com/android-ndk/ndk/issues/265.
|
// https://github.com/android-ndk/ndk/issues/265.
|
||||||
Unversioned_until *string
|
Unversioned_until *string
|
||||||
|
|
||||||
// Private property for use by the mutator that splits per-API level. Can be
|
// Use via apiLevel on the stubDecorator.
|
||||||
// one of <number:sdk_version> or <codename> or "current" passed to
|
|
||||||
// "ndkstubgen.py" as it is
|
|
||||||
ApiLevel string `blueprint:"mutated"`
|
ApiLevel string `blueprint:"mutated"`
|
||||||
|
|
||||||
// True if this API is not yet ready to be shipped in the NDK. It will be
|
// True if this API is not yet ready to be shipped in the NDK. It will be
|
||||||
@@ -96,125 +97,33 @@ type stubDecorator struct {
|
|||||||
versionScriptPath android.ModuleGenPath
|
versionScriptPath android.ModuleGenPath
|
||||||
parsedCoverageXmlPath android.ModuleOutPath
|
parsedCoverageXmlPath android.ModuleOutPath
|
||||||
installPath android.Path
|
installPath android.Path
|
||||||
|
|
||||||
|
apiLevel android.ApiLevel
|
||||||
|
firstVersion android.ApiLevel
|
||||||
|
unversionedUntil android.ApiLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
// OMG GO
|
func shouldUseVersionScript(ctx BaseModuleContext, stub *stubDecorator) bool {
|
||||||
func intMax(a int, b int) int {
|
return stub.apiLevel.GreaterThanOrEqualTo(stub.unversionedUntil)
|
||||||
if a > b {
|
|
||||||
return a
|
|
||||||
} else {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalizeNdkApiLevel(ctx android.BaseModuleContext, apiLevel string,
|
|
||||||
arch android.Arch) (string, error) {
|
|
||||||
|
|
||||||
if apiLevel == "" {
|
|
||||||
panic("empty apiLevel not allowed")
|
|
||||||
}
|
|
||||||
|
|
||||||
if apiLevel == "current" {
|
|
||||||
return apiLevel, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
minVersion := ctx.Config().MinSupportedSdkVersion()
|
|
||||||
firstArchVersions := map[android.ArchType]int{
|
|
||||||
android.Arm: minVersion,
|
|
||||||
android.Arm64: 21,
|
|
||||||
android.X86: minVersion,
|
|
||||||
android.X86_64: 21,
|
|
||||||
}
|
|
||||||
|
|
||||||
firstArchVersion, ok := firstArchVersions[arch.ArchType]
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Errorf("Arch %q not found in firstArchVersions", arch.ArchType))
|
|
||||||
}
|
|
||||||
|
|
||||||
if apiLevel == "minimum" {
|
|
||||||
return strconv.Itoa(firstArchVersion), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the NDK drops support for a platform version, we don't want to have to
|
|
||||||
// fix up every module that was using it as its SDK version. Clip to the
|
|
||||||
// supported version here instead.
|
|
||||||
version, err := strconv.Atoi(apiLevel)
|
|
||||||
if err != nil {
|
|
||||||
// Non-integer API levels are codenames.
|
|
||||||
return apiLevel, nil
|
|
||||||
}
|
|
||||||
version = intMax(version, minVersion)
|
|
||||||
|
|
||||||
return strconv.Itoa(intMax(version, firstArchVersion)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getFirstGeneratedVersion(firstSupportedVersion string, platformVersion int) (int, error) {
|
|
||||||
if firstSupportedVersion == "current" {
|
|
||||||
return platformVersion + 1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return strconv.Atoi(firstSupportedVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
func shouldUseVersionScript(ctx android.BaseModuleContext, stub *stubDecorator) (bool, error) {
|
|
||||||
// unversioned_until is normally empty, in which case we should use the version script.
|
|
||||||
if String(stub.properties.Unversioned_until) == "" {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if String(stub.properties.Unversioned_until) == "current" {
|
|
||||||
if stub.properties.ApiLevel == "current" {
|
|
||||||
return true, nil
|
|
||||||
} else {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if stub.properties.ApiLevel == "current" {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
unversionedUntil, err := android.ApiStrToNum(ctx, String(stub.properties.Unversioned_until))
|
|
||||||
if err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
|
|
||||||
version, err := android.ApiStrToNum(ctx, stub.properties.ApiLevel)
|
|
||||||
if err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return version >= unversionedUntil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generatePerApiVariants(ctx android.BottomUpMutatorContext, m *Module,
|
func generatePerApiVariants(ctx android.BottomUpMutatorContext, m *Module,
|
||||||
propName string, propValue string, perSplit func(*Module, string)) {
|
from android.ApiLevel, perSplit func(*Module, android.ApiLevel)) {
|
||||||
platformVersion := ctx.Config().PlatformSdkVersionInt()
|
|
||||||
|
|
||||||
firstSupportedVersion, err := normalizeNdkApiLevel(ctx, propValue,
|
var versions []android.ApiLevel
|
||||||
ctx.Arch())
|
versionStrs := []string{}
|
||||||
if err != nil {
|
for _, version := range ctx.Config().AllSupportedApiLevels() {
|
||||||
ctx.PropertyErrorf(propName, err.Error())
|
if version.GreaterThanOrEqualTo(from) {
|
||||||
|
versions = append(versions, version)
|
||||||
|
versionStrs = append(versionStrs, version.String())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
versions = append(versions, android.CurrentApiLevel)
|
||||||
firstGenVersion, err := getFirstGeneratedVersion(firstSupportedVersion,
|
versionStrs = append(versionStrs, android.CurrentApiLevel.String())
|
||||||
platformVersion)
|
|
||||||
if err != nil {
|
|
||||||
// In theory this is impossible because we've already run this through
|
|
||||||
// normalizeNdkApiLevel above.
|
|
||||||
ctx.PropertyErrorf(propName, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
var versionStrs []string
|
|
||||||
for version := firstGenVersion; version <= platformVersion; version++ {
|
|
||||||
versionStrs = append(versionStrs, strconv.Itoa(version))
|
|
||||||
}
|
|
||||||
versionStrs = append(versionStrs, ctx.Config().PlatformVersionActiveCodenames()...)
|
|
||||||
versionStrs = append(versionStrs, "current")
|
|
||||||
|
|
||||||
modules := ctx.CreateVariations(versionStrs...)
|
modules := ctx.CreateVariations(versionStrs...)
|
||||||
for i, module := range modules {
|
for i, module := range modules {
|
||||||
perSplit(module.(*Module), versionStrs[i])
|
perSplit(module.(*Module), versions[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,25 +137,56 @@ func NdkApiMutator(ctx android.BottomUpMutatorContext) {
|
|||||||
ctx.Module().Disable()
|
ctx.Module().Disable()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
generatePerApiVariants(ctx, m, "first_version",
|
firstVersion, err := nativeApiLevelFromUser(ctx,
|
||||||
String(compiler.properties.First_version),
|
String(compiler.properties.First_version))
|
||||||
func(m *Module, version string) {
|
if err != nil {
|
||||||
|
ctx.PropertyErrorf("first_version", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
generatePerApiVariants(ctx, m, firstVersion,
|
||||||
|
func(m *Module, version android.ApiLevel) {
|
||||||
m.compiler.(*stubDecorator).properties.ApiLevel =
|
m.compiler.(*stubDecorator).properties.ApiLevel =
|
||||||
version
|
version.String()
|
||||||
})
|
})
|
||||||
} else if m.SplitPerApiLevel() && m.IsSdkVariant() {
|
} else if m.SplitPerApiLevel() && m.IsSdkVariant() {
|
||||||
if ctx.Os() != android.Android {
|
if ctx.Os() != android.Android {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
generatePerApiVariants(ctx, m, "min_sdk_version",
|
from, err := nativeApiLevelFromUser(ctx, m.MinSdkVersion())
|
||||||
m.MinSdkVersion(), func(m *Module, version string) {
|
if err != nil {
|
||||||
m.Properties.Sdk_version = &version
|
ctx.PropertyErrorf("min_sdk_version", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
generatePerApiVariants(ctx, m, from,
|
||||||
|
func(m *Module, version android.ApiLevel) {
|
||||||
|
m.Properties.Sdk_version = StringPtr(version.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *stubDecorator) initializeProperties(ctx BaseModuleContext) bool {
|
||||||
|
this.apiLevel = nativeApiLevelOrPanic(ctx, this.properties.ApiLevel)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
this.firstVersion, err = nativeApiLevelFromUser(ctx,
|
||||||
|
String(this.properties.First_version))
|
||||||
|
if err != nil {
|
||||||
|
ctx.PropertyErrorf("first_version", err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.unversionedUntil, err = nativeApiLevelFromUserWithDefault(ctx,
|
||||||
|
String(this.properties.Unversioned_until), "minimum")
|
||||||
|
if err != nil {
|
||||||
|
ctx.PropertyErrorf("unversioned_until", err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (c *stubDecorator) compilerInit(ctx BaseModuleContext) {
|
func (c *stubDecorator) compilerInit(ctx BaseModuleContext) {
|
||||||
c.baseCompiler.compilerInit(ctx)
|
c.baseCompiler.compilerInit(ctx)
|
||||||
|
|
||||||
@@ -340,11 +280,16 @@ func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) O
|
|||||||
ctx.PropertyErrorf("symbol_file", "must end with .map.txt")
|
ctx.PropertyErrorf("symbol_file", "must end with .map.txt")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !c.initializeProperties(ctx) {
|
||||||
|
// Emits its own errors, so we don't need to.
|
||||||
|
return Objects{}
|
||||||
|
}
|
||||||
|
|
||||||
symbolFile := String(c.properties.Symbol_file)
|
symbolFile := String(c.properties.Symbol_file)
|
||||||
objs, versionScript := compileStubLibrary(ctx, flags, symbolFile,
|
objs, versionScript := compileStubLibrary(ctx, flags, symbolFile,
|
||||||
c.properties.ApiLevel, "")
|
c.apiLevel.String(), "")
|
||||||
c.versionScriptPath = versionScript
|
c.versionScriptPath = versionScript
|
||||||
if c.properties.ApiLevel == "current" && ctx.PrimaryArch() {
|
if c.apiLevel.IsCurrent() && ctx.PrimaryArch() {
|
||||||
c.parsedCoverageXmlPath = parseSymbolFileForCoverage(ctx, symbolFile)
|
c.parsedCoverageXmlPath = parseSymbolFileForCoverage(ctx, symbolFile)
|
||||||
}
|
}
|
||||||
return objs
|
return objs
|
||||||
@@ -366,12 +311,7 @@ func (stub *stubDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
|
|||||||
func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
|
func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
|
||||||
objs Objects) android.Path {
|
objs Objects) android.Path {
|
||||||
|
|
||||||
useVersionScript, err := shouldUseVersionScript(ctx, stub)
|
if shouldUseVersionScript(ctx, stub) {
|
||||||
if err != nil {
|
|
||||||
ctx.ModuleErrorf(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if useVersionScript {
|
|
||||||
linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
|
linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
|
||||||
flags.Local.LdFlags = append(flags.Local.LdFlags, linkerScriptFlag)
|
flags.Local.LdFlags = append(flags.Local.LdFlags, linkerScriptFlag)
|
||||||
flags.LdFlagsDeps = append(flags.LdFlagsDeps, stub.versionScriptPath)
|
flags.LdFlagsDeps = append(flags.LdFlagsDeps, stub.versionScriptPath)
|
||||||
@@ -386,8 +326,6 @@ func (stub *stubDecorator) nativeCoverage() bool {
|
|||||||
|
|
||||||
func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {
|
func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {
|
||||||
arch := ctx.Target().Arch.ArchType.Name
|
arch := ctx.Target().Arch.ArchType.Name
|
||||||
apiLevel := stub.properties.ApiLevel
|
|
||||||
|
|
||||||
// arm64 isn't actually a multilib toolchain, so unlike the other LP64
|
// arm64 isn't actually a multilib toolchain, so unlike the other LP64
|
||||||
// architectures it's just installed to lib.
|
// architectures it's just installed to lib.
|
||||||
libDir := "lib"
|
libDir := "lib"
|
||||||
@@ -396,7 +334,7 @@ func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
|
installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
|
||||||
"platforms/android-%s/arch-%s/usr/%s", apiLevel, arch, libDir))
|
"platforms/android-%s/arch-%s/usr/%s", stub.apiLevel, arch, libDir))
|
||||||
stub.installPath = ctx.InstallFile(installDir, path.Base(), path)
|
stub.installPath = ctx.InstallFile(installDir, path.Base(), path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
cc/stl.go
20
cc/stl.go
@@ -17,7 +17,6 @@ package cc
|
|||||||
import (
|
import (
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getNdkStlFamily(m LinkableInterface) string {
|
func getNdkStlFamily(m LinkableInterface) string {
|
||||||
@@ -136,23 +135,8 @@ func (stl *stl) begin(ctx BaseModuleContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func needsLibAndroidSupport(ctx BaseModuleContext) bool {
|
func needsLibAndroidSupport(ctx BaseModuleContext) bool {
|
||||||
versionStr, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch())
|
version := nativeApiLevelOrPanic(ctx, ctx.sdkVersion())
|
||||||
if err != nil {
|
return version.LessThan(android.FirstNonLibAndroidSupportVersion)
|
||||||
ctx.PropertyErrorf("sdk_version", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if versionStr == "current" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
version, err := strconv.Atoi(versionStr)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf(
|
|
||||||
"invalid API level returned from normalizeNdkApiLevel: %q",
|
|
||||||
versionStr))
|
|
||||||
}
|
|
||||||
|
|
||||||
return version < 21
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func staticUnwinder(ctx android.BaseModuleContext) string {
|
func staticUnwinder(ctx android.BaseModuleContext) string {
|
||||||
|
Reference in New Issue
Block a user