diff --git a/android/api_levels.go b/android/api_levels.go index a51911787..64d3d5d95 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -16,6 +16,7 @@ package android import ( "encoding/json" + "strconv" ) func init() { @@ -50,26 +51,46 @@ func GetApiLevelsJson(ctx PathContext) WritablePath { return PathForOutput(ctx, "api_levels.json") } -func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) { - baseApiLevel := 9000 - 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, - } - for i, codename := range ctx.Config().PlatformVersionCombinedCodenames() { - apiLevelsMap[codename] = baseApiLevel + i - } +func getApiLevelsMap(config Config) map[string]int { + return config.Once("ApiLevelsMap", func() interface{} { + baseApiLevel := 9000 + 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, + } + for i, codename := range config.PlatformVersionCombinedCodenames() { + apiLevelsMap[codename] = baseApiLevel + i + } + return apiLevelsMap + }).(map[string]int) +} + +// Converts an API level string into its numeric form. +// * Codenames are decoded. +// * Numeric API levels are simply converted. +// * "minimum" and "current" are not currently handled since the former is +// NDK specific and the latter has inconsistent meaning. +func ApiStrToNum(ctx BaseContext, apiLevel string) (int, error) { + num, ok := getApiLevelsMap(ctx.Config())[apiLevel] + if ok { + return num, nil + } + return strconv.Atoi(apiLevel) +} + +func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) { + apiLevelsMap := getApiLevelsMap(ctx.Config()) apiLevelsJson := GetApiLevelsJson(ctx) createApiLevelsJson(ctx, apiLevelsJson, apiLevelsMap) } diff --git a/cc/ndk_library.go b/cc/ndk_library.go index 5a76666ee..db9632575 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -156,11 +156,11 @@ func getFirstGeneratedVersion(firstSupportedVersion string, platformVersion int) return strconv.Atoi(firstSupportedVersion) } -func shouldUseVersionScript(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 - } +func shouldUseVersionScript(ctx android.BaseContext, stub *stubDecorator) (bool, error) { + // https://github.com/android-ndk/ndk/issues/622 + // The loader spews warnings to stderr on L-MR1 when loading a library that + // has symbol versioning. + firstVersionSupportingRelease := 23 if String(stub.properties.Unversioned_until) == "current" { if stub.properties.ApiLevel == "current" { @@ -174,16 +174,31 @@ func shouldUseVersionScript(stub *stubDecorator) (bool, error) { return true, nil } - unversionedUntil, err := strconv.Atoi(String(stub.properties.Unversioned_until)) + version, err := android.ApiStrToNum(ctx, stub.properties.ApiLevel) if err != nil { return true, err } - version, err := strconv.Atoi(stub.properties.ApiLevel) + // unversioned_until is normally empty, in which case we use the version + // script as long as we are on a supported API level. + if String(stub.properties.Unversioned_until) == "" { + return version >= firstVersionSupportingRelease, nil + } + + unversionedUntil, err := android.ApiStrToNum(ctx, String(stub.properties.Unversioned_until)) if err != nil { return true, err } + if unversionedUntil < firstVersionSupportingRelease { + return true, fmt.Errorf("unversioned_until must be at least %d", + firstVersionSupportingRelease) + } + + if version < firstVersionSupportingRelease { + return false, nil + } + return version >= unversionedUntil, nil } @@ -318,7 +333,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(stub) + useVersionScript, err := shouldUseVersionScript(ctx, stub) if err != nil { ctx.ModuleErrorf(err.Error()) }