Replace stringly-typed API levels.
Handling of API levels within Soong is currently fairly difficult since it isn't always clear based on context what kind of API level a given string represents, how much canonicalizing and error checking the code receiving the string are expected to do, or how those errors should be treated. The API level struct does not export its raw data, so as to keep its "constructor" private to the android package, and to prevent misuse of the `number` field, which is only an implementation detail for preview API levels. API levels can be parsed with either `android.ApiLevelFromUser`, which returns any errors to the caller, or `android.ApiLevelOrPanic`, which is used in the case where the input is trusted and any errors in parsing should panic. Even within the `android` package, these APIs should be preferred over direct construction. For cases where there are context specific parsing requirements, such as handling the "minimum" alias in the cc module, `nativeApiLevelFromUser` and `nativeApiLevelOrPanic` should be used instead. Test: treehugger Bug: http://b/154667674 Change-Id: Id52921fda32cb437fb1775ac2183299dedc0cf20
This commit is contained in:
parent
6b5430203c
commit
1a2462717e
10 changed files with 394 additions and 166 deletions
|
@ -24,6 +24,192 @@ func init() {
|
|||
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 {
|
||||
return &apiLevelsSingleton{}
|
||||
}
|
||||
|
@ -52,6 +238,36 @@ func GetApiLevelsJson(ctx PathContext) WritablePath {
|
|||
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")
|
||||
|
||||
func getApiLevelsMap(config Config) map[string]int {
|
||||
|
|
|
@ -642,8 +642,34 @@ func (c *config) PlatformBaseOS() string {
|
|||
return String(c.productVariables.Platform_base_os)
|
||||
}
|
||||
|
||||
func (c *config) MinSupportedSdkVersion() int {
|
||||
return 16
|
||||
func (c *config) MinSupportedSdkVersion() ApiLevel {
|
||||
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 {
|
||||
|
|
|
@ -18,7 +18,6 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
|
@ -31,7 +30,7 @@ func init() {
|
|||
}
|
||||
|
||||
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: [
|
||||
"androidmk.go",
|
||||
"api_level.go",
|
||||
"builder.go",
|
||||
"cc.go",
|
||||
"ccdeps.go",
|
||||
|
|
|
@ -451,7 +451,7 @@ func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *
|
|||
}
|
||||
|
||||
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.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 {
|
||||
if c.linker != nil {
|
||||
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()))
|
||||
|
@ -1682,11 +1682,13 @@ func (c *Module) begin(ctx BaseModuleContext) {
|
|||
feature.begin(ctx)
|
||||
}
|
||||
if ctx.useSdk() && c.IsSdkVariant() {
|
||||
version, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch())
|
||||
version, err := nativeApiLevelFromUser(ctx, ctx.sdkVersion())
|
||||
if err != nil {
|
||||
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()
|
||||
}
|
||||
|
||||
func getCurrentNdkPrebuiltVersion(ctx DepsContext) string {
|
||||
if ctx.Config().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt {
|
||||
return strconv.Itoa(config.NdkMaxPrebuiltVersionInt)
|
||||
}
|
||||
return ctx.Config().PlatformSdkVersion()
|
||||
}
|
||||
|
||||
func kytheExtractAllFactory() android.Singleton {
|
||||
return &kytheExtractAllSingleton{}
|
||||
}
|
||||
|
|
|
@ -126,8 +126,6 @@ var (
|
|||
ExperimentalCStdVersion = "gnu11"
|
||||
ExperimentalCppStdVersion = "gnu++2a"
|
||||
|
||||
NdkMaxPrebuiltVersionInt = 27
|
||||
|
||||
// prebuilts/clang default settings.
|
||||
ClangDefaultBase = "prebuilts/clang/host"
|
||||
ClangDefaultVersion = "clang-r383902b"
|
||||
|
|
|
@ -16,7 +16,6 @@ package cc
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
|
@ -52,6 +51,10 @@ var (
|
|||
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.
|
||||
//
|
||||
// Example:
|
||||
|
@ -77,9 +80,7 @@ type libraryProperties struct {
|
|||
// https://github.com/android-ndk/ndk/issues/265.
|
||||
Unversioned_until *string
|
||||
|
||||
// Private property for use by the mutator that splits per-API level. Can be
|
||||
// one of <number:sdk_version> or <codename> or "current" passed to
|
||||
// "ndkstubgen.py" as it is
|
||||
// Use via apiLevel on the stubDecorator.
|
||||
ApiLevel string `blueprint:"mutated"`
|
||||
|
||||
// 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
|
||||
parsedCoverageXmlPath android.ModuleOutPath
|
||||
installPath android.Path
|
||||
|
||||
apiLevel android.ApiLevel
|
||||
firstVersion android.ApiLevel
|
||||
unversionedUntil android.ApiLevel
|
||||
}
|
||||
|
||||
// OMG GO
|
||||
func intMax(a int, b int) int {
|
||||
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 shouldUseVersionScript(ctx BaseModuleContext, stub *stubDecorator) bool {
|
||||
return stub.apiLevel.GreaterThanOrEqualTo(stub.unversionedUntil)
|
||||
}
|
||||
|
||||
func generatePerApiVariants(ctx android.BottomUpMutatorContext, m *Module,
|
||||
propName string, propValue string, perSplit func(*Module, string)) {
|
||||
platformVersion := ctx.Config().PlatformSdkVersionInt()
|
||||
from android.ApiLevel, perSplit func(*Module, android.ApiLevel)) {
|
||||
|
||||
firstSupportedVersion, err := normalizeNdkApiLevel(ctx, propValue,
|
||||
ctx.Arch())
|
||||
if err != nil {
|
||||
ctx.PropertyErrorf(propName, err.Error())
|
||||
var versions []android.ApiLevel
|
||||
versionStrs := []string{}
|
||||
for _, version := range ctx.Config().AllSupportedApiLevels() {
|
||||
if version.GreaterThanOrEqualTo(from) {
|
||||
versions = append(versions, version)
|
||||
versionStrs = append(versionStrs, version.String())
|
||||
}
|
||||
}
|
||||
|
||||
firstGenVersion, err := getFirstGeneratedVersion(firstSupportedVersion,
|
||||
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")
|
||||
versions = append(versions, android.CurrentApiLevel)
|
||||
versionStrs = append(versionStrs, android.CurrentApiLevel.String())
|
||||
|
||||
modules := ctx.CreateVariations(versionStrs...)
|
||||
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()
|
||||
return
|
||||
}
|
||||
generatePerApiVariants(ctx, m, "first_version",
|
||||
String(compiler.properties.First_version),
|
||||
func(m *Module, version string) {
|
||||
firstVersion, err := nativeApiLevelFromUser(ctx,
|
||||
String(compiler.properties.First_version))
|
||||
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 =
|
||||
version
|
||||
version.String()
|
||||
})
|
||||
} else if m.SplitPerApiLevel() && m.IsSdkVariant() {
|
||||
if ctx.Os() != android.Android {
|
||||
return
|
||||
}
|
||||
generatePerApiVariants(ctx, m, "min_sdk_version",
|
||||
m.MinSdkVersion(), func(m *Module, version string) {
|
||||
m.Properties.Sdk_version = &version
|
||||
from, err := nativeApiLevelFromUser(ctx, m.MinSdkVersion())
|
||||
if err != nil {
|
||||
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) {
|
||||
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")
|
||||
}
|
||||
|
||||
if !c.initializeProperties(ctx) {
|
||||
// Emits its own errors, so we don't need to.
|
||||
return Objects{}
|
||||
}
|
||||
|
||||
symbolFile := String(c.properties.Symbol_file)
|
||||
objs, versionScript := compileStubLibrary(ctx, flags, symbolFile,
|
||||
c.properties.ApiLevel, "")
|
||||
c.apiLevel.String(), "")
|
||||
c.versionScriptPath = versionScript
|
||||
if c.properties.ApiLevel == "current" && ctx.PrimaryArch() {
|
||||
if c.apiLevel.IsCurrent() && ctx.PrimaryArch() {
|
||||
c.parsedCoverageXmlPath = parseSymbolFileForCoverage(ctx, symbolFile)
|
||||
}
|
||||
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,
|
||||
objs Objects) android.Path {
|
||||
|
||||
useVersionScript, err := shouldUseVersionScript(ctx, stub)
|
||||
if err != nil {
|
||||
ctx.ModuleErrorf(err.Error())
|
||||
}
|
||||
|
||||
if useVersionScript {
|
||||
if shouldUseVersionScript(ctx, stub) {
|
||||
linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
|
||||
flags.Local.LdFlags = append(flags.Local.LdFlags, linkerScriptFlag)
|
||||
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) {
|
||||
arch := ctx.Target().Arch.ArchType.Name
|
||||
apiLevel := stub.properties.ApiLevel
|
||||
|
||||
// arm64 isn't actually a multilib toolchain, so unlike the other LP64
|
||||
// architectures it's just installed to lib.
|
||||
libDir := "lib"
|
||||
|
@ -396,7 +334,7 @@ func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
20
cc/stl.go
20
cc/stl.go
|
@ -17,7 +17,6 @@ package cc
|
|||
import (
|
||||
"android/soong/android"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func getNdkStlFamily(m LinkableInterface) string {
|
||||
|
@ -136,23 +135,8 @@ func (stl *stl) begin(ctx BaseModuleContext) {
|
|||
}
|
||||
|
||||
func needsLibAndroidSupport(ctx BaseModuleContext) bool {
|
||||
versionStr, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch())
|
||||
if err != nil {
|
||||
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
|
||||
version := nativeApiLevelOrPanic(ctx, ctx.sdkVersion())
|
||||
return version.LessThan(android.FirstNonLibAndroidSupportVersion)
|
||||
}
|
||||
|
||||
func staticUnwinder(ctx android.BaseModuleContext) string {
|
||||
|
|
Loading…
Reference in a new issue