diff options
59 files changed, 1395 insertions, 768 deletions
diff --git a/android/androidmk.go b/android/androidmk.go index fafbfd61e..e90e5f0e0 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -304,15 +304,16 @@ func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod bluep host := false switch amod.Os().Class { case Host: - // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common. - if amod.Arch().ArchType != Common { - a.SetString("LOCAL_MODULE_HOST_ARCH", archStr) - } - host = true - case HostCross: - // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common. - if amod.Arch().ArchType != Common { - a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr) + if amod.Target().HostCross { + // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common. + if amod.Arch().ArchType != Common { + a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr) + } + } else { + // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common. + if amod.Arch().ArchType != Common { + a.SetString("LOCAL_MODULE_HOST_ARCH", archStr) + } } host = true case Device: @@ -359,9 +360,11 @@ func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod bluep if amod.ArchSpecific() { switch amod.Os().Class { case Host: - prefix = "HOST_" - case HostCross: - prefix = "HOST_CROSS_" + if amod.Target().HostCross { + prefix = "HOST_CROSS_" + } else { + prefix = "HOST_" + } case Device: prefix = "TARGET_" @@ -563,9 +566,11 @@ func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Mod if amod.ArchSpecific() { switch amod.Os().Class { case Host: - prefix = "HOST_" - case HostCross: - prefix = "HOST_CROSS_" + if amod.Target().HostCross { + prefix = "HOST_CROSS_" + } else { + prefix = "HOST_" + } case Device: prefix = "TARGET_" diff --git a/android/apex.go b/android/apex.go index f857ec692..7ae46d4be 100644 --- a/android/apex.go +++ b/android/apex.go @@ -24,29 +24,36 @@ import ( "github.com/google/blueprint" ) -const ( - SdkVersion_Android10 = 29 +var ( + SdkVersion_Android10 = uncheckedFinalApiLevel(29) ) type ApexInfo struct { // Name of the apex variation that this module is mutated into ApexVariationName string - MinSdkVersion int - Updatable bool - RequiredSdks SdkRefs + // Serialized ApiLevel. Use via MinSdkVersion() method. Cannot be stored in + // its struct form because this is cloned into properties structs, and + // ApiLevel has private members. + MinSdkVersionStr string + Updatable bool + RequiredSdks SdkRefs InApexes []string } -func (i ApexInfo) mergedName() string { - name := "apex" + strconv.Itoa(i.MinSdkVersion) +func (i ApexInfo) mergedName(ctx EarlyModuleContext) string { + name := "apex" + strconv.Itoa(i.MinSdkVersion(ctx).FinalOrFutureInt()) for _, sdk := range i.RequiredSdks { name += "_" + sdk.Name + "_" + sdk.Version } return name } +func (this *ApexInfo) MinSdkVersion(ctx EarlyModuleContext) ApiLevel { + return ApiLevelOrPanic(ctx, this.MinSdkVersionStr) +} + // Extracted from ApexModule to make it easier to define custom subsets of the // ApexModule interface and improve code navigation within the IDE. type DepIsInSameApex interface { @@ -129,7 +136,7 @@ type ApexModule interface { // Returns the highest version which is <= maxSdkVersion. // For example, with maxSdkVersion is 10 and versionList is [9,11] // it returns 9 as string - ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) + ChooseSdkVersion(ctx BaseModuleContext, versionList []string, maxSdkVersion ApiLevel) (string, error) // Tests if the module comes from an updatable APEX. Updatable() bool @@ -141,7 +148,7 @@ type ApexModule interface { // Returns nil if this module supports sdkVersion // Otherwise, returns error with reason - ShouldSupportSdkVersion(ctx BaseModuleContext, sdkVersion int) error + ShouldSupportSdkVersion(ctx BaseModuleContext, sdkVersion ApiLevel) error // Returns true if this module needs a unique variation per apex, for example if // use_apex_name_macro is set. @@ -313,14 +320,18 @@ func (m *ApexModuleBase) DepIsInSameApex(ctx BaseModuleContext, dep Module) bool return true } -func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) { +func (m *ApexModuleBase) ChooseSdkVersion(ctx BaseModuleContext, versionList []string, maxSdkVersion ApiLevel) (string, error) { for i := range versionList { - ver, _ := strconv.Atoi(versionList[len(versionList)-i-1]) - if ver <= maxSdkVersion { - return versionList[len(versionList)-i-1], nil + version := versionList[len(versionList)-i-1] + ver, err := ApiLevelFromUser(ctx, version) + if err != nil { + return "", err + } + if ver.LessThanOrEqualTo(maxSdkVersion) { + return version, nil } } - return "", fmt.Errorf("not found a version(<=%d) in versionList: %v", maxSdkVersion, versionList) + return "", fmt.Errorf("not found a version(<=%s) in versionList: %v", maxSdkVersion, versionList) } func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) { @@ -347,18 +358,18 @@ func (a byApexName) Less(i, j int) bool { return a[i].ApexVariationName < a[j].A // mergeApexVariations deduplicates APEX variations that would build identically into a common // variation. It returns the reduced list of variations and a list of aliases from the original // variation names to the new variation names. -func mergeApexVariations(apexVariations []ApexInfo) (merged []ApexInfo, aliases [][2]string) { +func mergeApexVariations(ctx EarlyModuleContext, apexVariations []ApexInfo) (merged []ApexInfo, aliases [][2]string) { sort.Sort(byApexName(apexVariations)) seen := make(map[string]int) for _, apexInfo := range apexVariations { apexName := apexInfo.ApexVariationName - mergedName := apexInfo.mergedName() + mergedName := apexInfo.mergedName(ctx) if index, exists := seen[mergedName]; exists { merged[index].InApexes = append(merged[index].InApexes, apexName) merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable } else { seen[mergedName] = len(merged) - apexInfo.ApexVariationName = apexInfo.mergedName() + apexInfo.ApexVariationName = apexInfo.mergedName(ctx) apexInfo.InApexes = CopyOf(apexInfo.InApexes) merged = append(merged, apexInfo) } @@ -374,7 +385,7 @@ func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Mod var apexVariations []ApexInfo var aliases [][2]string if !mctx.Module().(ApexModule).UniqueApexVariations() && !m.ApexProperties.UniqueApexVariationsForDeps { - apexVariations, aliases = mergeApexVariations(m.apexVariations) + apexVariations, aliases = mergeApexVariations(mctx, m.apexVariations) } else { apexVariations = m.apexVariations } @@ -603,7 +614,13 @@ func (d *ApexBundleDepsInfo) BuildDepsInfoLists(ctx ModuleContext, minSdkVersion } // TODO(b/158059172): remove minSdkVersion allowlist -var minSdkVersionAllowlist = map[string]int{ +var minSdkVersionAllowlist = func(apiMap map[string]int) map[string]ApiLevel { + list := make(map[string]ApiLevel, len(apiMap)) + for name, finalApiInt := range apiMap { + list[name] = uncheckedFinalApiLevel(finalApiInt) + } + return list +}(map[string]int{ "adbd": 30, "android.net.ipsec.ike": 30, "androidx-constraintlayout_constraintlayout-solver": 30, @@ -672,7 +689,7 @@ var minSdkVersionAllowlist = map[string]int{ "statsd": 30, "tensorflow_headers": 30, "xz-java": 29, -} +}) // Function called while walking an APEX's payload dependencies. // @@ -686,7 +703,7 @@ type UpdatableModule interface { } // CheckMinSdkVersion checks if every dependency of an updatable module sets min_sdk_version accordingly -func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion int) { +func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion ApiLevel) { // do not enforce min_sdk_version for host if ctx.Host() { return @@ -699,7 +716,7 @@ func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion int) // do not enforce deps.min_sdk_version if APEX/APK doesn't set min_sdk_version or // min_sdk_version is not finalized (e.g. current or codenames) - if minSdkVersion == FutureApiLevel { + if minSdkVersion.IsCurrent() { return } @@ -714,7 +731,7 @@ func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion int) } if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil { toName := ctx.OtherModuleName(to) - if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver > minSdkVersion { + if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver.GreaterThan(minSdkVersion) { ctx.OtherModuleErrorf(to, "should support min_sdk_version(%v) for %q: %v. Dependency path: %s", minSdkVersion, ctx.ModuleName(), err.Error(), ctx.GetPathString(false)) return false diff --git a/android/api_levels.go b/android/api_levels.go index ddcdbb7e4..97683404e 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -49,6 +49,14 @@ type ApiLevel struct { isPreview bool } +func (this ApiLevel) FinalOrFutureInt() int { + if this.IsPreview() { + return FutureApiLevelInt + } else { + return this.number + } +} + // 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". @@ -119,13 +127,6 @@ func uncheckedFinalApiLevel(num int) ApiLevel { } } -// 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. @@ -180,7 +181,7 @@ func ApiLevelFromUser(ctx EarlyModuleContext, raw string) (ApiLevel, error) { } if raw == "current" { - return CurrentApiLevel, nil + return FutureApiLevel, nil } for _, preview := range ctx.Config().PreviewApiLevels() { @@ -261,8 +262,19 @@ func getFinalCodenamesMap(config Config) map[string]int { "R": 30, } + // TODO: Differentiate "current" and "future". + // The code base calls it FutureApiLevel, but the spelling is "current", + // and these are really two different things. When defining APIs it + // means the API has not yet been added to a specific release. When + // choosing an API level to build for it means that the future API level + // should be used, except in the case where the build is finalized in + // which case the platform version should be used. This is *weird*, + // because in the circumstance where API foo was added in R and bar was + // added in S, both of these are usable when building for "current" when + // neither R nor S are final, but the S APIs stop being available in a + // final R build. if Bool(config.productVariables.Platform_sdk_final) { - apiLevelsMap["current"] = config.PlatformSdkVersionInt() + apiLevelsMap["current"] = config.PlatformSdkVersion().FinalOrFutureInt() } return apiLevelsMap @@ -300,24 +312,6 @@ func getApiLevelsMap(config Config) map[string]int { }).(map[string]int) } -// Converts an API level string into its numeric form. -// * Codenames are decoded. -// * Numeric API levels are simply converted. -// * "current" is mapped to FutureApiLevel(10000) -// * "minimum" is NDK specific and not handled with this. (refer normalizeNdkApiLevel in cc.go) -func ApiStrToNum(ctx BaseModuleContext, apiLevel string) (int, error) { - if apiLevel == "current" { - return FutureApiLevel, nil - } - if num, ok := getApiLevelsMap(ctx.Config())[apiLevel]; ok { - return num, nil - } - if num, err := strconv.Atoi(apiLevel); err == nil { - return num, nil - } - return 0, fmt.Errorf("SDK version should be one of \"current\", <number> or <codename>: %q", apiLevel) -} - func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) { apiLevelsMap := getApiLevelsMap(ctx.Config()) apiLevelsJson := GetApiLevelsJson(ctx) diff --git a/android/arch.go b/android/arch.go index 414113893..f4b0d66d9 100644 --- a/android/arch.go +++ b/android/arch.go @@ -78,13 +78,22 @@ module { }, target: { android: { - // Device variants + // Device variants (implies Bionic) }, host: { // Host variants }, + bionic: { + // Bionic (device and host) variants + }, + linux_bionic: { + // Bionic host variants + }, + linux: { + // Bionic (device and host) and Linux glibc variants + }, linux_glibc: { - // Linux host variants + // Linux host variants (using non-Bionic libc) }, darwin: { // Darwin host variants @@ -95,6 +104,9 @@ module { not_windows: { // Non-windows host variants }, + android_arm: { + // Any <os>_<arch> combination restricts to that os and arch + }, }, } */ @@ -578,7 +590,7 @@ var ( Linux = NewOsType("linux_glibc", Host, false) Darwin = NewOsType("darwin", Host, false) LinuxBionic = NewOsType("linux_bionic", Host, false) - Windows = NewOsType("windows", HostCross, true) + Windows = NewOsType("windows", Host, true) Android = NewOsType("android", Device, false) Fuchsia = NewOsType("fuchsia", Device, false) @@ -609,7 +621,6 @@ const ( Generic OsClass = iota Device Host - HostCross ) func (class OsClass) String() string { @@ -620,8 +631,6 @@ func (class OsClass) String() string { return "device" case Host: return "host" - case HostCross: - return "host cross" default: panic(fmt.Errorf("unknown class %d", class)) } @@ -681,6 +690,11 @@ type Target struct { NativeBridge NativeBridgeSupport NativeBridgeHostArchName string NativeBridgeRelativePath string + + // HostCross is true when the target cannot run natively on the current build host. + // For example, linux_glibc_x86 returns true on a regular x86/i686/Linux machines, but returns false + // on Mac (different OS), or on 64-bit only i686/Linux machines (unsupported arch). + HostCross bool } func (target Target) String() string { @@ -739,26 +753,15 @@ func osMutator(bpctx blueprint.BottomUpMutatorContext) { return } - osClasses := base.OsClassSupported() - var moduleOSList []OsType for _, os := range OsTypeList { - supportedClass := false - for _, osClass := range osClasses { - if os.Class == osClass { - supportedClass = true + for _, t := range mctx.Config().Targets[os] { + if base.supportsTarget(t, mctx.Config()) { + moduleOSList = append(moduleOSList, os) + break } } - if !supportedClass { - continue - } - - if len(mctx.Config().Targets[os]) == 0 { - continue - } - - moduleOSList = append(moduleOSList, os) } if len(moduleOSList) == 0 { @@ -913,7 +916,7 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) { prefer32 := false if base.prefer32 != nil { - prefer32 = base.prefer32(mctx, base, os.Class) + prefer32 = base.prefer32(mctx, base, os) } multilib, extraMultilib := decodeMultilib(base, os.Class) @@ -964,7 +967,7 @@ func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib st switch class { case Device: multilib = String(base.commonProperties.Target.Android.Compile_multilib) - case Host, HostCross: + case Host: multilib = String(base.commonProperties.Target.Host.Compile_multilib) } if multilib == "" { @@ -1240,7 +1243,7 @@ func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) { // key: value, // }, // }, - if os.Class == Host || os.Class == HostCross { + if os.Class == Host { field := "Host" prefix := "target.host" m.appendProperties(ctx, genProps, targetProp, field, prefix) @@ -1280,7 +1283,7 @@ func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) { prefix := "target." + os.Name m.appendProperties(ctx, genProps, targetProp, field, prefix) - if (os.Class == Host || os.Class == HostCross) && os != Windows { + if os.Class == Host && os != Windows { field := "Not_windows" prefix := "target.not_windows" m.appendProperties(ctx, genProps, targetProp, field, prefix) @@ -1508,6 +1511,36 @@ func decodeTargetProductVariables(config *config) (map[OsType][]Target, error) { nativeBridgeRelativePathStr = arch.ArchType.String() } + // A target is considered as HostCross if it's a host target which can't run natively on + // the currently configured build machine (either because the OS is different or because of + // the unsupported arch) + hostCross := false + if os.Class == Host { + var osSupported bool + if os == BuildOs { + osSupported = true + } else if BuildOs.Linux() && os.Linux() { + // LinuxBionic and Linux are compatible + osSupported = true + } else { + osSupported = false + } + + var archSupported bool + if arch.ArchType == Common { + archSupported = true + } else if arch.ArchType.Name == *variables.HostArch { + archSupported = true + } else if variables.HostSecondaryArch != nil && arch.ArchType.Name == *variables.HostSecondaryArch { + archSupported = true + } else { + archSupported = false + } + if !osSupported || !archSupported { + hostCross = true + } + } + targets[os] = append(targets[os], Target{ Os: os, @@ -1515,6 +1548,7 @@ func decodeTargetProductVariables(config *config) (map[OsType][]Target, error) { NativeBridge: nativeBridgeEnabled, NativeBridgeHostArchName: nativeBridgeHostArchNameStr, NativeBridgeRelativePath: nativeBridgeRelativePathStr, + HostCross: hostCross, }) } @@ -1531,6 +1565,9 @@ func decodeTargetProductVariables(config *config) (map[OsType][]Target, error) { if Bool(config.Host_bionic) { addTarget(LinuxBionic, "x86_64", nil, nil, nil, NativeBridgeDisabled, nil, nil) } + if Bool(config.Host_bionic_arm64) { + addTarget(LinuxBionic, "arm64", nil, nil, nil, NativeBridgeDisabled, nil, nil) + } if String(variables.CrossHost) != "" { crossHostOs := osByName(*variables.CrossHost) @@ -1771,13 +1808,22 @@ func getCommonTargets(targets []Target) []Target { } func firstTarget(targets []Target, filters ...string) []Target { + // find the first target from each OS + var ret []Target + hasHost := false + set := make(map[OsType]bool) + for _, filter := range filters { buildTargets := filterMultilibTargets(targets, filter) - if len(buildTargets) > 0 { - return buildTargets[:1] + for _, t := range buildTargets { + if _, found := set[t.Os]; !found { + hasHost = hasHost || (t.Os.Class == Host) + set[t.Os] = true + ret = append(ret, t) + } } } - return nil + return ret } // Use the module multilib setting to select one or more targets from a target list diff --git a/android/config.go b/android/config.go index 1c06e8c55..8df65f720 100644 --- a/android/config.go +++ b/android/config.go @@ -21,7 +21,6 @@ import ( "os" "path/filepath" "runtime" - "strconv" "strings" "sync" @@ -37,7 +36,13 @@ var Bool = proptools.Bool var String = proptools.String var StringDefault = proptools.StringDefault -const FutureApiLevel = 10000 +const FutureApiLevelInt = 10000 + +var FutureApiLevel = ApiLevel{ + value: "current", + number: FutureApiLevelInt, + isPreview: true, +} // The configuration file name const configFileName = "soong.config" @@ -46,8 +51,9 @@ const productVariablesFileName = "soong.variables" // A FileConfigurableOptions contains options which can be configured by the // config file. These will be included in the config struct. type FileConfigurableOptions struct { - Mega_device *bool `json:",omitempty"` - Host_bionic *bool `json:",omitempty"` + Mega_device *bool `json:",omitempty"` + Host_bionic *bool `json:",omitempty"` + Host_bionic_arm64 *bool `json:",omitempty"` } func (f *FileConfigurableOptions) SetDefaultConfig() { @@ -222,15 +228,17 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string config := &config{ productVariables: productVariables{ - DeviceName: stringPtr("test_device"), - Platform_sdk_version: intPtr(30), - DeviceSystemSdkVersions: []string{"14", "15"}, - Platform_systemsdk_versions: []string{"29", "30"}, - AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}, - AAPTPreferredConfig: stringPtr("xhdpi"), - AAPTCharacteristics: stringPtr("nosdcard"), - AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"}, - UncompressPrivAppDex: boolPtr(true), + DeviceName: stringPtr("test_device"), + Platform_sdk_version: intPtr(30), + Platform_sdk_codename: stringPtr("S"), + Platform_version_active_codenames: []string{"S"}, + DeviceSystemSdkVersions: []string{"14", "15"}, + Platform_systemsdk_versions: []string{"29", "30"}, + AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}, + AAPTPreferredConfig: stringPtr("xhdpi"), + AAPTCharacteristics: stringPtr("nosdcard"), + AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"}, + UncompressPrivAppDex: boolPtr(true), }, buildDir: buildDir, @@ -260,10 +268,10 @@ func TestArchConfigNativeBridge(buildDir string, env map[string]string, bp strin config := testConfig.config config.Targets[Android] = []Target{ - {Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", ""}, - {Android, Arch{ArchType: X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", ""}, - {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled, "x86_64", "arm64"}, - {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled, "x86", "arm"}, + {Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false}, + {Android, Arch{ArchType: X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false}, + {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled, "x86_64", "arm64", false}, + {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled, "x86", "arm", false}, } return testConfig @@ -275,10 +283,10 @@ func TestArchConfigFuchsia(buildDir string, env map[string]string, bp string, fs config.Targets = map[OsType][]Target{ Fuchsia: []Target{ - {Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", ""}, + {Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false}, }, BuildOs: []Target{ - {BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", ""}, + {BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false}, }, } @@ -292,12 +300,12 @@ func TestArchConfig(buildDir string, env map[string]string, bp string, fs map[st config.Targets = map[OsType][]Target{ Android: []Target{ - {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", ""}, - {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", ""}, + {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false}, + {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false}, }, BuildOs: []Target{ - {BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", ""}, - {BuildOs, Arch{ArchType: X86}, NativeBridgeDisabled, "", ""}, + {BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false}, + {BuildOs, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false}, }, } @@ -614,12 +622,8 @@ func (c *config) PlatformVersionName() string { return String(c.productVariables.Platform_version_name) } -func (c *config) PlatformSdkVersionInt() int { - return *c.productVariables.Platform_sdk_version -} - -func (c *config) PlatformSdkVersion() string { - return strconv.Itoa(c.PlatformSdkVersionInt()) +func (c *config) PlatformSdkVersion() ApiLevel { + return uncheckedFinalApiLevel(*c.productVariables.Platform_sdk_version) } func (c *config) PlatformSdkCodename() string { @@ -648,7 +652,7 @@ func (c *config) MinSupportedSdkVersion() ApiLevel { func (c *config) FinalApiLevels() []ApiLevel { var levels []ApiLevel - for i := 1; i <= c.PlatformSdkVersionInt(); i++ { + for i := 1; i <= c.PlatformSdkVersion().FinalOrFutureInt(); i++ { levels = append(levels, uncheckedFinalApiLevel(i)) } return levels @@ -672,19 +676,18 @@ func (c *config) AllSupportedApiLevels() []ApiLevel { return append(levels, c.PreviewApiLevels()...) } -func (c *config) DefaultAppTargetSdkInt() int { - if Bool(c.productVariables.Platform_sdk_final) { - return c.PlatformSdkVersionInt() - } else { - return FutureApiLevel - } -} - -func (c *config) DefaultAppTargetSdk() string { +func (c *config) DefaultAppTargetSdk(ctx EarlyModuleContext) ApiLevel { if Bool(c.productVariables.Platform_sdk_final) { return c.PlatformSdkVersion() } else { - return c.PlatformSdkCodename() + codename := c.PlatformSdkCodename() + if codename == "" { + return NoneApiLevel + } + if codename == "REL" { + panic("Platform_sdk_codename should not be REL when Platform_sdk_final is true") + } + return ApiLevelOrPanic(ctx, codename) } } diff --git a/android/module.go b/android/module.go index d794dc2fc..c4e43c219 100644 --- a/android/module.go +++ b/android/module.go @@ -176,6 +176,31 @@ type BaseModuleContext interface { // It is intended for use inside the visit functions of Visit* and WalkDeps. OtherModuleType(m blueprint.Module) string + // OtherModuleProvider returns the value for a provider for the given module. If the value is + // not set it returns the zero value of the type of the provider, so the return value can always + // be type asserted to the type of the provider. The value returned may be a deep copy of the + // value originally passed to SetProvider. + OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{} + + // OtherModuleHasProvider returns true if the provider for the given module has been set. + OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool + + // Provider returns the value for a provider for the current module. If the value is + // not set it returns the zero value of the type of the provider, so the return value can always + // be type asserted to the type of the provider. It panics if called before the appropriate + // mutator or GenerateBuildActions pass for the provider. The value returned may be a deep + // copy of the value originally passed to SetProvider. + Provider(provider blueprint.ProviderKey) interface{} + + // HasProvider returns true if the provider for the current module has been set. + HasProvider(provider blueprint.ProviderKey) bool + + // SetProvider sets the value for a provider for the current module. It panics if not called + // during the appropriate mutator or GenerateBuildActions pass for the provider, if the value + // is not of the appropriate type, or if the value has already been set. The value should not + // be modified after being passed to SetProvider. + SetProvider(provider blueprint.ProviderKey, value interface{}) + GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module // GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if @@ -245,6 +270,24 @@ type BaseModuleContext interface { // and returns a top-down dependency path from a start module to current child module. GetWalkPath() []Module + // PrimaryModule returns the first variant of the current module. Variants of a module are always visited in + // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the + // Module returned by PrimaryModule without data races. This can be used to perform singleton actions that are + // only done once for all variants of a module. + PrimaryModule() Module + + // FinalModule returns the last variant of the current module. Variants of a module are always visited in + // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all + // variants using VisitAllModuleVariants if the current module == FinalModule(). This can be used to perform + // singleton actions that are only done once for all variants of a module. + FinalModule() Module + + // VisitAllModuleVariants calls visit for each variant of the current module. Variants of a module are always + // visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read + // from all variants if the current module == FinalModule(). Otherwise, care must be taken to not access any + // data modified by the current mutator. + VisitAllModuleVariants(visit func(Module)) + // GetTagPath is supposed to be called in visit function passed in WalkDeps() // and returns a top-down dependency tags path from a start module to current child module. // It has one less entry than GetWalkPath() as it contains the dependency tags that @@ -324,24 +367,6 @@ type ModuleContext interface { // additional dependencies. Phony(phony string, deps ...Path) - // PrimaryModule returns the first variant of the current module. Variants of a module are always visited in - // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the - // Module returned by PrimaryModule without data races. This can be used to perform singleton actions that are - // only done once for all variants of a module. - PrimaryModule() Module - - // FinalModule returns the last variant of the current module. Variants of a module are always visited in - // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all - // variants using VisitAllModuleVariants if the current module == FinalModule(). This can be used to perform - // singleton actions that are only done once for all variants of a module. - FinalModule() Module - - // VisitAllModuleVariants calls visit for each variant of the current module. Variants of a module are always - // visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read - // from all variants if the current module == FinalModule(). Otherwise, care must be taken to not access any - // data modified by the current mutator. - VisitAllModuleVariants(visit func(Module)) - // GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods, // but do not exist. GetMissingDependencies() []string @@ -600,7 +625,7 @@ type commonProperties struct { Native_bridge_supported *bool `android:"arch_variant"` // init.rc files to be installed if this module is installed - Init_rc []string `android:"path"` + Init_rc []string `android:"arch_variant,path"` // VINTF manifest fragments to be installed if this module is installed Vintf_fragments []string `android:"path"` @@ -923,7 +948,7 @@ type ModuleBase struct { initRcPaths Paths vintfFragmentsPaths Paths - prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool + prefer32 func(ctx BaseModuleContext, base *ModuleBase, os OsType) bool } func (m *ModuleBase) ComponentDepsMutator(BottomUpMutatorContext) {} @@ -950,7 +975,7 @@ func (m *ModuleBase) VariablesForTests() map[string]string { return m.variables } -func (m *ModuleBase) Prefer32(prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool) { +func (m *ModuleBase) Prefer32(prefer32 func(ctx BaseModuleContext, base *ModuleBase, os OsType) bool) { m.prefer32 = prefer32 } @@ -1046,7 +1071,7 @@ func (m *ModuleBase) Os() OsType { } func (m *ModuleBase) Host() bool { - return m.Os().Class == Host || m.Os().Class == HostCross + return m.Os().Class == Host } func (m *ModuleBase) Device() bool { @@ -1066,28 +1091,28 @@ func (m *ModuleBase) IsCommonOSVariant() bool { return m.commonProperties.CommonOSVariant } -func (m *ModuleBase) OsClassSupported() []OsClass { +func (m *ModuleBase) supportsTarget(target Target, config Config) bool { switch m.commonProperties.HostOrDeviceSupported { case HostSupported: - return []OsClass{Host, HostCross} + return target.Os.Class == Host case HostSupportedNoCross: - return []OsClass{Host} + return target.Os.Class == Host && !target.HostCross case DeviceSupported: - return []OsClass{Device} + return target.Os.Class == Device case HostAndDeviceSupported, HostAndDeviceDefault: - var supported []OsClass + supported := false if Bool(m.hostAndDeviceProperties.Host_supported) || (m.commonProperties.HostOrDeviceSupported == HostAndDeviceDefault && m.hostAndDeviceProperties.Host_supported == nil) { - supported = append(supported, Host, HostCross) + supported = supported || target.Os.Class == Host } if m.hostAndDeviceProperties.Device_supported == nil || *m.hostAndDeviceProperties.Device_supported { - supported = append(supported, Device) + supported = supported || target.Os.Class == Device } return supported default: - return nil + return false } } @@ -1681,6 +1706,21 @@ func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name strin func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string { return b.bp.OtherModuleType(m) } +func (b *baseModuleContext) OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{} { + return b.bp.OtherModuleProvider(m, provider) +} +func (b *baseModuleContext) OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool { + return b.bp.OtherModuleHasProvider(m, provider) +} +func (b *baseModuleContext) Provider(provider blueprint.ProviderKey) interface{} { + return b.bp.Provider(provider) +} +func (b *baseModuleContext) HasProvider(provider blueprint.ProviderKey) bool { + return b.bp.HasProvider(provider) +} +func (b *baseModuleContext) SetProvider(provider blueprint.ProviderKey, value interface{}) { + b.bp.SetProvider(provider, value) +} func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module { return b.bp.GetDirectDepWithTag(name, tag) @@ -2001,6 +2041,20 @@ func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag { return b.tagPath } +func (b *baseModuleContext) VisitAllModuleVariants(visit func(Module)) { + b.bp.VisitAllModuleVariants(func(module blueprint.Module) { + visit(module.(Module)) + }) +} + +func (b *baseModuleContext) PrimaryModule() Module { + return b.bp.PrimaryModule().(Module) +} + +func (b *baseModuleContext) FinalModule() Module { + return b.bp.FinalModule().(Module) +} + // A regexp for removing boilerplate from BaseDependencyTag from the string representation of // a dependency tag. var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`) @@ -2036,20 +2090,6 @@ func (b *baseModuleContext) GetPathString(skipFirst bool) string { return sb.String() } -func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) { - m.bp.VisitAllModuleVariants(func(module blueprint.Module) { - visit(module.(Module)) - }) -} - -func (m *moduleContext) PrimaryModule() Module { - return m.bp.PrimaryModule().(Module) -} - -func (m *moduleContext) FinalModule() Module { - return m.bp.FinalModule().(Module) -} - func (m *moduleContext) ModuleSubDir() string { return m.bp.ModuleSubDir() } @@ -2075,7 +2115,7 @@ func (b *baseModuleContext) Os() OsType { } func (b *baseModuleContext) Host() bool { - return b.os.Class == Host || b.os.Class == HostCross + return b.os.Class == Host } func (b *baseModuleContext) Device() bool { @@ -2535,30 +2575,36 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { } // Create (host|host-cross|target)-<OS> phony rules to build a reduced checkbuild. - osDeps := map[OsType]Paths{} + type osAndCross struct { + os OsType + hostCross bool + } + osDeps := map[osAndCross]Paths{} ctx.VisitAllModules(func(module Module) { if module.Enabled() { - os := module.Target().Os - osDeps[os] = append(osDeps[os], module.base().checkbuildFiles...) + key := osAndCross{os: module.Target().Os, hostCross: module.Target().HostCross} + osDeps[key] = append(osDeps[key], module.base().checkbuildFiles...) } }) osClass := make(map[string]Paths) - for os, deps := range osDeps { + for key, deps := range osDeps { var className string - switch os.Class { + switch key.os.Class { case Host: - className = "host" - case HostCross: - className = "host-cross" + if key.hostCross { + className = "host-cross" + } else { + className = "host" + } case Device: className = "target" default: continue } - name := className + "-" + os.Name + name := className + "-" + key.os.Name osClass[className] = append(osClass[className], PathForPhony(ctx, name)) ctx.Phony(name, deps...) diff --git a/android/mutator.go b/android/mutator.go index 5acd9926c..7a104772f 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -315,6 +315,14 @@ type BottomUpMutatorContext interface { // be used to add dependencies on the toVariationName variant using the fromVariationName // variant. CreateAliasVariation(fromVariationName, toVariationName string) + + // SetVariationProvider sets the value for a provider for the given newly created variant of + // the current module, i.e. one of the Modules returned by CreateVariations.. It panics if + // not called during the appropriate mutator or GenerateBuildActions pass for the provider, + // if the value is not of the appropriate type, or if the module is not a newly created + // variant of the current module. The value should not be modified after being passed to + // SetVariationProvider. + SetVariationProvider(module blueprint.Module, provider blueprint.ProviderKey, value interface{}) } type bottomUpMutatorContext struct { @@ -550,3 +558,7 @@ func (b *bottomUpMutatorContext) AliasVariation(variationName string) { func (b *bottomUpMutatorContext) CreateAliasVariation(fromVariationName, toVariationName string) { b.bp.CreateAliasVariation(fromVariationName, toVariationName) } + +func (b *bottomUpMutatorContext) SetVariationProvider(module blueprint.Module, provider blueprint.ProviderKey, value interface{}) { + b.bp.SetVariationProvider(module, provider, value) +} diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go index 6c3cd9eef..854395e64 100644 --- a/android/prebuilt_test.go +++ b/android/prebuilt_test.go @@ -285,7 +285,7 @@ func TestPrebuilts(t *testing.T) { t.Errorf("windows is assumed to be disabled by default") } config.config.Targets[Windows] = []Target{ - {Windows, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", ""}, + {Windows, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", true}, } ctx := NewTestArchContext() diff --git a/android/singleton.go b/android/singleton.go index 2c51c6c48..9832378d5 100644 --- a/android/singleton.go +++ b/android/singleton.go @@ -29,6 +29,16 @@ type SingletonContext interface { ModuleType(module blueprint.Module) string BlueprintFile(module blueprint.Module) string + // ModuleProvider returns the value, if any, for the provider for a module. If the value for the + // provider was not set it returns the zero value of the type of the provider, which means the + // return value can always be type-asserted to the type of the provider. The return value should + // always be considered read-only. It panics if called before the appropriate mutator or + // GenerateBuildActions pass for the provider on the module. + ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{} + + // ModuleHasProvider returns true if the provider for the given module has been set. + ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool + ModuleErrorf(module blueprint.Module, format string, args ...interface{}) Errorf(format string, args ...interface{}) Failed() bool diff --git a/android/variable.go b/android/variable.go index 53f081e8c..ce523ed90 100644 --- a/android/variable.go +++ b/android/variable.go @@ -365,12 +365,12 @@ func (v *productVariables) SetDefaultConfig() { *v = productVariables{ BuildNumberFile: stringPtr("build_number.txt"), - Platform_version_name: stringPtr("Q"), - Platform_sdk_version: intPtr(28), - Platform_sdk_codename: stringPtr("Q"), + Platform_version_name: stringPtr("S"), + Platform_sdk_version: intPtr(30), + Platform_sdk_codename: stringPtr("S"), Platform_sdk_final: boolPtr(false), - Platform_version_active_codenames: []string{"Q"}, - Platform_vndk_version: stringPtr("Q"), + Platform_version_active_codenames: []string{"S"}, + Platform_vndk_version: stringPtr("S"), HostArch: stringPtr("x86_64"), HostSecondaryArch: stringPtr("x86"), diff --git a/apex/androidmk.go b/apex/androidmk.go index 1b53a672b..c4fe3a36a 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -157,13 +157,14 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo host := false switch fi.module.Target().Os.Class { case android.Host: - if fi.module.Target().Arch.ArchType != android.Common { - fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr) - } - host = true - case android.HostCross: - if fi.module.Target().Arch.ArchType != android.Common { - fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr) + if fi.module.Target().HostCross { + if fi.module.Target().Arch.ArchType != android.Common { + fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr) + } + } else { + if fi.module.Target().Arch.ArchType != android.Common { + fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr) + } } host = true case android.Device: diff --git a/apex/apex.go b/apex/apex.go index 8e35e07c0..e8294a8f6 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -795,7 +795,7 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { } apexInfo := android.ApexInfo{ ApexVariationName: mctx.ModuleName(), - MinSdkVersion: a.minSdkVersion(mctx), + MinSdkVersionStr: a.minSdkVersion(mctx).String(), RequiredSdks: a.RequiredSdks(), Updatable: a.Updatable(), InApexes: []string{mctx.ModuleName()}, @@ -1952,27 +1952,21 @@ func (a *apexBundle) WalkPayloadDeps(ctx android.ModuleContext, do android.Paylo }) } -func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int { +func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) android.ApiLevel { ver := proptools.String(a.properties.Min_sdk_version) if ver == "" { return android.FutureApiLevel } - // Treat the current codenames as "current", which means future API version (10000) - // Otherwise, ApiStrToNum converts codename(non-finalized) to a value from [9000...] - // and would fail to build against "current". - if android.InList(ver, ctx.Config().PlatformVersionActiveCodenames()) { - return android.FutureApiLevel - } - // In "REL" branch, "current" is mapped to finalized sdk version - if ctx.Config().PlatformSdkCodename() == "REL" && ver == "current" { - return ctx.Config().PlatformSdkVersionInt() - } - // Finalized codenames are OKAY and will be converted to int - intVer, err := android.ApiStrToNum(ctx, ver) + apiLevel, err := android.ApiLevelFromUser(ctx, ver) if err != nil { ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) + return android.NoneApiLevel + } + if apiLevel.IsPreview() { + // All codenames should build against "current". + return android.FutureApiLevel } - return intVer + return apiLevel } func (a *apexBundle) Updatable() bool { @@ -2046,7 +2040,9 @@ func (a *apexBundle) checkMinSdkVersion(ctx android.ModuleContext) { if proptools.Bool(a.properties.Use_vendor) && ctx.DeviceConfig().VndkVersion() == "" { return } - android.CheckMinSdkVersion(a, ctx, a.minSdkVersion(ctx)) + // apexBundle::minSdkVersion reports its own errors. + minSdkVersion := a.minSdkVersion(ctx) + android.CheckMinSdkVersion(a, ctx, minSdkVersion) } // Ensures that a lib providing stub isn't statically linked diff --git a/apex/apex_test.go b/apex/apex_test.go index 5c49667e5..20991096c 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -207,7 +207,7 @@ func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*andr config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"} config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q") config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false) - config.TestProductVariables.Platform_version_active_codenames = []string{"R"} + config.TestProductVariables.Platform_version_active_codenames = []string{"Q"} config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER") for _, handler := range handlers { @@ -836,6 +836,105 @@ func TestApexWithStubs(t *testing.T) { }) } +func TestApexWithStubsWithMinSdkVersion(t *testing.T) { + t.Parallel() + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib", "mylib3"], + min_sdk_version: "29", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["mylib2", "mylib3"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + min_sdk_version: "28", + } + + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + cflags: ["-include mylib.h"], + system_shared_libs: [], + stl: "none", + stubs: { + versions: ["28", "29", "30", "current"], + }, + min_sdk_version: "28", + } + + cc_library { + name: "mylib3", + srcs: ["mylib.cpp"], + shared_libs: ["mylib4"], + system_shared_libs: [], + stl: "none", + stubs: { + versions: ["28", "29", "30", "current"], + }, + apex_available: [ "myapex" ], + min_sdk_version: "28", + } + + cc_library { + name: "mylib4", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + min_sdk_version: "28", + } + `) + + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + copyCmds := apexRule.Args["copy_commands"] + + // Ensure that direct non-stubs dep is always included + ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") + + // Ensure that indirect stubs dep is not included + ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so") + + // Ensure that direct stubs dep is included + ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so") + + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex29").Rule("ld").Args["libFlags"] + + // Ensure that mylib is linking with the version 29 stubs for mylib2 + ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_29/mylib2.so") + // ... and not linking to the non-stub (impl) variant of mylib2 + ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") + + // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because mylib3 is in the same apex) + ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex29/mylib3.so") + // .. and not linking to the stubs variant of mylib3 + ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_29/mylib3.so") + + // Ensure that stubs libs are built without -include flags + mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + ensureNotContains(t, mylib2Cflags, "-include ") + + // Ensure that genstub is invoked with --apex + ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_29").Rule("genStubSrc").Args["flags"]) + + ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + "lib64/mylib.so", + "lib64/mylib3.so", + "lib64/mylib4.so", + }) +} + func TestApexWithExplicitStubsDependency(t *testing.T) { ctx, _ := testApex(t, ` apex { @@ -1425,13 +1524,7 @@ func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - // 9000 is quite a magic number. - // Finalized SDK codenames are mapped as P(28), Q(29), ... - // And, codenames which are not finalized yet(active_codenames + future_codenames) are numbered from 9000, 9001, ... - // to distinguish them from finalized and future_api(10000) - // In this test, "R" is assumed not finalized yet( listed in Platform_version_active_codenames) and translated into 9000 - // (refer android/api_levels.go) - expectLink("libx", "shared_apex10000", "libz", "shared_9000") + expectLink("libx", "shared_apex10000", "libz", "shared_R") expectNoLink("libx", "shared_apex10000", "libz", "shared_29") expectNoLink("libx", "shared_apex10000", "libz", "shared") } @@ -6130,7 +6223,7 @@ func TestNonPreferredPrebuiltDependency(t *testing.T) { name: "mylib", srcs: ["mylib.cpp"], stubs: { - versions: ["10000"], + versions: ["current"], }, apex_available: ["myapex"], } @@ -6140,7 +6233,7 @@ func TestNonPreferredPrebuiltDependency(t *testing.T) { prefer: false, srcs: ["prebuilt.so"], stubs: { - versions: ["10000"], + versions: ["current"], }, apex_available: ["myapex"], } diff --git a/apex/builder.go b/apex/builder.go index c5680ad2d..b0f0c8212 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -21,7 +21,6 @@ import ( "path/filepath" "runtime" "sort" - "strconv" "strings" "android/soong/android" @@ -214,7 +213,8 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, }, }) - if a.minSdkVersion(ctx) == android.SdkVersion_Android10 { + minSdkVersion := a.minSdkVersion(ctx) + if minSdkVersion.EqualTo(android.SdkVersion_Android10) { // b/143654022 Q apexd can't understand newly added keys in apex_manifest.json // prepare stripped-down version so that APEX modules built from R+ can be installed to Q a.manifestJsonOut = android.PathForModuleOut(ctx, "apex_manifest.json") @@ -426,7 +426,8 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { var emitCommands []string imageContentFile := android.PathForModuleOut(ctx, "content.txt") emitCommands = append(emitCommands, "echo ./apex_manifest.pb >> "+imageContentFile.String()) - if a.minSdkVersion(ctx) == android.SdkVersion_Android10 { + minSdkVersion := a.minSdkVersion(ctx) + if minSdkVersion.EqualTo(android.SdkVersion_Android10) { emitCommands = append(emitCommands, "echo ./apex_manifest.json >> "+imageContentFile.String()) } for _, fi := range a.filesInfo { @@ -532,12 +533,13 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String()) } - targetSdkVersion := ctx.Config().DefaultAppTargetSdk() + targetSdkVersion := ctx.Config().DefaultAppTargetSdk(ctx).String() // TODO(b/157078772): propagate min_sdk_version to apexer. - minSdkVersion := ctx.Config().DefaultAppTargetSdk() + minSdkVersion := ctx.Config().DefaultAppTargetSdk(ctx).String() - if a.minSdkVersion(ctx) == android.SdkVersion_Android10 { - minSdkVersion = strconv.Itoa(a.minSdkVersion(ctx)) + moduleMinSdkVersion := a.minSdkVersion(ctx) + if moduleMinSdkVersion.EqualTo(android.SdkVersion_Android10) { + minSdkVersion = moduleMinSdkVersion.String() } if java.UseApiFingerprint(ctx) { @@ -566,7 +568,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { ctx.PropertyErrorf("test_only_no_hashtree", "not available") return } - if a.minSdkVersion(ctx) > android.SdkVersion_Android10 || a.testOnlyShouldSkipHashtreeGeneration() { + if moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) || a.testOnlyShouldSkipHashtreeGeneration() { // Apexes which are supposed to be installed in builtin dirs(/system, etc) // don't need hashtree for activation. Therefore, by removing hashtree from // apex bundle (filesystem image in it, to be specific), we can save storage. @@ -583,7 +585,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { optFlags = append(optFlags, "--do_not_check_keyname") } - if a.minSdkVersion(ctx) == android.SdkVersion_Android10 { + if moduleMinSdkVersion == android.SdkVersion_Android10 { implicitInputs = append(implicitInputs, a.manifestJsonOut) optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String()) } diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 37457e921..9f6c8ada9 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -326,7 +326,7 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { Args: map[string]string{ "abis": strings.Join(java.SupportedAbis(ctx), ","), "allow-prereleased": strconv.FormatBool(proptools.Bool(a.properties.Prerelease)), - "sdk-version": ctx.Config().PlatformSdkVersion(), + "sdk-version": ctx.Config().PlatformSdkVersion().String(), }, }) diff --git a/apex/vndk.go b/apex/vndk.go index 5cc0e2a43..93265c4ac 100644 --- a/apex/vndk.go +++ b/apex/vndk.go @@ -16,7 +16,6 @@ package apex import ( "path/filepath" - "strconv" "strings" "sync" @@ -124,10 +123,10 @@ func makeCompatSymlinks(name string, ctx android.ModuleContext) (symlinks []stri // Since prebuilt vndk libs still depend on system/lib/vndk path if strings.HasPrefix(name, vndkApexNamePrefix) { vndkVersion := strings.TrimPrefix(name, vndkApexNamePrefix) - if numVer, err := strconv.Atoi(vndkVersion); err != nil { + if ver, err := android.ApiLevelFromUser(ctx, vndkVersion); err != nil { ctx.ModuleErrorf("apex_vndk should be named as %v<ver:number>: %s", vndkApexNamePrefix, name) return - } else if numVer > android.SdkVersion_Android10 { + } else if ver.GreaterThan(android.SdkVersion_Android10) { return } // the name of vndk apex is formatted "com.android.vndk.v" + version diff --git a/cc/androidmk.go b/cc/androidmk.go index 5bdbac649..f0e615217 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -83,6 +83,13 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries { if len(c.Properties.Logtags) > 0 { entries.AddStrings("LOCAL_LOGTAGS_FILES", c.Properties.Logtags...) } + // Note: Pass the exact value of AndroidMkSystemSharedLibs to the Make + // world, even if it is an empty list. In the Make world, + // LOCAL_SYSTEM_SHARED_LIBRARIES defaults to "none", which is expanded + // to the default list of system shared libs by the build system. + // Soong computes the exact list of system shared libs, so we have to + // override the default value when the list of libs is actually empty. + entries.SetString("LOCAL_SYSTEM_SHARED_LIBRARIES", strings.Join(c.Properties.AndroidMkSystemSharedLibs, " ")) if len(c.Properties.AndroidMkSharedLibs) > 0 { entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...) } diff --git a/cc/builder.go b/cc/builder.go index ef653481d..81c09b1a1 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -221,7 +221,6 @@ var ( ExecStrategy: "${config.REAbiDumperExecStrategy}", Platform: map[string]string{ remoteexec.PoolKey: "${config.RECXXPool}", - "InputRootAbsolutePath": android.AbsSrcDirForExistingUseCases(), }, }, []string{"cFlags", "exportDirs"}, nil) @@ -100,6 +100,9 @@ type Deps struct { // Used for data dependencies adjacent to tests DataLibs []string + // Used by DepsMutator to pass system_shared_libs information to check_elf_file.py. + SystemSharedLibs []string + StaticUnwinderIfLegacy bool ReexportSharedLibHeaders, ReexportStaticLibHeaders, ReexportHeaderLibHeaders []string @@ -238,6 +241,9 @@ type BaseProperties struct { PreventInstall bool `blueprint:"mutated"` ApexesProvidingSharedLibs []string `blueprint:"mutated"` + // Set by DepsMutator. + AndroidMkSystemSharedLibs []string `blueprint:"mutated"` + ImageVariationPrefix string `blueprint:"mutated"` VndkVersion string `blueprint:"mutated"` SubName string `blueprint:"mutated"` @@ -354,7 +360,7 @@ type ModuleContextIntf interface { useClangLld(actx ModuleContext) bool isForPlatform() bool apexVariationName() string - apexSdkVersion() int + apexSdkVersion() android.ApiLevel hasStubsVariants() bool isStubs() bool bootstrap() bool @@ -615,7 +621,7 @@ type Module struct { kytheFiles android.Paths // For apex variants, this is set as apex.min_sdk_version - apexSdkVersion int + apexSdkVersion android.ApiLevel } func (c *Module) Toc() android.OptionalPath { @@ -950,9 +956,9 @@ func (c *Module) Init() android.Module { c.AddProperties(feature.props()...) } - c.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool { + c.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, os android.OsType) bool { // Windows builds always prefer 32-bit - return class == android.HostCross + return os == android.Windows }) android.InitAndroidArchModule(c, c.hod, c.multilib) android.InitApexModule(c) @@ -1328,7 +1334,7 @@ func (ctx *moduleContextImpl) apexVariationName() string { return ctx.mod.ApexVariationName() } -func (ctx *moduleContextImpl) apexSdkVersion() int { +func (ctx *moduleContextImpl) apexSdkVersion() android.ApiLevel { return ctx.mod.apexSdkVersion } @@ -1839,6 +1845,8 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { deps := c.deps(ctx) + c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs + variantNdkLibs := []string{} variantLateNdkLibs := []string{} if ctx.Os() == android.Android { @@ -2317,7 +2325,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // For the dependency from platform to apex, use the latest stubs c.apexSdkVersion = android.FutureApiLevel if !c.IsForPlatform() { - c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion + c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion(ctx) } if android.InList("hwaddress", ctx.Config().SanitizeDevice()) { @@ -2421,7 +2429,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if libDepTag, ok := depTag.(libraryDependencyTag); ok { // Only use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859) - if libDepTag.staticUnwinder && c.apexSdkVersion > android.SdkVersion_Android10 { + if libDepTag.staticUnwinder && c.apexSdkVersion.GreaterThan(android.SdkVersion_Android10) { return } @@ -2465,7 +2473,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // when to use (unspecified) stubs, check min_sdk_version and choose the right one if useThisDep && depIsStubs && !libDepTag.explicitlyVersioned { - versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), c.apexSdkVersion) + versionToUse, err := c.ChooseSdkVersion(ctx, ccDep.StubsVersions(), c.apexSdkVersion) if err != nil { ctx.OtherModuleErrorf(dep, err.Error()) return @@ -2488,7 +2496,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // if this is for use_vendor apex && dep has stubsVersions // apply the same rule of apex sdk enforcement to choose right version var err error - versionToUse, err = c.ChooseSdkVersion(versions, c.apexSdkVersion) + versionToUse, err = c.ChooseSdkVersion(ctx, versions, c.apexSdkVersion) if err != nil { ctx.OtherModuleErrorf(dep, err.Error()) return @@ -2559,17 +2567,20 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // in the context of proper cc.Modules. if ccWholeStaticLib, ok := ccDep.(*Module); ok { staticLib := ccWholeStaticLib.linker.(libraryInterface) - if missingDeps := staticLib.getWholeStaticMissingDeps(); missingDeps != nil { - postfix := " (required by " + ctx.OtherModuleName(dep) + ")" - for i := range missingDeps { - missingDeps[i] += postfix - } - ctx.AddMissingDependencies(missingDeps) - } - if _, ok := ccWholeStaticLib.linker.(prebuiltLinkerInterface); ok { - depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, linkFile.Path()) + if objs := staticLib.objs(); len(objs.objFiles) > 0 { + depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(objs) } else { - depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs()) + // This case normally catches prebuilt static + // libraries, but it can also occur when + // AllowMissingDependencies is on and the + // dependencies has no sources of its own + // but has a whole_static_libs dependency + // on a missing library. We want to depend + // on the .a file so that there is something + // in the dependency tree that contains the + // error rule for the missing transitive + // dependency. + depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, linkFile.Path()) } } else { ctx.ModuleErrorf( @@ -3012,21 +3023,8 @@ func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu return true } -// b/154667674: refactor this to handle "current" in a consistent way -func decodeSdkVersionString(ctx android.BaseModuleContext, versionString string) (int, error) { - if versionString == "" { - return 0, fmt.Errorf("not specified") - } - if versionString == "current" { - if ctx.Config().PlatformSdkCodename() == "REL" { - return ctx.Config().PlatformSdkVersionInt(), nil - } - return android.FutureApiLevel, nil - } - return android.ApiStrToNum(ctx, versionString) -} - -func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { +func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, + sdkVersion android.ApiLevel) error { // We ignore libclang_rt.* prebuilt libs since they declare sdk_version: 14(b/121358700) if strings.HasPrefix(ctx.OtherModuleName(c), "libclang_rt") { return nil @@ -3050,11 +3048,17 @@ func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersi // non-SDK variant resets sdk_version, which works too. minSdkVersion = c.SdkVersion() } - ver, err := decodeSdkVersionString(ctx, minSdkVersion) + if minSdkVersion == "" { + return fmt.Errorf("neither min_sdk_version nor sdk_version specificed") + } + // Not using nativeApiLevelFromUser because the context here is not + // necessarily a native context. + ver, err := android.ApiLevelFromUser(ctx, minSdkVersion) if err != nil { return err } - if ver > sdkVersion { + + if ver.GreaterThan(sdkVersion) { return fmt.Errorf("newer SDK(%v)", ver) } return nil diff --git a/cc/cc_test.go b/cc/cc_test.go index 132d09136..e0d464093 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -3780,3 +3780,46 @@ func TestProductVariableDefaults(t *testing.T) { t.Errorf("expected -DBAR in cppflags, got %q", libfoo.flags.Local.CppFlags) } } + +func TestEmptyWholeStaticLibsAllowMissingDependencies(t *testing.T) { + t.Parallel() + bp := ` + cc_library_static { + name: "libfoo", + srcs: ["foo.c"], + whole_static_libs: ["libbar"], + } + + cc_library_static { + name: "libbar", + whole_static_libs: ["libmissing"], + } + ` + + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.Allow_missing_dependencies = BoolPtr(true) + + ctx := CreateTestContext() + ctx.SetAllowMissingDependencies(true) + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Output("libbar.a") + if g, w := libbar.Rule, android.ErrorRule; g != w { + t.Fatalf("Expected libbar rule to be %q, got %q", w, g) + } + + if g, w := libbar.Args["error"], "missing dependencies: libmissing"; !strings.Contains(g, w) { + t.Errorf("Expected libbar error to contain %q, was %q", w, g) + } + + libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Output("libfoo.a") + if g, w := libfoo.Inputs.Strings(), libbar.Output.String(); !android.InList(w, g) { + t.Errorf("Expected libfoo.a to depend on %q, got %q", w, g) + } + +} diff --git a/cc/check.go b/cc/check.go index 46328e915..0058b8c06 100644 --- a/cc/check.go +++ b/cc/check.go @@ -38,6 +38,8 @@ func CheckBadCompilerFlags(ctx BaseModuleContext, prop string, flags []string) { ctx.PropertyErrorf(prop, "Illegal flag `%s`", flag) } else if flag == "--coverage" { ctx.PropertyErrorf(prop, "Bad flag: `%s`, use native_coverage instead", flag) + } else if flag == "-fwhole-program-vtables" { + ctx.PropertyErrorf(prop, "Bad flag: `%s`, use whole_program_vtables instead", flag) } else if flag == "-Weverything" { if !ctx.Config().IsEnvTrue("ANDROID_TEMPORARILY_ALLOW_WEVERYTHING") { ctx.PropertyErrorf(prop, "-Weverything is not allowed in Android.bp files. "+ diff --git a/cc/compiler.go b/cc/compiler.go index f74582004..bb5c7bf2a 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -354,7 +354,9 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_NAME__='\""+ctx.apexVariationName()+"\"'") } if ctx.Device() { - flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_SDK_VERSION__="+strconv.Itoa(ctx.apexSdkVersion())) + flags.Global.CommonFlags = append(flags.Global.CommonFlags, + fmt.Sprintf("-D__ANDROID_SDK_VERSION__=%d", + ctx.apexSdkVersion().FinalOrFutureInt())) } } @@ -390,7 +392,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps if ctx.Os().Class == android.Device { version := ctx.sdkVersion() if version == "" || version == "current" { - target += strconv.Itoa(android.FutureApiLevel) + target += strconv.Itoa(android.FutureApiLevelInt) } else { target += version } diff --git a/cc/library.go b/cc/library.go index 7b09b1145..bf7868ff7 100644 --- a/cc/library.go +++ b/cc/library.go @@ -19,8 +19,6 @@ import ( "io" "path/filepath" "regexp" - "sort" - "strconv" "strings" "sync" @@ -340,10 +338,6 @@ type libraryDecorator struct { flagExporter stripper Stripper - // If we're used as a whole_static_lib, our missing dependencies need - // to be given - wholeStaticMissingDeps []string - // For whole_static_libs objects Objects @@ -684,7 +678,6 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa } type libraryInterface interface { - getWholeStaticMissingDeps() []string static() bool shared() bool objs() Objects @@ -891,8 +884,6 @@ func (library *libraryDecorator) linkStatic(ctx ModuleContext, library.coverageOutputFile = TransformCoverageFilesToZip(ctx, library.objects, ctx.ModuleName()) - library.wholeStaticMissingDeps = ctx.GetMissingDependencies() - ctx.CheckbuildFile(outputFile) return outputFile @@ -1184,10 +1175,6 @@ func (library *libraryDecorator) buildShared() bool { BoolDefault(library.SharedProperties.Shared.Enabled, true) } -func (library *libraryDecorator) getWholeStaticMissingDeps() []string { - return append([]string(nil), library.wholeStaticMissingDeps...) -} - func (library *libraryDecorator) objs() Objects { return library.objects } @@ -1520,20 +1507,18 @@ func LinkageMutator(mctx android.BottomUpMutatorContext) { } func normalizeVersions(ctx android.BaseModuleContext, versions []string) { - numVersions := make([]int, len(versions)) + var previous android.ApiLevel for i, v := range versions { - numVer, err := android.ApiStrToNum(ctx, v) + ver, err := android.ApiLevelFromUser(ctx, v) if err != nil { ctx.PropertyErrorf("versions", "%s", err.Error()) return } - numVersions[i] = numVer - } - if !sort.IsSorted(sort.IntSlice(numVersions)) { - ctx.PropertyErrorf("versions", "not sorted: %v", versions) - } - for i, v := range numVersions { - versions[i] = strconv.Itoa(v) + if i > 0 && ver.LessThanOrEqualTo(previous) { + ctx.PropertyErrorf("versions", "not sorted: %v", versions) + } + versions[i] = ver.String() + previous = ver } } diff --git a/cc/library_test.go b/cc/library_test.go index cb167252d..49838b48e 100644 --- a/cc/library_test.go +++ b/cc/library_test.go @@ -195,7 +195,7 @@ func TestStubsVersions(t *testing.T) { name: "libfoo", srcs: ["foo.c"], stubs: { - versions: ["29", "R", "10000"], + versions: ["29", "R", "current"], }, } ` @@ -204,7 +204,7 @@ func TestStubsVersions(t *testing.T) { ctx := testCcWithConfig(t, config) variants := ctx.ModuleVariantsForTests("libfoo") - for _, expectedVer := range []string{"29", "9000", "10000"} { + for _, expectedVer := range []string{"29", "R", "current"} { expectedVariant := "android_arm_armv7-a-neon_shared_" + expectedVer if !inList(expectedVariant, variants) { t.Errorf("missing expected variant: %q", expectedVariant) @@ -218,7 +218,7 @@ func TestStubsVersions_NotSorted(t *testing.T) { name: "libfoo", srcs: ["foo.c"], stubs: { - versions: ["29", "10000", "R"], + versions: ["29", "current", "R"], }, } ` @@ -233,10 +233,10 @@ func TestStubsVersions_ParseError(t *testing.T) { name: "libfoo", srcs: ["foo.c"], stubs: { - versions: ["29", "10000", "X"], + versions: ["29", "current", "X"], }, } ` - testCcError(t, `"libfoo" .*: versions: SDK version should be`, bp) + testCcError(t, `"libfoo" .*: versions: "X" could not be parsed as an integer and is not a recognized codename`, bp) } diff --git a/cc/linker.go b/cc/linker.go index 58f8a294e..12c8b2c59 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -278,19 +278,19 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic") } - systemSharedLibs := linker.Properties.System_shared_libs - if systemSharedLibs == nil { + deps.SystemSharedLibs = linker.Properties.System_shared_libs + if deps.SystemSharedLibs == nil { // Provide a default system_shared_libs if it is unspecified. Note: If an // empty list [] is specified, it implies that the module declines the // default system_shared_libs. - systemSharedLibs = []string{"libc", "libm", "libdl"} + deps.SystemSharedLibs = []string{"libc", "libm", "libdl"} } if inList("libdl", deps.SharedLibs) { // If system_shared_libs has libc but not libdl, make sure shared_libs does not // have libdl to avoid loading libdl before libc. - if inList("libc", systemSharedLibs) { - if !inList("libdl", systemSharedLibs) { + if inList("libc", deps.SystemSharedLibs) { + if !inList("libdl", deps.SystemSharedLibs) { ctx.PropertyErrorf("shared_libs", "libdl must be in system_shared_libs, not shared_libs") } @@ -300,12 +300,12 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { // If libc and libdl are both in system_shared_libs make sure libdl comes after libc // to avoid loading libdl before libc. - if inList("libdl", systemSharedLibs) && inList("libc", systemSharedLibs) && - indexList("libdl", systemSharedLibs) < indexList("libc", systemSharedLibs) { + if inList("libdl", deps.SystemSharedLibs) && inList("libc", deps.SystemSharedLibs) && + indexList("libdl", deps.SystemSharedLibs) < indexList("libc", deps.SystemSharedLibs) { ctx.PropertyErrorf("system_shared_libs", "libdl must be after libc") } - deps.LateSharedLibs = append(deps.LateSharedLibs, systemSharedLibs...) + deps.LateSharedLibs = append(deps.LateSharedLibs, deps.SystemSharedLibs...) } if ctx.Fuchsia() { @@ -45,6 +45,8 @@ type LTOProperties struct { Thin *bool `android:"arch_variant"` } `android:"arch_variant"` + GlobalThin *bool `blueprint:"mutated"` + // Dep properties indicate that this module needs to be built with LTO // since it is an object dependency of an LTO module. FullDep bool `blueprint:"mutated"` @@ -68,6 +70,8 @@ func (lto *lto) props() []interface{} { func (lto *lto) begin(ctx BaseModuleContext) { if ctx.Config().IsEnvTrue("DISABLE_LTO") { lto.Properties.Lto.Never = boolPtr(true) + } else if ctx.Config().IsEnvTrue("GLOBAL_THINLTO") { + lto.Properties.GlobalThin = boolPtr(true) } } @@ -91,7 +95,7 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { if lto.LTO() { var ltoFlag string - if Bool(lto.Properties.Lto.Thin) { + if lto.ThinLTO() { ltoFlag = "-flto=thin -fsplit-lto-unit" } else { ltoFlag = "-flto" @@ -104,7 +108,7 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { flags.Local.CFlags = append(flags.Local.CFlags, "-fwhole-program-vtables") } - if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && Bool(lto.Properties.Lto.Thin) && lto.useClangLld(ctx) { + if lto.ThinLTO() && ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && lto.useClangLld(ctx) { // Set appropriate ThinLTO cache policy cacheDirFormat := "-Wl,--thinlto-cache-dir=" cacheDir := android.PathForOutput(ctx, "thinlto-cache").String() @@ -129,25 +133,37 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { // Can be called with a null receiver func (lto *lto) LTO() bool { - if lto == nil || lto.Disabled() { + if lto == nil || lto.Never() { return false } - full := Bool(lto.Properties.Lto.Full) - thin := Bool(lto.Properties.Lto.Thin) - return full || thin + return lto.FullLTO() || lto.ThinLTO() +} + +func (lto *lto) FullLTO() bool { + return Bool(lto.Properties.Lto.Full) +} + +func (lto *lto) ThinLTO() bool { + if Bool(lto.Properties.GlobalThin) { + if !lto.Never() && !lto.FullLTO() { + return true + } + } + + return Bool(lto.Properties.Lto.Thin) } // Is lto.never explicitly set to true? -func (lto *lto) Disabled() bool { - return lto.Properties.Lto.Never != nil && *lto.Properties.Lto.Never +func (lto *lto) Never() bool { + return Bool(lto.Properties.Lto.Never) } // Propagate lto requirements down from binaries func ltoDepsMutator(mctx android.TopDownMutatorContext) { if m, ok := mctx.Module().(*Module); ok && m.lto.LTO() { - full := Bool(m.lto.Properties.Lto.Full) - thin := Bool(m.lto.Properties.Lto.Thin) + full := m.lto.FullLTO() + thin := m.lto.ThinLTO() if full && thin { mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive") } @@ -168,11 +184,11 @@ func ltoDepsMutator(mctx android.TopDownMutatorContext) { } if dep, ok := dep.(*Module); ok && dep.lto != nil && - !dep.lto.Disabled() { - if full && !Bool(dep.lto.Properties.Lto.Full) { + !dep.lto.Never() { + if full && !dep.lto.FullLTO() { dep.lto.Properties.FullDep = true } - if thin && !Bool(dep.lto.Properties.Lto.Thin) { + if thin && !dep.lto.ThinLTO() { dep.lto.Properties.ThinDep = true } } @@ -189,19 +205,19 @@ func ltoMutator(mctx android.BottomUpMutatorContext) { // Create variations for LTO types required as static // dependencies variationNames := []string{""} - if m.lto.Properties.FullDep && !Bool(m.lto.Properties.Lto.Full) { + if m.lto.Properties.FullDep && !m.lto.FullLTO() { variationNames = append(variationNames, "lto-full") } - if m.lto.Properties.ThinDep && !Bool(m.lto.Properties.Lto.Thin) { + if m.lto.Properties.ThinDep && !m.lto.ThinLTO() { variationNames = append(variationNames, "lto-thin") } // Use correct dependencies if LTO property is explicitly set // (mutually exclusive) - if Bool(m.lto.Properties.Lto.Full) { + if m.lto.FullLTO() { mctx.SetDependencyVariation("lto-full") } - if Bool(m.lto.Properties.Lto.Thin) { + if m.lto.ThinLTO() { mctx.SetDependencyVariation("lto-thin") } diff --git a/cc/ndk_library.go b/cc/ndk_library.go index 4c6d98c52..5682d1c6b 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -118,8 +118,8 @@ func generatePerApiVariants(ctx android.BottomUpMutatorContext, m *Module, versionStrs = append(versionStrs, version.String()) } } - versions = append(versions, android.CurrentApiLevel) - versionStrs = append(versionStrs, android.CurrentApiLevel.String()) + versions = append(versions, android.FutureApiLevel) + versionStrs = append(versionStrs, android.FutureApiLevel.String()) modules := ctx.CreateVariations(versionStrs...) for i, module := range modules { diff --git a/cc/ndkstubgen/__init__.py b/cc/ndkstubgen/__init__.py index 2f4326a9c..86bf6ff85 100755 --- a/cc/ndkstubgen/__init__.py +++ b/cc/ndkstubgen/__init__.py @@ -20,13 +20,16 @@ import json import logging import os import sys +from typing import Iterable, TextIO import symbolfile +from symbolfile import Arch, Version class Generator: """Output generator that writes stub source files and version scripts.""" - def __init__(self, src_file, version_script, arch, api, llndk, apex): + def __init__(self, src_file: TextIO, version_script: TextIO, arch: Arch, + api: int, llndk: bool, apex: bool) -> None: self.src_file = src_file self.version_script = version_script self.arch = arch @@ -34,12 +37,12 @@ class Generator: self.llndk = llndk self.apex = apex - def write(self, versions): + def write(self, versions: Iterable[Version]) -> None: """Writes all symbol data to the output files.""" for version in versions: self.write_version(version) - def write_version(self, version): + def write_version(self, version: Version) -> None: """Writes a single version block's data to the output files.""" if symbolfile.should_omit_version(version, self.arch, self.api, self.llndk, self.apex): @@ -84,7 +87,7 @@ class Generator: self.version_script.write('}' + base + ';\n') -def parse_args(): +def parse_args() -> argparse.Namespace: """Parses and returns command line arguments.""" parser = argparse.ArgumentParser() @@ -100,23 +103,31 @@ def parse_args(): parser.add_argument( '--apex', action='store_true', help='Use the APEX variant.') + # https://github.com/python/mypy/issues/1317 + # mypy has issues with using os.path.realpath as an argument here. parser.add_argument( - '--api-map', type=os.path.realpath, required=True, + '--api-map', + type=os.path.realpath, # type: ignore + required=True, help='Path to the API level map JSON file.') parser.add_argument( - 'symbol_file', type=os.path.realpath, help='Path to symbol file.') + 'symbol_file', + type=os.path.realpath, # type: ignore + help='Path to symbol file.') parser.add_argument( - 'stub_src', type=os.path.realpath, + 'stub_src', + type=os.path.realpath, # type: ignore help='Path to output stub source file.') parser.add_argument( - 'version_script', type=os.path.realpath, + 'version_script', + type=os.path.realpath, # type: ignore help='Path to output version script.') return parser.parse_args() -def main(): +def main() -> None: """Program entry point.""" args = parse_args() diff --git a/cc/ndkstubgen/mypy.ini b/cc/ndkstubgen/mypy.ini new file mode 100644 index 000000000..82aa7eb9d --- /dev/null +++ b/cc/ndkstubgen/mypy.ini @@ -0,0 +1,2 @@ +[mypy] +disallow_untyped_defs = True diff --git a/cc/ndkstubgen/test_ndkstubgen.py b/cc/ndkstubgen/test_ndkstubgen.py index 70bcf781c..6d2c9d673 100755 --- a/cc/ndkstubgen/test_ndkstubgen.py +++ b/cc/ndkstubgen/test_ndkstubgen.py @@ -21,19 +21,20 @@ import unittest import ndkstubgen import symbolfile +from symbolfile import Arch, Tag # pylint: disable=missing-docstring class GeneratorTest(unittest.TestCase): - def test_omit_version(self): + def test_omit_version(self) -> None: # Thorough testing of the cases involved here is handled by # OmitVersionTest, PrivateVersionTest, and SymbolPresenceTest. src_file = io.StringIO() version_file = io.StringIO() - generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9, - False, False) + generator = ndkstubgen.Generator(src_file, version_file, Arch('arm'), + 9, False, False) version = symbolfile.Version('VERSION_PRIVATE', None, [], [ symbolfile.Symbol('foo', []), @@ -42,74 +43,75 @@ class GeneratorTest(unittest.TestCase): self.assertEqual('', src_file.getvalue()) self.assertEqual('', version_file.getvalue()) - version = symbolfile.Version('VERSION', None, ['x86'], [ + version = symbolfile.Version('VERSION', None, [Tag('x86')], [ symbolfile.Symbol('foo', []), ]) generator.write_version(version) self.assertEqual('', src_file.getvalue()) self.assertEqual('', version_file.getvalue()) - version = symbolfile.Version('VERSION', None, ['introduced=14'], [ + version = symbolfile.Version('VERSION', None, [Tag('introduced=14')], [ symbolfile.Symbol('foo', []), ]) generator.write_version(version) self.assertEqual('', src_file.getvalue()) self.assertEqual('', version_file.getvalue()) - def test_omit_symbol(self): + def test_omit_symbol(self) -> None: # Thorough testing of the cases involved here is handled by # SymbolPresenceTest. src_file = io.StringIO() version_file = io.StringIO() - generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9, - False, False) + generator = ndkstubgen.Generator(src_file, version_file, Arch('arm'), + 9, False, False) version = symbolfile.Version('VERSION_1', None, [], [ - symbolfile.Symbol('foo', ['x86']), + symbolfile.Symbol('foo', [Tag('x86')]), ]) generator.write_version(version) self.assertEqual('', src_file.getvalue()) self.assertEqual('', version_file.getvalue()) version = symbolfile.Version('VERSION_1', None, [], [ - symbolfile.Symbol('foo', ['introduced=14']), + symbolfile.Symbol('foo', [Tag('introduced=14')]), ]) generator.write_version(version) self.assertEqual('', src_file.getvalue()) self.assertEqual('', version_file.getvalue()) version = symbolfile.Version('VERSION_1', None, [], [ - symbolfile.Symbol('foo', ['llndk']), + symbolfile.Symbol('foo', [Tag('llndk')]), ]) generator.write_version(version) self.assertEqual('', src_file.getvalue()) self.assertEqual('', version_file.getvalue()) version = symbolfile.Version('VERSION_1', None, [], [ - symbolfile.Symbol('foo', ['apex']), + symbolfile.Symbol('foo', [Tag('apex')]), ]) generator.write_version(version) self.assertEqual('', src_file.getvalue()) self.assertEqual('', version_file.getvalue()) - def test_write(self): + def test_write(self) -> None: src_file = io.StringIO() version_file = io.StringIO() - generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9, - False, False) + generator = ndkstubgen.Generator(src_file, version_file, Arch('arm'), + 9, False, False) versions = [ symbolfile.Version('VERSION_1', None, [], [ symbolfile.Symbol('foo', []), - symbolfile.Symbol('bar', ['var']), - symbolfile.Symbol('woodly', ['weak']), - symbolfile.Symbol('doodly', ['weak', 'var']), + symbolfile.Symbol('bar', [Tag('var')]), + symbolfile.Symbol('woodly', [Tag('weak')]), + symbolfile.Symbol('doodly', + [Tag('weak'), Tag('var')]), ]), symbolfile.Version('VERSION_2', 'VERSION_1', [], [ symbolfile.Symbol('baz', []), ]), symbolfile.Version('VERSION_3', 'VERSION_1', [], [ - symbolfile.Symbol('qux', ['versioned=14']), + symbolfile.Symbol('qux', [Tag('versioned=14')]), ]), ] @@ -141,7 +143,7 @@ class GeneratorTest(unittest.TestCase): class IntegrationTest(unittest.TestCase): - def test_integration(self): + def test_integration(self) -> None: api_map = { 'O': 9000, 'P': 9001, @@ -178,14 +180,14 @@ class IntegrationTest(unittest.TestCase): wobble; } VERSION_4; """)) - parser = symbolfile.SymbolFileParser(input_file, api_map, 'arm', 9, - False, False) + parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'), + 9, False, False) versions = parser.parse() src_file = io.StringIO() version_file = io.StringIO() - generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9, - False, False) + generator = ndkstubgen.Generator(src_file, version_file, Arch('arm'), + 9, False, False) generator.write(versions) expected_src = textwrap.dedent("""\ @@ -213,7 +215,7 @@ class IntegrationTest(unittest.TestCase): """) self.assertEqual(expected_version, version_file.getvalue()) - def test_integration_future_api(self): + def test_integration_future_api(self) -> None: api_map = { 'O': 9000, 'P': 9001, @@ -230,14 +232,14 @@ class IntegrationTest(unittest.TestCase): *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, api_map, 'arm', 9001, - False, False) + parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'), + 9001, False, False) versions = parser.parse() src_file = io.StringIO() version_file = io.StringIO() - generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9001, - False, False) + generator = ndkstubgen.Generator(src_file, version_file, Arch('arm'), + 9001, False, False) generator.write(versions) expected_src = textwrap.dedent("""\ @@ -255,7 +257,7 @@ class IntegrationTest(unittest.TestCase): """) self.assertEqual(expected_version, version_file.getvalue()) - def test_multiple_definition(self): + def test_multiple_definition(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { global: @@ -280,8 +282,8 @@ class IntegrationTest(unittest.TestCase): } VERSION_2; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, - False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) with self.assertRaises( symbolfile.MultiplyDefinedSymbolError) as ex_context: @@ -289,7 +291,7 @@ class IntegrationTest(unittest.TestCase): self.assertEqual(['bar', 'foo'], ex_context.exception.multiply_defined_symbols) - def test_integration_with_apex(self): + def test_integration_with_apex(self) -> None: api_map = { 'O': 9000, 'P': 9001, @@ -328,14 +330,14 @@ class IntegrationTest(unittest.TestCase): wobble; } VERSION_4; """)) - parser = symbolfile.SymbolFileParser(input_file, api_map, 'arm', 9, - False, True) + parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'), + 9, False, True) versions = parser.parse() src_file = io.StringIO() version_file = io.StringIO() - generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9, - False, True) + generator = ndkstubgen.Generator(src_file, version_file, Arch('arm'), + 9, False, True) generator.write(versions) expected_src = textwrap.dedent("""\ @@ -369,7 +371,8 @@ class IntegrationTest(unittest.TestCase): """) self.assertEqual(expected_version, version_file.getvalue()) -def main(): + +def main() -> None: suite = unittest.TestLoader().loadTestsFromName(__name__) unittest.TextTestRunner(verbosity=3).run(suite) diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py index faa3823f3..5678e7d83 100644 --- a/cc/symbolfile/__init__.py +++ b/cc/symbolfile/__init__.py @@ -14,15 +14,31 @@ # limitations under the License. # """Parser for Android's version script information.""" +from dataclasses import dataclass import logging import re +from typing import ( + Dict, + Iterable, + List, + Mapping, + NewType, + Optional, + TextIO, + Tuple, +) + + +ApiMap = Mapping[str, int] +Arch = NewType('Arch', str) +Tag = NewType('Tag', str) ALL_ARCHITECTURES = ( - 'arm', - 'arm64', - 'x86', - 'x86_64', + Arch('arm'), + Arch('arm64'), + Arch('x86'), + Arch('x86_64'), ) @@ -30,18 +46,36 @@ ALL_ARCHITECTURES = ( FUTURE_API_LEVEL = 10000 -def logger(): +def logger() -> logging.Logger: """Return the main logger for this module.""" return logging.getLogger(__name__) -def get_tags(line): +@dataclass +class Symbol: + """A symbol definition from a symbol file.""" + + name: str + tags: List[Tag] + + +@dataclass +class Version: + """A version block of a symbol file.""" + + name: str + base: Optional[str] + tags: List[Tag] + symbols: List[Symbol] + + +def get_tags(line: str) -> List[Tag]: """Returns a list of all tags on this line.""" _, _, all_tags = line.strip().partition('#') - return [e for e in re.split(r'\s+', all_tags) if e.strip()] + return [Tag(e) for e in re.split(r'\s+', all_tags) if e.strip()] -def is_api_level_tag(tag): +def is_api_level_tag(tag: Tag) -> bool: """Returns true if this tag has an API level that may need decoding.""" if tag.startswith('introduced='): return True @@ -52,7 +86,7 @@ def is_api_level_tag(tag): return False -def decode_api_level(api, api_map): +def decode_api_level(api: str, api_map: ApiMap) -> int: """Decodes the API level argument into the API level number. For the average case, this just decodes the integer value from the string, @@ -70,12 +104,13 @@ def decode_api_level(api, api_map): return api_map[api] -def decode_api_level_tags(tags, api_map): +def decode_api_level_tags(tags: Iterable[Tag], api_map: ApiMap) -> List[Tag]: """Decodes API level code names in a list of tags. Raises: ParseError: An unknown version name was found in a tag. """ + decoded_tags = list(tags) for idx, tag in enumerate(tags): if not is_api_level_tag(tag): continue @@ -83,13 +118,13 @@ def decode_api_level_tags(tags, api_map): try: decoded = str(decode_api_level(value, api_map)) - tags[idx] = '='.join([name, decoded]) + decoded_tags[idx] = Tag('='.join([name, decoded])) except KeyError: - raise ParseError('Unknown version name in tag: {}'.format(tag)) - return tags + raise ParseError(f'Unknown version name in tag: {tag}') + return decoded_tags -def split_tag(tag): +def split_tag(tag: Tag) -> Tuple[str, str]: """Returns a key/value tuple of the tag. Raises: @@ -103,7 +138,7 @@ def split_tag(tag): return key, value -def get_tag_value(tag): +def get_tag_value(tag: Tag) -> str: """Returns the value of a key/value tag. Raises: @@ -114,12 +149,13 @@ def get_tag_value(tag): return split_tag(tag)[1] -def version_is_private(version): +def version_is_private(version: str) -> bool: """Returns True if the version name should be treated as private.""" return version.endswith('_PRIVATE') or version.endswith('_PLATFORM') -def should_omit_version(version, arch, api, llndk, apex): +def should_omit_version(version: Version, arch: Arch, api: int, llndk: bool, + apex: bool) -> bool: """Returns True if the version section should be ommitted. We want to omit any sections that do not have any symbols we'll have in the @@ -145,7 +181,8 @@ def should_omit_version(version, arch, api, llndk, apex): return False -def should_omit_symbol(symbol, arch, api, llndk, apex): +def should_omit_symbol(symbol: Symbol, arch: Arch, api: int, llndk: bool, + apex: bool) -> bool: """Returns True if the symbol should be omitted.""" no_llndk_no_apex = 'llndk' not in symbol.tags and 'apex' not in symbol.tags keep = no_llndk_no_apex or \ @@ -160,7 +197,7 @@ def should_omit_symbol(symbol, arch, api, llndk, apex): return False -def symbol_in_arch(tags, arch): +def symbol_in_arch(tags: Iterable[Tag], arch: Arch) -> bool: """Returns true if the symbol is present for the given architecture.""" has_arch_tags = False for tag in tags: @@ -175,7 +212,7 @@ def symbol_in_arch(tags, arch): return not has_arch_tags -def symbol_in_api(tags, arch, api): +def symbol_in_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool: """Returns true if the symbol is present for the given API level.""" introduced_tag = None arch_specific = False @@ -197,7 +234,7 @@ def symbol_in_api(tags, arch, api): return api >= int(get_tag_value(introduced_tag)) -def symbol_versioned_in_api(tags, api): +def symbol_versioned_in_api(tags: Iterable[Tag], api: int) -> bool: """Returns true if the symbol should be versioned for the given API. This models the `versioned=API` tag. This should be a very uncommonly @@ -223,68 +260,40 @@ class ParseError(RuntimeError): class MultiplyDefinedSymbolError(RuntimeError): """A symbol name was multiply defined.""" - def __init__(self, multiply_defined_symbols): - super(MultiplyDefinedSymbolError, self).__init__( + def __init__(self, multiply_defined_symbols: Iterable[str]) -> None: + super().__init__( 'Version script contains multiple definitions for: {}'.format( ', '.join(multiply_defined_symbols))) self.multiply_defined_symbols = multiply_defined_symbols -class Version: - """A version block of a symbol file.""" - def __init__(self, name, base, tags, symbols): - self.name = name - self.base = base - self.tags = tags - self.symbols = symbols - - def __eq__(self, other): - if self.name != other.name: - return False - if self.base != other.base: - return False - if self.tags != other.tags: - return False - if self.symbols != other.symbols: - return False - return True - - -class Symbol: - """A symbol definition from a symbol file.""" - def __init__(self, name, tags): - self.name = name - self.tags = tags - - def __eq__(self, other): - return self.name == other.name and set(self.tags) == set(other.tags) - - class SymbolFileParser: """Parses NDK symbol files.""" - def __init__(self, input_file, api_map, arch, api, llndk, apex): + def __init__(self, input_file: TextIO, api_map: ApiMap, arch: Arch, + api: int, llndk: bool, apex: bool) -> None: self.input_file = input_file self.api_map = api_map self.arch = arch self.api = api self.llndk = llndk self.apex = apex - self.current_line = None + self.current_line: Optional[str] = None - def parse(self): + def parse(self) -> List[Version]: """Parses the symbol file and returns a list of Version objects.""" versions = [] while self.next_line() != '': + assert self.current_line is not None if '{' in self.current_line: versions.append(self.parse_version()) else: raise ParseError( - 'Unexpected contents at top level: ' + self.current_line) + f'Unexpected contents at top level: {self.current_line}') self.check_no_duplicate_symbols(versions) return versions - def check_no_duplicate_symbols(self, versions): + def check_no_duplicate_symbols(self, versions: Iterable[Version]) -> None: """Raises errors for multiply defined symbols. This situation is the normal case when symbol versioning is actually @@ -312,12 +321,13 @@ class SymbolFileParser: raise MultiplyDefinedSymbolError( sorted(list(multiply_defined_symbols))) - def parse_version(self): + def parse_version(self) -> Version: """Parses a single version section and returns a Version object.""" + assert self.current_line is not None name = self.current_line.split('{')[0].strip() tags = get_tags(self.current_line) tags = decode_api_level_tags(tags, self.api_map) - symbols = [] + symbols: List[Symbol] = [] global_scope = True cpp_symbols = False while self.next_line() != '': @@ -333,9 +343,7 @@ class SymbolFileParser: cpp_symbols = False else: base = base.rstrip(';').rstrip() - if base == '': - base = None - return Version(name, base, tags, symbols) + return Version(name, base or None, tags, symbols) elif 'extern "C++" {' in self.current_line: cpp_symbols = True elif not cpp_symbols and ':' in self.current_line: @@ -354,8 +362,9 @@ class SymbolFileParser: pass raise ParseError('Unexpected EOF in version block.') - def parse_symbol(self): + def parse_symbol(self) -> Symbol: """Parses a single symbol line and returns a Symbol object.""" + assert self.current_line is not None if ';' not in self.current_line: raise ParseError( 'Expected ; to terminate symbol: ' + self.current_line) @@ -368,7 +377,7 @@ class SymbolFileParser: tags = decode_api_level_tags(tags, self.api_map) return Symbol(name, tags) - def next_line(self): + def next_line(self) -> str: """Returns the next non-empty non-comment line. A return value of '' indicates EOF. diff --git a/cc/symbolfile/mypy.ini b/cc/symbolfile/mypy.ini new file mode 100644 index 000000000..82aa7eb9d --- /dev/null +++ b/cc/symbolfile/mypy.ini @@ -0,0 +1,2 @@ +[mypy] +disallow_untyped_defs = True diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py index c91131fee..92b13999e 100644 --- a/cc/symbolfile/test_symbolfile.py +++ b/cc/symbolfile/test_symbolfile.py @@ -19,12 +19,13 @@ import textwrap import unittest import symbolfile +from symbolfile import Arch, Tag # pylint: disable=missing-docstring class DecodeApiLevelTest(unittest.TestCase): - def test_decode_api_level(self): + def test_decode_api_level(self) -> None: self.assertEqual(9, symbolfile.decode_api_level('9', {})) self.assertEqual(9000, symbolfile.decode_api_level('O', {'O': 9000})) @@ -33,70 +34,73 @@ class DecodeApiLevelTest(unittest.TestCase): class TagsTest(unittest.TestCase): - def test_get_tags_no_tags(self): + def test_get_tags_no_tags(self) -> None: self.assertEqual([], symbolfile.get_tags('')) self.assertEqual([], symbolfile.get_tags('foo bar baz')) - def test_get_tags(self): + def test_get_tags(self) -> None: self.assertEqual(['foo', 'bar'], symbolfile.get_tags('# foo bar')) self.assertEqual(['bar', 'baz'], symbolfile.get_tags('foo # bar baz')) - def test_split_tag(self): - self.assertTupleEqual(('foo', 'bar'), symbolfile.split_tag('foo=bar')) - self.assertTupleEqual(('foo', 'bar=baz'), symbolfile.split_tag('foo=bar=baz')) + def test_split_tag(self) -> None: + self.assertTupleEqual(('foo', 'bar'), + symbolfile.split_tag(Tag('foo=bar'))) + self.assertTupleEqual(('foo', 'bar=baz'), + symbolfile.split_tag(Tag('foo=bar=baz'))) with self.assertRaises(ValueError): - symbolfile.split_tag('foo') + symbolfile.split_tag(Tag('foo')) - def test_get_tag_value(self): - self.assertEqual('bar', symbolfile.get_tag_value('foo=bar')) - self.assertEqual('bar=baz', symbolfile.get_tag_value('foo=bar=baz')) + def test_get_tag_value(self) -> None: + self.assertEqual('bar', symbolfile.get_tag_value(Tag('foo=bar'))) + self.assertEqual('bar=baz', + symbolfile.get_tag_value(Tag('foo=bar=baz'))) with self.assertRaises(ValueError): - symbolfile.get_tag_value('foo') + symbolfile.get_tag_value(Tag('foo')) - def test_is_api_level_tag(self): - self.assertTrue(symbolfile.is_api_level_tag('introduced=24')) - self.assertTrue(symbolfile.is_api_level_tag('introduced-arm=24')) - self.assertTrue(symbolfile.is_api_level_tag('versioned=24')) + def test_is_api_level_tag(self) -> None: + self.assertTrue(symbolfile.is_api_level_tag(Tag('introduced=24'))) + self.assertTrue(symbolfile.is_api_level_tag(Tag('introduced-arm=24'))) + self.assertTrue(symbolfile.is_api_level_tag(Tag('versioned=24'))) # Shouldn't try to process things that aren't a key/value tag. - self.assertFalse(symbolfile.is_api_level_tag('arm')) - self.assertFalse(symbolfile.is_api_level_tag('introduced')) - self.assertFalse(symbolfile.is_api_level_tag('versioned')) + self.assertFalse(symbolfile.is_api_level_tag(Tag('arm'))) + self.assertFalse(symbolfile.is_api_level_tag(Tag('introduced'))) + self.assertFalse(symbolfile.is_api_level_tag(Tag('versioned'))) # We don't support arch specific `versioned` tags. - self.assertFalse(symbolfile.is_api_level_tag('versioned-arm=24')) + self.assertFalse(symbolfile.is_api_level_tag(Tag('versioned-arm=24'))) - def test_decode_api_level_tags(self): + def test_decode_api_level_tags(self) -> None: api_map = { 'O': 9000, 'P': 9001, } tags = [ - 'introduced=9', - 'introduced-arm=14', - 'versioned=16', - 'arm', - 'introduced=O', - 'introduced=P', + Tag('introduced=9'), + Tag('introduced-arm=14'), + Tag('versioned=16'), + Tag('arm'), + Tag('introduced=O'), + Tag('introduced=P'), ] expected_tags = [ - 'introduced=9', - 'introduced-arm=14', - 'versioned=16', - 'arm', - 'introduced=9000', - 'introduced=9001', + Tag('introduced=9'), + Tag('introduced-arm=14'), + Tag('versioned=16'), + Tag('arm'), + Tag('introduced=9000'), + Tag('introduced=9001'), ] self.assertListEqual( expected_tags, symbolfile.decode_api_level_tags(tags, api_map)) with self.assertRaises(symbolfile.ParseError): - symbolfile.decode_api_level_tags(['introduced=O'], {}) + symbolfile.decode_api_level_tags([Tag('introduced=O')], {}) class PrivateVersionTest(unittest.TestCase): - def test_version_is_private(self): + def test_version_is_private(self) -> None: self.assertFalse(symbolfile.version_is_private('foo')) self.assertFalse(symbolfile.version_is_private('PRIVATE')) self.assertFalse(symbolfile.version_is_private('PLATFORM')) @@ -110,191 +114,227 @@ class PrivateVersionTest(unittest.TestCase): class SymbolPresenceTest(unittest.TestCase): - def test_symbol_in_arch(self): - self.assertTrue(symbolfile.symbol_in_arch([], 'arm')) - self.assertTrue(symbolfile.symbol_in_arch(['arm'], 'arm')) - - self.assertFalse(symbolfile.symbol_in_arch(['x86'], 'arm')) - - def test_symbol_in_api(self): - self.assertTrue(symbolfile.symbol_in_api([], 'arm', 9)) - self.assertTrue(symbolfile.symbol_in_api(['introduced=9'], 'arm', 9)) - self.assertTrue(symbolfile.symbol_in_api(['introduced=9'], 'arm', 14)) - self.assertTrue(symbolfile.symbol_in_api(['introduced-arm=9'], 'arm', 14)) - self.assertTrue(symbolfile.symbol_in_api(['introduced-arm=9'], 'arm', 14)) - self.assertTrue(symbolfile.symbol_in_api(['introduced-x86=14'], 'arm', 9)) - self.assertTrue(symbolfile.symbol_in_api( - ['introduced-arm=9', 'introduced-x86=21'], 'arm', 14)) - self.assertTrue(symbolfile.symbol_in_api( - ['introduced=9', 'introduced-x86=21'], 'arm', 14)) - self.assertTrue(symbolfile.symbol_in_api( - ['introduced=21', 'introduced-arm=9'], 'arm', 14)) - self.assertTrue(symbolfile.symbol_in_api( - ['future'], 'arm', symbolfile.FUTURE_API_LEVEL)) - - self.assertFalse(symbolfile.symbol_in_api(['introduced=14'], 'arm', 9)) - self.assertFalse(symbolfile.symbol_in_api(['introduced-arm=14'], 'arm', 9)) - self.assertFalse(symbolfile.symbol_in_api(['future'], 'arm', 9)) - self.assertFalse(symbolfile.symbol_in_api( - ['introduced=9', 'future'], 'arm', 14)) - self.assertFalse(symbolfile.symbol_in_api( - ['introduced-arm=9', 'future'], 'arm', 14)) - self.assertFalse(symbolfile.symbol_in_api( - ['introduced-arm=21', 'introduced-x86=9'], 'arm', 14)) - self.assertFalse(symbolfile.symbol_in_api( - ['introduced=9', 'introduced-arm=21'], 'arm', 14)) - self.assertFalse(symbolfile.symbol_in_api( - ['introduced=21', 'introduced-x86=9'], 'arm', 14)) + def test_symbol_in_arch(self) -> None: + self.assertTrue(symbolfile.symbol_in_arch([], Arch('arm'))) + self.assertTrue(symbolfile.symbol_in_arch([Tag('arm')], Arch('arm'))) + + self.assertFalse(symbolfile.symbol_in_arch([Tag('x86')], Arch('arm'))) + + def test_symbol_in_api(self) -> None: + self.assertTrue(symbolfile.symbol_in_api([], Arch('arm'), 9)) + self.assertTrue( + symbolfile.symbol_in_api([Tag('introduced=9')], Arch('arm'), 9)) + self.assertTrue( + symbolfile.symbol_in_api([Tag('introduced=9')], Arch('arm'), 14)) + self.assertTrue( + symbolfile.symbol_in_api([Tag('introduced-arm=9')], Arch('arm'), + 14)) + self.assertTrue( + symbolfile.symbol_in_api([Tag('introduced-arm=9')], Arch('arm'), + 14)) + self.assertTrue( + symbolfile.symbol_in_api([Tag('introduced-x86=14')], Arch('arm'), + 9)) + self.assertTrue( + symbolfile.symbol_in_api( + [Tag('introduced-arm=9'), + Tag('introduced-x86=21')], Arch('arm'), 14)) + self.assertTrue( + symbolfile.symbol_in_api( + [Tag('introduced=9'), + Tag('introduced-x86=21')], Arch('arm'), 14)) + self.assertTrue( + symbolfile.symbol_in_api( + [Tag('introduced=21'), + Tag('introduced-arm=9')], Arch('arm'), 14)) + self.assertTrue( + symbolfile.symbol_in_api([Tag('future')], Arch('arm'), + symbolfile.FUTURE_API_LEVEL)) + + self.assertFalse( + symbolfile.symbol_in_api([Tag('introduced=14')], Arch('arm'), 9)) + self.assertFalse( + symbolfile.symbol_in_api([Tag('introduced-arm=14')], Arch('arm'), + 9)) + self.assertFalse( + symbolfile.symbol_in_api([Tag('future')], Arch('arm'), 9)) + self.assertFalse( + symbolfile.symbol_in_api( + [Tag('introduced=9'), Tag('future')], Arch('arm'), 14)) + self.assertFalse( + symbolfile.symbol_in_api([Tag('introduced-arm=9'), + Tag('future')], Arch('arm'), 14)) + self.assertFalse( + symbolfile.symbol_in_api( + [Tag('introduced-arm=21'), + Tag('introduced-x86=9')], Arch('arm'), 14)) + self.assertFalse( + symbolfile.symbol_in_api( + [Tag('introduced=9'), + Tag('introduced-arm=21')], Arch('arm'), 14)) + self.assertFalse( + symbolfile.symbol_in_api( + [Tag('introduced=21'), + Tag('introduced-x86=9')], Arch('arm'), 14)) # Interesting edge case: this symbol should be omitted from the # library, but this call should still return true because none of the # tags indiciate that it's not present in this API level. - self.assertTrue(symbolfile.symbol_in_api(['x86'], 'arm', 9)) + self.assertTrue(symbolfile.symbol_in_api([Tag('x86')], Arch('arm'), 9)) - def test_verioned_in_api(self): + def test_verioned_in_api(self) -> None: self.assertTrue(symbolfile.symbol_versioned_in_api([], 9)) - self.assertTrue(symbolfile.symbol_versioned_in_api(['versioned=9'], 9)) - self.assertTrue(symbolfile.symbol_versioned_in_api(['versioned=9'], 14)) + self.assertTrue( + symbolfile.symbol_versioned_in_api([Tag('versioned=9')], 9)) + self.assertTrue( + symbolfile.symbol_versioned_in_api([Tag('versioned=9')], 14)) - self.assertFalse(symbolfile.symbol_versioned_in_api(['versioned=14'], 9)) + self.assertFalse( + symbolfile.symbol_versioned_in_api([Tag('versioned=14')], 9)) class OmitVersionTest(unittest.TestCase): - def test_omit_private(self): + def test_omit_private(self) -> None: self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, [], []), 'arm', 9, False, + symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False, False)) self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo_PRIVATE', None, [], []), 'arm', 9, - False, False)) + symbolfile.Version('foo_PRIVATE', None, [], []), Arch('arm'), + 9, False, False)) self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo_PLATFORM', None, [], []), 'arm', 9, - False, False)) + symbolfile.Version('foo_PLATFORM', None, [], []), Arch('arm'), + 9, False, False)) self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['platform-only'], []), 'arm', - 9, False, False)) + symbolfile.Version('foo', None, [Tag('platform-only')], []), + Arch('arm'), 9, False, False)) - def test_omit_llndk(self): + def test_omit_llndk(self) -> None: self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['llndk'], []), 'arm', 9, - False, False)) + symbolfile.Version('foo', None, [Tag('llndk')], []), + Arch('arm'), 9, False, False)) self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, [], []), 'arm', 9, True, + symbolfile.Version('foo', None, [], []), Arch('arm'), 9, True, False)) self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['llndk'], []), 'arm', 9, True, - False)) + symbolfile.Version('foo', None, [Tag('llndk')], []), + Arch('arm'), 9, True, False)) - def test_omit_apex(self): + def test_omit_apex(self) -> None: self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['apex'], []), 'arm', 9, False, - False)) + symbolfile.Version('foo', None, [Tag('apex')], []), + Arch('arm'), 9, False, False)) self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, [], []), 'arm', 9, False, + symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False, True)) self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['apex'], []), 'arm', 9, False, - True)) + symbolfile.Version('foo', None, [Tag('apex')], []), + Arch('arm'), 9, False, True)) - def test_omit_arch(self): + def test_omit_arch(self) -> None: self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, [], []), 'arm', 9, False, + symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False, False)) self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['arm'], []), 'arm', 9, False, - False)) + symbolfile.Version('foo', None, [Tag('arm')], []), Arch('arm'), + 9, False, False)) self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['x86'], []), 'arm', 9, False, - False)) + symbolfile.Version('foo', None, [Tag('x86')], []), Arch('arm'), + 9, False, False)) - def test_omit_api(self): + def test_omit_api(self) -> None: self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, [], []), 'arm', 9, False, + symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False, False)) self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['introduced=9'], []), 'arm', - 9, False, False)) + symbolfile.Version('foo', None, [Tag('introduced=9')], []), + Arch('arm'), 9, False, False)) self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['introduced=14'], []), 'arm', - 9, False, False)) + symbolfile.Version('foo', None, [Tag('introduced=14')], []), + Arch('arm'), 9, False, False)) class OmitSymbolTest(unittest.TestCase): - def test_omit_llndk(self): + def test_omit_llndk(self) -> None: self.assertTrue( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['llndk']), - 'arm', 9, False, False)) + symbolfile.should_omit_symbol( + symbolfile.Symbol('foo', [Tag('llndk')]), Arch('arm'), 9, + False, False)) self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm', - 9, True, False)) + symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), + Arch('arm'), 9, True, False)) self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['llndk']), - 'arm', 9, True, False)) + symbolfile.should_omit_symbol( + symbolfile.Symbol('foo', [Tag('llndk')]), Arch('arm'), 9, True, + False)) - def test_omit_apex(self): + def test_omit_apex(self) -> None: self.assertTrue( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['apex']), - 'arm', 9, False, False)) + symbolfile.should_omit_symbol( + symbolfile.Symbol('foo', [Tag('apex')]), Arch('arm'), 9, False, + False)) self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm', - 9, False, True)) + symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), + Arch('arm'), 9, False, True)) self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['apex']), - 'arm', 9, False, True)) + symbolfile.should_omit_symbol( + symbolfile.Symbol('foo', [Tag('apex')]), Arch('arm'), 9, False, + True)) - def test_omit_arch(self): + def test_omit_arch(self) -> None: self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm', - 9, False, False)) + symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), + Arch('arm'), 9, False, False)) self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['arm']), - 'arm', 9, False, False)) + symbolfile.should_omit_symbol( + symbolfile.Symbol('foo', [Tag('arm')]), Arch('arm'), 9, False, + False)) self.assertTrue( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['x86']), - 'arm', 9, False, False)) + symbolfile.should_omit_symbol( + symbolfile.Symbol('foo', [Tag('x86')]), Arch('arm'), 9, False, + False)) - def test_omit_api(self): + def test_omit_api(self) -> None: self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm', - 9, False, False)) + symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), + Arch('arm'), 9, False, False)) self.assertFalse( symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', ['introduced=9']), 'arm', 9, False, - False)) + symbolfile.Symbol('foo', [Tag('introduced=9')]), Arch('arm'), + 9, False, False)) self.assertTrue( symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', ['introduced=14']), 'arm', 9, False, - False)) + symbolfile.Symbol('foo', [Tag('introduced=14')]), Arch('arm'), + 9, False, False)) class SymbolFileParseTest(unittest.TestCase): - def test_next_line(self): + def test_next_line(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ foo @@ -302,10 +342,12 @@ class SymbolFileParseTest(unittest.TestCase): # baz qux """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) self.assertIsNone(parser.current_line) self.assertEqual('foo', parser.next_line().strip()) + assert parser.current_line is not None self.assertEqual('foo', parser.current_line.strip()) self.assertEqual('bar', parser.next_line().strip()) @@ -317,7 +359,7 @@ class SymbolFileParseTest(unittest.TestCase): self.assertEqual('', parser.next_line()) self.assertEqual('', parser.current_line) - def test_parse_version(self): + def test_parse_version(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { # foo bar baz; @@ -327,7 +369,8 @@ class SymbolFileParseTest(unittest.TestCase): VERSION_2 { } VERSION_1; # asdf """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() version = parser.parse_version() @@ -337,7 +380,7 @@ class SymbolFileParseTest(unittest.TestCase): expected_symbols = [ symbolfile.Symbol('baz', []), - symbolfile.Symbol('qux', ['woodly', 'doodly']), + symbolfile.Symbol('qux', [Tag('woodly'), Tag('doodly')]), ] self.assertEqual(expected_symbols, version.symbols) @@ -347,32 +390,35 @@ class SymbolFileParseTest(unittest.TestCase): self.assertEqual('VERSION_1', version.base) self.assertEqual([], version.tags) - def test_parse_version_eof(self): + def test_parse_version_eof(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() - def test_unknown_scope_label(self): + def test_unknown_scope_label(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { foo: } """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() - def test_parse_symbol(self): + def test_parse_symbol(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ foo; bar; # baz qux """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() symbol = parser.parse_symbol() @@ -384,48 +430,51 @@ class SymbolFileParseTest(unittest.TestCase): self.assertEqual('bar', symbol.name) self.assertEqual(['baz', 'qux'], symbol.tags) - def test_wildcard_symbol_global(self): + def test_wildcard_symbol_global(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() - def test_wildcard_symbol_local(self): + def test_wildcard_symbol_local(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { local: *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() version = parser.parse_version() self.assertEqual([], version.symbols) - def test_missing_semicolon(self): + def test_missing_semicolon(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { foo }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() - def test_parse_fails_invalid_input(self): + def test_parse_fails_invalid_input(self) -> None: with self.assertRaises(symbolfile.ParseError): input_file = io.StringIO('foo') - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), + 16, False, False) parser.parse() - def test_parse(self): + def test_parse(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { local: @@ -443,23 +492,24 @@ class SymbolFileParseTest(unittest.TestCase): qwerty; } VERSION_1; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) versions = parser.parse() expected = [ symbolfile.Version('VERSION_1', None, [], [ symbolfile.Symbol('foo', []), - symbolfile.Symbol('bar', ['baz']), + symbolfile.Symbol('bar', [Tag('baz')]), ]), - symbolfile.Version('VERSION_2', 'VERSION_1', ['wasd'], [ + symbolfile.Version('VERSION_2', 'VERSION_1', [Tag('wasd')], [ symbolfile.Symbol('woodly', []), - symbolfile.Symbol('doodly', ['asdf']), + symbolfile.Symbol('doodly', [Tag('asdf')]), ]), ] self.assertEqual(expected, versions) - def test_parse_llndk_apex_symbol(self): + def test_parse_llndk_apex_symbol(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { foo; @@ -468,7 +518,8 @@ class SymbolFileParseTest(unittest.TestCase): qux; # apex }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, True) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, True) parser.next_line() version = parser.parse_version() @@ -477,14 +528,14 @@ class SymbolFileParseTest(unittest.TestCase): expected_symbols = [ symbolfile.Symbol('foo', []), - symbolfile.Symbol('bar', ['llndk']), - symbolfile.Symbol('baz', ['llndk', 'apex']), - symbolfile.Symbol('qux', ['apex']), + symbolfile.Symbol('bar', [Tag('llndk')]), + symbolfile.Symbol('baz', [Tag('llndk'), Tag('apex')]), + symbolfile.Symbol('qux', [Tag('apex')]), ] self.assertEqual(expected_symbols, version.symbols) -def main(): +def main() -> None: suite = unittest.TestLoader().loadTestsFromName(__name__) unittest.TextTestRunner(verbosity=3).run(suite) diff --git a/genrule/genrule.go b/genrule/genrule.go index 1cec2893a..4a2f81073 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -555,7 +555,8 @@ func (g *Module) AndroidMk() android.AndroidMkData { } } -func (g *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { +func (g *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, + sdkVersion android.ApiLevel) error { // Because generated outputs are checked by client modules(e.g. cc_library, ...) // we can safely ignore the check here. return nil diff --git a/java/aar.go b/java/aar.go index 667dd9de4..9cab0bdca 100644 --- a/java/aar.go +++ b/java/aar.go @@ -189,7 +189,7 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext, // Version code if !hasVersionCode { - linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion()) + linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion().String()) } if !hasVersionName { @@ -774,7 +774,8 @@ func (a *AARImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.M return a.depIsInSameApex(ctx, dep) } -func (g *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { +func (g *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, + sdkVersion android.ApiLevel) error { return nil } diff --git a/java/app.go b/java/app.go index ae7373fc7..13d08b94a 100755 --- a/java/app.go +++ b/java/app.go @@ -157,7 +157,7 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) "abis": strings.Join(SupportedAbis(ctx), ","), "allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)), "screen-densities": screenDensities, - "sdk-version": ctx.Config().PlatformSdkVersion(), + "sdk-version": ctx.Config().PlatformSdkVersion().String(), "stem": as.BaseModuleName(), "apkcerts": as.apkcertsFile.String(), "partition": as.PartitionTag(ctx.DeviceConfig()), @@ -436,7 +436,7 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if minSdkVersion, err := a.minSdkVersion().effectiveVersion(ctx); err == nil { a.checkJniLibsSdkVersion(ctx, minSdkVersion) - android.CheckMinSdkVersion(a, ctx, int(minSdkVersion)) + android.CheckMinSdkVersion(a, ctx, minSdkVersion.ApiLevel(ctx)) } else { ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) } @@ -678,7 +678,7 @@ func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext) { seenModules[child] = true // Skip host modules. - if child.Target().Os.Class == android.Host || child.Target().Os.Class == android.HostCross { + if child.Target().Os.Class == android.Host { return false } @@ -1637,7 +1637,8 @@ func (a *AndroidAppImport) minSdkVersion() sdkSpec { return sdkSpecFrom("") } -func (j *AndroidAppImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { +func (j *AndroidAppImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, + sdkVersion android.ApiLevel) error { // Do not check for prebuilts against the min_sdk_version of enclosing APEX return nil } diff --git a/java/app_test.go b/java/app_test.go index 536797119..4347db8b1 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -1078,6 +1078,7 @@ func TestAppSdkVersion(t *testing.T) { platformSdkFinal bool expectedMinSdkVersion string platformApis bool + activeCodenames []string }{ { name: "current final SDK", @@ -1094,6 +1095,7 @@ func TestAppSdkVersion(t *testing.T) { platformSdkCodename: "OMR1", platformSdkFinal: false, expectedMinSdkVersion: "OMR1", + activeCodenames: []string{"OMR1"}, }, { name: "default final SDK", @@ -1112,11 +1114,14 @@ func TestAppSdkVersion(t *testing.T) { platformSdkCodename: "OMR1", platformSdkFinal: false, expectedMinSdkVersion: "OMR1", + activeCodenames: []string{"OMR1"}, }, { name: "14", sdkVersion: "14", expectedMinSdkVersion: "14", + platformSdkCodename: "S", + activeCodenames: []string{"S"}, }, } @@ -1137,6 +1142,7 @@ func TestAppSdkVersion(t *testing.T) { config := testAppConfig(nil, bp, nil) config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename + config.TestProductVariables.Platform_version_active_codenames = test.activeCodenames config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal checkSdkVersion(t, config, test.expectedMinSdkVersion) @@ -1179,15 +1185,6 @@ func TestVendorAppSdkVersion(t *testing.T) { platformSdkInt: 29, platformSdkCodename: "Q", platformSdkFinal: false, - deviceCurrentApiLevelForVendorModules: "current", - expectedMinSdkVersion: "Q", - }, - { - name: "current final SDK", - sdkVersion: "current", - platformSdkInt: 29, - platformSdkCodename: "Q", - platformSdkFinal: false, deviceCurrentApiLevelForVendorModules: "28", expectedMinSdkVersion: "28", }, diff --git a/java/droiddoc.go b/java/droiddoc.go index 85a61dd98..33f422d4e 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -253,6 +253,10 @@ type DroidstubsProperties struct { // if set to true, allow Metalava to generate doc_stubs source files. Defaults to false. Create_doc_stubs *bool + // if set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false. + // Has no effect if create_doc_stubs: true. + Output_javadoc_comments *bool + // if set to false then do not write out stubs. Defaults to true. // // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately. @@ -1150,7 +1154,9 @@ func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuil cmd.FlagWithArg("--doc-stubs ", stubsDir.String()) } else { cmd.FlagWithArg("--stubs ", stubsDir.String()) - cmd.Flag("--exclude-documentation-from-stubs") + if !Bool(d.properties.Output_javadoc_comments) { + cmd.Flag("--exclude-documentation-from-stubs") + } } } } @@ -1228,7 +1234,7 @@ func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *a cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml) cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml) - cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion()) + cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion().String()) cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename()) filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar") @@ -1412,9 +1418,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { // TODO(b/154317059): Clean up this whitelist by baselining and/or checking in last-released. if d.Name() != "android.car-system-stubs-docs" && - d.Name() != "android.car-stubs-docs" && - d.Name() != "system-api-stubs-docs" && - d.Name() != "test-api-stubs-docs" { + d.Name() != "android.car-stubs-docs" { cmd.Flag("--lints-as-errors") cmd.Flag("--warnings-as-errors") // Most lints are actually warnings. } diff --git a/java/java.go b/java/java.go index d67e9e098..1d7eaa771 100644 --- a/java/java.go +++ b/java/java.go @@ -1658,7 +1658,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { if v := sdkSpec.version; v.isNumbered() { return v.String() } else { - return ctx.Config().DefaultAppTargetSdk() + return ctx.Config().DefaultAppTargetSdk(ctx).String() } } @@ -1876,7 +1876,8 @@ func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu return j.depIsInSameApex(ctx, dep) } -func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { +func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, + sdkVersion android.ApiLevel) error { sdkSpec := j.minSdkVersion() if !sdkSpec.specified() { return fmt.Errorf("min_sdk_version is not specified") @@ -1888,7 +1889,7 @@ func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersi if err != nil { return err } - if int(ver) > sdkVersion { + if ver.ApiLevel(ctx).GreaterThan(sdkVersion) { return fmt.Errorf("newer SDK(%v)", ver) } return nil @@ -2753,7 +2754,8 @@ func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu return j.depIsInSameApex(ctx, dep) } -func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { +func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext, + sdkVersion android.ApiLevel) error { // Do not check for prebuilts against the min_sdk_version of enclosing APEX return nil } @@ -2936,7 +2938,8 @@ func (j *DexImport) DexJarBuildPath() android.Path { return j.dexJarFile } -func (j *DexImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { +func (j *DexImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, + sdkVersion android.ApiLevel) error { // we don't check prebuilt modules for sdk_version return nil } diff --git a/java/sdk.go b/java/sdk.go index 56fa12b3e..f59926502 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -107,7 +107,7 @@ type sdkVersion int const ( // special version number for a not-yet-frozen SDK - sdkVersionCurrent sdkVersion = sdkVersion(android.FutureApiLevel) + sdkVersionCurrent sdkVersion = sdkVersion(android.FutureApiLevelInt) // special version number to be used for SDK specs where version number doesn't // make sense, e.g. "none", "", etc. sdkVersionNone sdkVersion = sdkVersion(0) @@ -133,6 +133,10 @@ func (v sdkVersion) String() string { return "(no version)" } +func (v sdkVersion) ApiLevel(ctx android.EarlyModuleContext) android.ApiLevel { + return android.ApiLevelOrPanic(ctx, v.String()) +} + // asNumberString directly converts the numeric value of this sdk version as a string. // When isNumbered() is true, this method is the same as String(). However, for sdkVersionCurrent // and sdkVersionNone, this returns 10000 and 0 while String() returns "current" and "(no version"), @@ -243,7 +247,7 @@ func (s sdkSpec) effectiveVersion(ctx android.EarlyModuleContext) (sdkVersion, e if s.version.isNumbered() { return s.version, nil } - return sdkVersion(ctx.Config().DefaultAppTargetSdkInt()), nil + return sdkVersion(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt()), nil } // effectiveVersionString converts an sdkSpec into the concrete version string that the module @@ -251,8 +255,8 @@ func (s sdkSpec) effectiveVersion(ctx android.EarlyModuleContext) (sdkVersion, e // it returns the codename (P, Q, R, etc.) func (s sdkSpec) effectiveVersionString(ctx android.EarlyModuleContext) (string, error) { ver, err := s.effectiveVersion(ctx) - if err == nil && int(ver) == ctx.Config().DefaultAppTargetSdkInt() { - return ctx.Config().DefaultAppTargetSdk(), nil + if err == nil && int(ver) == ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt() { + return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil } return ver.String(), err } diff --git a/java/sdk_library.go b/java/sdk_library.go index 1a5ef544c..0d29a3763 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -1203,6 +1203,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC Sdk_version *string System_modules *string Libs []string + Output_javadoc_comments *bool Arg_files []string Args *string Java_version *string @@ -1278,6 +1279,11 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC } droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide ")) + // Output Javadoc comments for public scope. + if apiScope == apiScopePublic { + props.Output_javadoc_comments = proptools.BoolPtr(true) + } + // Add in scope specific arguments. droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...) props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files @@ -1878,7 +1884,8 @@ func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, return false } -func (module *SdkLibraryImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { +func (module *SdkLibraryImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, + sdkVersion android.ApiLevel) error { // we don't check prebuilt modules for sdk_version return nil } @@ -2078,7 +2085,8 @@ func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) { // do nothing } -func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { +func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext, + sdkVersion android.ApiLevel) error { // sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked return nil } diff --git a/python/binary.go b/python/binary.go index 5a7492648..1d2400efd 100644 --- a/python/binary.go +++ b/python/binary.go @@ -79,7 +79,7 @@ func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { } func PythonBinaryHostFactory() android.Module { - module, _ := NewBinary(android.HostSupportedNoCross) + module, _ := NewBinary(android.HostSupported) return module.Init() } diff --git a/python/library.go b/python/library.go index 65c1352e7..0c8d61313 100644 --- a/python/library.go +++ b/python/library.go @@ -26,7 +26,7 @@ func init() { } func PythonLibraryHostFactory() android.Module { - module := newModule(android.HostSupportedNoCross, android.MultilibFirst) + module := newModule(android.HostSupported, android.MultilibFirst) return module.Init() } diff --git a/rust/binary.go b/rust/binary.go index 1d02453db..e95cb3afc 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -24,6 +24,10 @@ func init() { } type BinaryCompilerProperties struct { + // Change the rustlibs linkage to select rlib linkage by default for device targets. + // Also link libstd as an rlib as well on device targets. + // Note: This is the default behavior for host targets. + Prefer_rlib *bool `android:"arch_variant"` } type binaryDecorator struct { @@ -131,9 +135,16 @@ func (binary *binaryDecorator) coverageOutputZipPath() android.OptionalPath { func (binary *binaryDecorator) autoDep(ctx BaseModuleContext) autoDep { // Binaries default to dylib dependencies for device, rlib for host. + if Bool(binary.Properties.Prefer_rlib) { + return rlibAutoDep + } if ctx.Device() { return dylibAutoDep } else { return rlibAutoDep } } + +func (binary *binaryDecorator) staticStd(ctx *depsContext) bool { + return binary.baseCompiler.staticStd(ctx) || Bool(binary.Properties.Prefer_rlib) +} diff --git a/rust/binary_test.go b/rust/binary_test.go index 394abfcdd..f31a7fcda 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -30,6 +30,13 @@ func TestBinaryLinkage(t *testing.T) { rustlibs: ["libfoo"], host_supported: true, } + rust_binary { + name: "rlib_linked", + srcs: ["foo.rs"], + rustlibs: ["libfoo"], + host_supported: true, + prefer_rlib: true, + } rust_library { name: "libfoo", srcs: ["foo.rs"], @@ -49,6 +56,34 @@ func TestBinaryLinkage(t *testing.T) { } } +// Test that prefer_rlib links in libstd statically as well as rustlibs. +func TestBinaryPreferRlib(t *testing.T) { + ctx := testRust(t, ` + rust_binary { + name: "rlib_linked", + srcs: ["foo.rs"], + rustlibs: ["libfoo"], + host_supported: true, + prefer_rlib: true, + } + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + host_supported: true, + }`) + + mod := ctx.ModuleForTests("rlib_linked", "android_arm64_armv8-a").Module().(*Module) + + if !android.InList("libfoo.rlib-std", mod.Properties.AndroidMkRlibs) { + t.Errorf("rustlibs dependency libfoo should be an rlib dep when prefer_rlib is defined") + } + + if !android.InList("libstd", mod.Properties.AndroidMkRlibs) { + t.Errorf("libstd dependency should be an rlib dep when prefer_rlib is defined") + } +} + // Test that the path returned by HostToolPath is correct func TestHostToolPath(t *testing.T) { ctx := testRust(t, ` diff --git a/rust/bindgen.go b/rust/bindgen.go index cafdb8bfa..d8d126d37 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -21,6 +21,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + cc_config "android/soong/cc/config" ) var ( @@ -56,7 +57,11 @@ func init() { var _ SourceProvider = (*bindgenDecorator)(nil) type BindgenProperties struct { - // The wrapper header file + // The wrapper header file. By default this is assumed to be a C header unless the extension is ".hh" or ".hpp". + // This is used to specify how to interpret the header and determines which '-std' flag to use by default. + // + // If your C++ header must have some other extension, then the default behavior can be overridden by setting the + // cpp_std property. Wrapper_src *string `android:"path,arch_variant"` // list of bindgen-specific flags and options @@ -81,6 +86,22 @@ type BindgenProperties struct { // "my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]" Custom_bindgen string `android:"path"` + // C standard version to use. Can be a specific version (such as "gnu11"), + // "experimental" (which will use draft versions like C1x when available), + // or the empty string (which will use the default). + // + // If this is set, the file extension will be ignored and this will be used as the std version value. Setting this + // to "default" will use the build system default version. This cannot be set at the same time as cpp_std. + C_std *string + + // C++ standard version to use. Can be a specific version (such as + // "gnu++11"), "experimental" (which will use draft versions like C++1z when + // available), or the empty string (which will use the default). + // + // If this is set, the file extension will be ignored and this will be used as the std version value. Setting this + // to "default" will use the build system default version. This cannot be set at the same time as c_std. + Cpp_std *string + //TODO(b/161141999) Add support for headers from cc_library_header modules. } @@ -90,6 +111,45 @@ type bindgenDecorator struct { Properties BindgenProperties } +func (b *bindgenDecorator) getStdVersion(ctx ModuleContext, src android.Path) (string, bool) { + // Assume headers are C headers + isCpp := false + stdVersion := "" + + switch src.Ext() { + case ".hpp", ".hh": + isCpp = true + } + + if String(b.Properties.Cpp_std) != "" && String(b.Properties.C_std) != "" { + ctx.PropertyErrorf("c_std", "c_std and cpp_std cannot both be defined at the same time.") + } + + if String(b.Properties.Cpp_std) != "" { + if String(b.Properties.Cpp_std) == "experimental" { + stdVersion = cc_config.ExperimentalCppStdVersion + } else if String(b.Properties.Cpp_std) == "default" { + stdVersion = cc_config.CppStdVersion + } else { + stdVersion = String(b.Properties.Cpp_std) + } + } else if b.Properties.C_std != nil { + if String(b.Properties.C_std) == "experimental" { + stdVersion = cc_config.ExperimentalCStdVersion + } else if String(b.Properties.C_std) == "default" { + stdVersion = cc_config.CStdVersion + } else { + stdVersion = String(b.Properties.C_std) + } + } else if isCpp { + stdVersion = cc_config.CppStdVersion + } else { + stdVersion = cc_config.CStdVersion + } + + return stdVersion, isCpp +} + func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path { ccToolchain := ctx.RustModule().ccToolchain(ctx) @@ -134,6 +194,17 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source") } + // Add C std version flag + stdVersion, isCpp := b.getStdVersion(ctx, wrapperFile.Path()) + cflags = append(cflags, "-std="+stdVersion) + + // Specify the header source language to avoid ambiguity. + if isCpp { + cflags = append(cflags, "-x c++") + } else { + cflags = append(cflags, "-x c") + } + outputFile := android.PathForModuleOut(ctx, b.BaseSourceProvider.getStem(ctx)+".rs") var cmd, cmdDesc string @@ -169,7 +240,9 @@ func (b *bindgenDecorator) SourceProviderProps() []interface{} { // rust_bindgen generates Rust FFI bindings to C libraries using bindgen given a wrapper header as the primary input. // Bindgen has a number of flags to control the generated source, and additional flags can be passed to clang to ensure -// the header and generated source is appropriately handled. +// the header and generated source is appropriately handled. It is recommended to add it as a dependency in the +// rlibs, dylibs or rustlibs property. It may also be added in the srcs property for external crates, using the ":" +// prefix. func RustBindgenFactory() android.Module { module, _ := NewRustBindgen(android.HostAndDeviceSupported) return module.Init() diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go index 191da9b11..e69bce24d 100644 --- a/rust/bindgen_test.go +++ b/rust/bindgen_test.go @@ -41,7 +41,7 @@ func TestRustBindgen(t *testing.T) { export_include_dirs: ["static_include"], } `) - libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a").Output("bindings.rs") + libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") // Ensure that the flags are present and escaped if !strings.Contains(libbindgen.Args["flags"], "'--bindgen-flag.*'") { t.Errorf("missing bindgen flags in rust_bindgen rule: flags %#v", libbindgen.Args["flags"]) @@ -73,7 +73,7 @@ func TestRustBindgenCustomBindgen(t *testing.T) { } `) - libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a").Output("bindings.rs") + libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") // The rule description should contain the custom binary name rather than bindgen, so checking the description // should be sufficient. @@ -82,3 +82,47 @@ func TestRustBindgenCustomBindgen(t *testing.T) { libbindgen.Description) } } + +func TestRustBindgenStdVersions(t *testing.T) { + testRustError(t, "c_std and cpp_std cannot both be defined at the same time.", ` + rust_bindgen { + name: "libbindgen", + wrapper_src: "src/any.h", + crate_name: "bindgen", + stem: "libbindgen", + source_stem: "bindings", + c_std: "somevalue", + cpp_std: "somevalue", + } + `) + + ctx := testRust(t, ` + rust_bindgen { + name: "libbindgen_cstd", + wrapper_src: "src/any.h", + crate_name: "bindgen", + stem: "libbindgen", + source_stem: "bindings", + c_std: "foo" + } + rust_bindgen { + name: "libbindgen_cppstd", + wrapper_src: "src/any.h", + crate_name: "bindgen", + stem: "libbindgen", + source_stem: "bindings", + cpp_std: "foo" + } + `) + + libbindgen_cstd := ctx.ModuleForTests("libbindgen_cstd", "android_arm64_armv8-a_source").Output("bindings.rs") + libbindgen_cppstd := ctx.ModuleForTests("libbindgen_cppstd", "android_arm64_armv8-a_source").Output("bindings.rs") + + if !strings.Contains(libbindgen_cstd.Args["cflags"], "-std=foo") { + t.Errorf("c_std value not passed in to rust_bindgen as a clang flag") + } + + if !strings.Contains(libbindgen_cppstd.Args["cflags"], "-std=foo") { + t.Errorf("cpp_std value not passed in to rust_bindgen as a clang flag") + } +} diff --git a/rust/config/arm_device.go b/rust/config/arm_device.go index ac4f1c659..adfe917a1 100644 --- a/rust/config/arm_device.go +++ b/rust/config/arm_device.go @@ -52,7 +52,7 @@ type toolchainArm struct { } func (t *toolchainArm) RustTriple() string { - return "arm-linux-androideabi" + return "armv7-linux-androideabi" } func (t *toolchainArm) ToolchainLinkFlags() string { diff --git a/rust/library.go b/rust/library.go index 4931f1995..2792c5b4a 100644 --- a/rust/library.go +++ b/rust/library.go @@ -15,6 +15,7 @@ package rust import ( + "fmt" "regexp" "strings" @@ -77,6 +78,8 @@ type LibraryMutatedProperties struct { VariantIsShared bool `blueprint:"mutated"` // This variant is a static library VariantIsStatic bool `blueprint:"mutated"` + // This variant is a source provider + VariantIsSource bool `blueprint:"mutated"` // This variant is disabled and should not be compiled // (used for SourceProvider variants that produce only source) @@ -103,6 +106,7 @@ type libraryInterface interface { static() bool shared() bool sysroot() bool + source() bool // Returns true if the build options for the module have selected a particular build type buildRlib() bool @@ -115,6 +119,7 @@ type libraryInterface interface { setDylib() setShared() setStatic() + setSource() // Set libstd linkage setRlibStd() @@ -158,6 +163,10 @@ func (library *libraryDecorator) staticStd(ctx *depsContext) bool { return library.static() || library.MutatedProperties.VariantIsStaticStd } +func (library *libraryDecorator) source() bool { + return library.MutatedProperties.VariantIsSource +} + func (library *libraryDecorator) buildRlib() bool { return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true) } @@ -210,13 +219,17 @@ func (library *libraryDecorator) setStatic() { library.MutatedProperties.VariantIsDylib = false } +func (library *libraryDecorator) setSource() { + library.MutatedProperties.VariantIsSource = true +} + func (library *libraryDecorator) autoDep(ctx BaseModuleContext) autoDep { if library.rlib() || library.static() { return rlibAutoDep } else if library.dylib() || library.shared() { return dylibAutoDep } else { - panic("autoDep called on library" + ctx.ModuleName() + "that has no enabled variants.") + panic(fmt.Errorf("autoDep called on library %q that has no enabled variants.", ctx.ModuleName())) } } @@ -518,40 +531,67 @@ func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name stri } } +// LibraryMutator mutates the libraries into variants according to the +// build{Rlib,Dylib} attributes. func LibraryMutator(mctx android.BottomUpMutatorContext) { - if m, ok := mctx.Module().(*Module); ok && m.compiler != nil { - switch library := m.compiler.(type) { - case libraryInterface: - if library.buildRlib() && library.buildDylib() { - variants := []string{"rlib", "dylib"} - if m.sourceProvider != nil { - variants = append(variants, "") - } - modules := mctx.CreateLocalVariations(variants...) + // Only mutate on Rust libraries. + m, ok := mctx.Module().(*Module) + if !ok || m.compiler == nil { + return + } + library, ok := m.compiler.(libraryInterface) + if !ok { + return + } - rlib := modules[0].(*Module) - dylib := modules[1].(*Module) - rlib.compiler.(libraryInterface).setRlib() - dylib.compiler.(libraryInterface).setDylib() - if m.sourceProvider != nil { - // This library is SourceProvider generated, so the non-library-producing - // variant needs to disable it's compiler and skip installation. - sourceProvider := modules[2].(*Module) - sourceProvider.compiler.SetDisabled() - } - } else if library.buildRlib() { - modules := mctx.CreateLocalVariations("rlib") - modules[0].(*Module).compiler.(libraryInterface).setRlib() - } else if library.buildDylib() { - modules := mctx.CreateLocalVariations("dylib") - modules[0].(*Module).compiler.(libraryInterface).setDylib() - } + var variants []string + // The source variant is used for SourceProvider modules. The other variants (i.e. rlib and dylib) + // depend on this variant. It must be the first variant to be declared. + sourceVariant := false + if m.sourceProvider != nil { + variants = append(variants, "source") + sourceVariant = true + } + if library.buildRlib() { + variants = append(variants, rlibVariation) + } + if library.buildDylib() { + variants = append(variants, dylibVariation) + } + + if len(variants) == 0 { + return + } + modules := mctx.CreateLocalVariations(variants...) + + // The order of the variations (modules) matches the variant names provided. Iterate + // through the new variation modules and set their mutated properties. + for i, v := range modules { + switch variants[i] { + case rlibVariation: + v.(*Module).compiler.(libraryInterface).setRlib() + case dylibVariation: + v.(*Module).compiler.(libraryInterface).setDylib() + case "source": + v.(*Module).compiler.(libraryInterface).setSource() + // The source variant does not produce any library. + // Disable the compilation steps. + v.(*Module).compiler.SetDisabled() + } + } - if m.sourceProvider != nil { - // Alias the non-library variant to the empty-string variant. - mctx.AliasVariation("") + // If a source variant is created, add an inter-variant dependency + // between the other variants and the source variant. + if sourceVariant { + sv := modules[0] + for _, v := range modules[1:] { + if !v.Enabled() { + continue } + mctx.AddInterVariantDependency(sourceDepTag, v, sv) } + // Alias the source variation so it can be named directly in "srcs" properties. + mctx.AliasVariation("source") } } diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go index a9dbf397d..bd11a5ae3 100644 --- a/rust/protobuf_test.go +++ b/rust/protobuf_test.go @@ -29,7 +29,7 @@ func TestRustProtobuf(t *testing.T) { } `) // Check that there's a rule to generate the expected output - _ = ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Output("buf.rs") + _ = ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("buf.rs") // Check that libprotobuf is added as a dependency. librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module) diff --git a/rust/rust.go b/rust/rust.go index d22acea4a..1f8b904d3 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -87,8 +87,7 @@ type Module struct { sourceProvider SourceProvider subAndroidMkOnce map[SubAndroidMkProvider]bool - outputFile android.OptionalPath - generatedFile android.OptionalPath + outputFile android.OptionalPath } func (mod *Module) OutputFiles(tag string) (android.Paths, error) { @@ -687,12 +686,25 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { flags, deps = mod.clippy.flags(ctx, flags, deps) } - // SourceProvider needs to call GenerateSource() before compiler calls compile() so it can provide the source. - // TODO(b/162588681) This shouldn't have to run for every variant. + // SourceProvider needs to call GenerateSource() before compiler calls + // compile() so it can provide the source. A SourceProvider has + // multiple variants (e.g. source, rlib, dylib). Only the "source" + // variant is responsible for effectively generating the source. The + // remaining variants relies on the "source" variant output. if mod.sourceProvider != nil { - generatedFile := mod.sourceProvider.GenerateSource(ctx, deps) - mod.generatedFile = android.OptionalPathForPath(generatedFile) - mod.sourceProvider.setSubName(ctx.ModuleSubDir()) + if mod.compiler.(libraryInterface).source() { + mod.sourceProvider.GenerateSource(ctx, deps) + mod.sourceProvider.setSubName(ctx.ModuleSubDir()) + if lib, ok := mod.compiler.(*libraryDecorator); ok { + lib.flagExporter.linkDirs = nil + lib.flagExporter.linkObjects = nil + lib.flagExporter.depFlags = nil + } + } else { + sourceMod := actx.GetDirectDepWithTag(mod.Name(), sourceDepTag) + sourceLib := sourceMod.(*Module).compiler.(*libraryDecorator) + mod.sourceProvider.setOutputFile(sourceLib.sourceProvider.Srcs()[0]) + } } if mod.compiler != nil && !mod.compiler.Disabled() { @@ -743,6 +755,7 @@ var ( dylibDepTag = dependencyTag{name: "dylib", library: true} procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true} testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"} + sourceDepTag = dependencyTag{name: "source"} ) type autoDep struct { @@ -751,8 +764,10 @@ type autoDep struct { } var ( - rlibAutoDep = autoDep{variation: "rlib", depTag: rlibDepTag} - dylibAutoDep = autoDep{variation: "dylib", depTag: dylibDepTag} + rlibVariation = "rlib" + dylibVariation = "dylib" + rlibAutoDep = autoDep{variation: rlibVariation, depTag: rlibDepTag} + dylibAutoDep = autoDep{variation: dylibVariation, depTag: dylibDepTag} ) type autoDeppable interface { @@ -1000,11 +1015,11 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { actx.AddVariationDependencies( append(rlibDepVariations, []blueprint.Variation{ - {Mutator: "rust_libraries", Variation: "rlib"}}...), + {Mutator: "rust_libraries", Variation: rlibVariation}}...), rlibDepTag, deps.Rlibs...) actx.AddVariationDependencies( append(commonDepVariations, []blueprint.Variation{ - {Mutator: "rust_libraries", Variation: "dylib"}}...), + {Mutator: "rust_libraries", Variation: dylibVariation}}...), dylibDepTag, deps.Dylibs...) if deps.Rustlibs != nil && !mod.compiler.Disabled() { diff --git a/rust/source_provider.go b/rust/source_provider.go index 755a369a7..03adf9e6f 100644 --- a/rust/source_provider.go +++ b/rust/source_provider.go @@ -43,6 +43,7 @@ type SourceProvider interface { SourceProviderProps() []interface{} SourceProviderDeps(ctx DepsContext, deps Deps) Deps setSubName(subName string) + setOutputFile(outputFile android.Path) } func (sp *BaseSourceProvider) Srcs() android.Paths { @@ -95,3 +96,7 @@ func (sp *BaseSourceProvider) SourceProviderDeps(ctx DepsContext, deps Deps) Dep func (sp *BaseSourceProvider) setSubName(subName string) { sp.subName = subName } + +func (sp *BaseSourceProvider) setOutputFile(outputFile android.Path) { + sp.OutputFile = outputFile +} diff --git a/sdk/testing.go b/sdk/testing.go index 68058ee0b..ae1e44888 100644 --- a/sdk/testing.go +++ b/sdk/testing.go @@ -68,14 +68,14 @@ func testSdkContext(bp string, fs map[string][]byte, extraOsTypes []android.OsTy // Add windows as a default disable OS to test behavior when some OS variants // are disabled. config.Targets[android.Windows] = []android.Target{ - {android.Windows, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", ""}, + {android.Windows, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", "", true}, } for _, extraOsType := range extraOsTypes { switch extraOsType { case android.LinuxBionic: config.Targets[android.LinuxBionic] = []android.Target{ - {android.LinuxBionic, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", ""}, + {android.LinuxBionic, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", "", false}, } } } @@ -89,7 +89,7 @@ func testSdkContext(bp string, fs map[string][]byte, extraOsTypes []android.OsTy android.RegisterAndroidMkBuildComponents(ctx) android.SetInMakeForTests(config) config.Targets[android.CommonOS] = []android.Target{ - {android.CommonOS, android.Arch{ArchType: android.Common}, android.NativeBridgeDisabled, "", ""}, + {android.CommonOS, android.Arch{ArchType: android.Common}, android.NativeBridgeDisabled, "", "", true}, } // from android package diff --git a/sdk/update.go b/sdk/update.go index 65baa5ed6..a10e8523c 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -371,8 +371,7 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) andro osPropertySet := targetPropertySet.AddPropertySet(sdkVariant.Target().Os.Name) // Enable the variant explicitly when we've disabled it by default on host. - if hasHostOsDependentMember && - (osType.Class == android.Host || osType.Class == android.HostCross) { + if hasHostOsDependentMember && osType.Class == android.Host { osPropertySet.AddProperty("enabled", true) } @@ -731,7 +730,7 @@ func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType for _, variant := range member.Variants() { osClass := variant.Target().Os.Class - if osClass == android.Host || osClass == android.HostCross { + if osClass == android.Host { hostSupported = true } else if osClass == android.Device { deviceSupported = true @@ -1061,8 +1060,7 @@ func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule archPropertySet = targetPropertySet // Enable the variant explicitly when we've disabled it by default on host. - if ctx.memberType.IsHostOsDependent() && - (osType.Class == android.Host || osType.Class == android.HostCross) { + if ctx.memberType.IsHostOsDependent() && osType.Class == android.Host { osPropertySet.AddProperty("enabled", true) } @@ -1086,7 +1084,7 @@ func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule func (osInfo *osTypeSpecificInfo) isHostVariant() bool { osClass := osInfo.osType.Class - return osClass == android.Host || osClass == android.HostCross + return osClass == android.Host } var _ isHostVariant = (*osTypeSpecificInfo)(nil) @@ -1323,7 +1321,7 @@ func (s *sdk) getPossibleOsTypes() []android.OsType { } } if s.HostSupported() { - if osType.Class == android.Host || osType.Class == android.HostCross { + if osType.Class == android.Host { osTypes = append(osTypes, osType) } } diff --git a/sh/sh_binary.go b/sh/sh_binary.go index f3f4a4aa7..7c3cdbdbb 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -313,6 +313,15 @@ func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { options := []tradefed.Option{{Name: "force-root", Value: "false"}} configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options}) } + if len(s.testProperties.Data_device_bins) > 0 { + moduleName := s.Name() + remoteDir := "/data/local/tests/unrestricted/" + moduleName + "/" + options := []tradefed.Option{{Name: "cleanup", Value: "true"}} + for _, bin := range s.testProperties.Data_device_bins { + options = append(options, tradefed.Option{Name: "push-file", Key: bin, Value: remoteDir + bin}) + } + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.PushFilePreparer", options}) + } s.testConfig = tradefed.AutoGenShellTestConfig(ctx, s.testProperties.Test_config, s.testProperties.Test_config_template, s.testProperties.Test_suites, configs, s.testProperties.Auto_gen_config, s.outputFilePath.Base()) diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index 768c8e5b0..480f9b797 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -310,7 +310,8 @@ func (m *syspropLibrary) AndroidMk() android.AndroidMkData { }} } -func (m *syspropLibrary) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { +func (m *syspropLibrary) ShouldSupportSdkVersion(ctx android.BaseModuleContext, + sdkVersion android.ApiLevel) error { return fmt.Errorf("sysprop_library is not supposed to be part of apex modules") } diff --git a/ui/build/config.go b/ui/build/config.go index 9bd087796..fe74ace39 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -298,8 +298,9 @@ func storeConfigMetrics(ctx Context, config Config) { } b := &smpb.BuildConfig{ - UseGoma: proto.Bool(config.UseGoma()), - UseRbe: proto.Bool(config.UseRBE()), + ForceUseGoma: proto.Bool(config.ForceUseGoma()), + UseGoma: proto.Bool(config.UseGoma()), + UseRbe: proto.Bool(config.UseRBE()), } ctx.Metrics.BuildConfig(b) } @@ -851,6 +852,11 @@ func (c *configImpl) StartRBE() bool { } func (c *configImpl) logDir() string { + for _, f := range []string{"RBE_log_dir", "FLAG_log_dir"} { + if v, ok := c.environ.Get(f); ok { + return v + } + } if c.Dist() { return filepath.Join(c.DistDir(), "logs") } diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go index d7c53ec2b..05efe132d 100644 --- a/ui/metrics/metrics_proto/metrics.pb.go +++ b/ui/metrics/metrics_proto/metrics.pb.go @@ -399,6 +399,7 @@ func (m *MetricsBase) GetBuildConfig() *BuildConfig { type BuildConfig struct { UseGoma *bool `protobuf:"varint,1,opt,name=use_goma,json=useGoma" json:"use_goma,omitempty"` UseRbe *bool `protobuf:"varint,2,opt,name=use_rbe,json=useRbe" json:"use_rbe,omitempty"` + ForceUseGoma *bool `protobuf:"varint,3,opt,name=force_use_goma,json=forceUseGoma" json:"force_use_goma,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -443,6 +444,13 @@ func (m *BuildConfig) GetUseRbe() bool { return false } +func (m *BuildConfig) GetForceUseGoma() bool { + if m != nil && m.ForceUseGoma != nil { + return *m.ForceUseGoma + } + return false +} + type PerfInfo struct { // The description for the phase/action/part while the tool running. Desc *string `protobuf:"bytes,1,opt,name=desc" json:"desc,omitempty"` @@ -764,69 +772,70 @@ func init() { } var fileDescriptor_6039342a2ba47b72 = []byte{ - // 1021 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xef, 0x6e, 0xdb, 0x36, - 0x10, 0xaf, 0x12, 0x27, 0xb6, 0x4e, 0xb1, 0xab, 0x30, 0xed, 0xa2, 0xb6, 0x08, 0x66, 0x18, 0x6b, - 0x11, 0x0c, 0x6b, 0x5a, 0x64, 0x45, 0x50, 0x04, 0xc5, 0x00, 0xc7, 0x09, 0xb2, 0x2e, 0x48, 0x5c, - 0x30, 0x7f, 0x56, 0x6c, 0x1f, 0x04, 0x5a, 0xa2, 0x13, 0x75, 0x96, 0x28, 0x90, 0x54, 0x91, 0xf4, - 0x1d, 0xf6, 0x54, 0x7b, 0x96, 0xbd, 0xc6, 0x30, 0xf0, 0x28, 0xd9, 0xca, 0xe6, 0xad, 0x41, 0xbf, - 0x89, 0xf7, 0xfb, 0xc3, 0x3b, 0xf2, 0x78, 0x36, 0xb4, 0x53, 0xae, 0x65, 0x12, 0xa9, 0xad, 0x5c, - 0x0a, 0x2d, 0xc8, 0x9a, 0x12, 0x22, 0xbb, 0x0c, 0x47, 0x45, 0x32, 0x89, 0xc3, 0x12, 0xea, 0xfd, - 0x05, 0xe0, 0x1d, 0xdb, 0xef, 0x3d, 0xa6, 0x38, 0x79, 0x09, 0x0f, 0x2c, 0x21, 0x66, 0x9a, 0x87, - 0x3a, 0x49, 0xb9, 0xd2, 0x2c, 0xcd, 0x03, 0xa7, 0xeb, 0x6c, 0x2e, 0x52, 0x82, 0xd8, 0x3e, 0xd3, - 0xfc, 0xac, 0x42, 0xc8, 0x23, 0x68, 0x59, 0x45, 0x12, 0x07, 0x0b, 0x5d, 0x67, 0xd3, 0xa5, 0x4d, - 0x5c, 0xbf, 0x8d, 0xc9, 0x2e, 0x3c, 0xca, 0x27, 0x4c, 0x8f, 0x85, 0x4c, 0xc3, 0x8f, 0x5c, 0xaa, - 0x44, 0x64, 0x61, 0x24, 0x62, 0x9e, 0xb1, 0x94, 0x07, 0x8b, 0xc8, 0x5d, 0xaf, 0x08, 0x17, 0x16, - 0x1f, 0x94, 0x30, 0x79, 0x0a, 0x1d, 0xcd, 0xe4, 0x25, 0xd7, 0x61, 0x2e, 0x45, 0x5c, 0x44, 0x3a, - 0x68, 0xa0, 0xa0, 0x6d, 0xa3, 0xef, 0x6c, 0x90, 0xc4, 0xf0, 0xa0, 0xa4, 0xd9, 0x24, 0x3e, 0x32, - 0x99, 0xb0, 0x4c, 0x07, 0x4b, 0x5d, 0x67, 0xb3, 0xb3, 0xfd, 0x7c, 0x6b, 0x4e, 0xcd, 0x5b, 0xb5, - 0x7a, 0xb7, 0xf6, 0x0c, 0x72, 0x61, 0x45, 0xbb, 0x8b, 0x07, 0x27, 0x87, 0x94, 0x58, 0xbf, 0x3a, - 0x40, 0x86, 0xe0, 0x95, 0xbb, 0x30, 0x19, 0x5d, 0x05, 0xcb, 0x68, 0xfe, 0xf4, 0xb3, 0xe6, 0x7d, - 0x19, 0x5d, 0xed, 0x36, 0xcf, 0x4f, 0x8e, 0x4e, 0x86, 0x3f, 0x9f, 0x50, 0xb0, 0x16, 0x26, 0x48, - 0xb6, 0x60, 0xad, 0x66, 0x38, 0xcd, 0xba, 0x89, 0x25, 0xae, 0xce, 0x88, 0x55, 0x02, 0xdf, 0x41, - 0x99, 0x56, 0x18, 0xe5, 0xc5, 0x94, 0xde, 0x42, 0xba, 0x6f, 0x91, 0x41, 0x5e, 0x54, 0xec, 0x23, - 0x70, 0xaf, 0x84, 0x2a, 0x93, 0x75, 0xbf, 0x28, 0xd9, 0x96, 0x31, 0xc0, 0x54, 0x29, 0xb4, 0xd1, - 0x6c, 0x3b, 0x8b, 0xad, 0x21, 0x7c, 0x91, 0xa1, 0x67, 0x4c, 0xb6, 0xb3, 0x18, 0x3d, 0xd7, 0xa1, - 0x89, 0x9e, 0x42, 0x05, 0x1e, 0xd6, 0xb0, 0x6c, 0x96, 0x43, 0x45, 0x7a, 0xe5, 0x66, 0x42, 0x85, - 0xfc, 0x5a, 0x4b, 0x16, 0xac, 0x20, 0xec, 0x59, 0xf8, 0xc0, 0x84, 0xa6, 0x9c, 0x48, 0x0a, 0xa5, - 0x8c, 0x45, 0x7b, 0xc6, 0x19, 0x98, 0xd8, 0x50, 0x91, 0x67, 0x70, 0xbf, 0xc6, 0xc1, 0xb4, 0x3b, - 0xb6, 0x7d, 0xa6, 0x2c, 0x4c, 0xe4, 0x39, 0xac, 0xd5, 0x78, 0xd3, 0x12, 0xef, 0xdb, 0x83, 0x9d, - 0x72, 0x6b, 0x79, 0x8b, 0x42, 0x87, 0x71, 0x22, 0x03, 0xdf, 0xe6, 0x2d, 0x0a, 0xbd, 0x9f, 0x48, - 0xf2, 0x03, 0x78, 0x8a, 0xeb, 0x22, 0x0f, 0xb5, 0x10, 0x13, 0x15, 0xac, 0x76, 0x17, 0x37, 0xbd, - 0xed, 0x8d, 0xb9, 0x47, 0xf4, 0x8e, 0xcb, 0xf1, 0xdb, 0x6c, 0x2c, 0x28, 0xa0, 0xe2, 0xcc, 0x08, - 0xc8, 0x2e, 0xb8, 0xbf, 0x31, 0x9d, 0x84, 0xb2, 0xc8, 0x54, 0x40, 0xee, 0xa2, 0x6e, 0x19, 0x3e, - 0x2d, 0x32, 0x45, 0xde, 0x00, 0x58, 0x26, 0x8a, 0xd7, 0xee, 0x22, 0x76, 0x11, 0xad, 0xd4, 0x59, - 0x92, 0x7d, 0x60, 0x56, 0xfd, 0xe0, 0x4e, 0x6a, 0x14, 0xa0, 0xfa, 0x7b, 0x58, 0xd2, 0x42, 0xb3, - 0x49, 0xf0, 0xb0, 0xeb, 0x7c, 0x5e, 0x68, 0xb9, 0xe4, 0x02, 0xe6, 0x8d, 0xa2, 0xe0, 0x2b, 0xb4, - 0x78, 0x36, 0xd7, 0xe2, 0xd4, 0xc4, 0xf0, 0x49, 0x96, 0x1d, 0x46, 0x57, 0xd5, 0x3f, 0x43, 0x64, - 0x00, 0x2b, 0x56, 0x15, 0x89, 0x6c, 0x9c, 0x5c, 0x06, 0xeb, 0x68, 0xd8, 0x9d, 0x6b, 0x88, 0xc2, - 0x01, 0xf2, 0xa8, 0x37, 0x9a, 0x2d, 0x7a, 0x2f, 0x61, 0xe5, 0xd6, 0xd3, 0x6f, 0x41, 0xe3, 0xfc, - 0xf4, 0x80, 0xfa, 0xf7, 0x48, 0x1b, 0x5c, 0xf3, 0xb5, 0x7f, 0xb0, 0x77, 0x7e, 0xe8, 0x3b, 0xa4, - 0x09, 0x66, 0x5c, 0xf8, 0x0b, 0xbd, 0x37, 0xd0, 0xc0, 0xe6, 0xf0, 0xa0, 0x6a, 0x76, 0xff, 0x9e, - 0x41, 0xfb, 0xf4, 0xd8, 0x77, 0x88, 0x0b, 0x4b, 0x7d, 0x7a, 0xbc, 0xf3, 0xca, 0x5f, 0x30, 0xb1, - 0xf7, 0xaf, 0x77, 0xfc, 0x45, 0x02, 0xb0, 0xfc, 0xfe, 0xf5, 0x4e, 0xb8, 0xf3, 0xca, 0x6f, 0xf4, - 0xfa, 0xe0, 0xd5, 0x72, 0x31, 0xd3, 0xb4, 0x50, 0x3c, 0xbc, 0x14, 0x29, 0xc3, 0x99, 0xdb, 0xa2, - 0xcd, 0x42, 0xf1, 0x43, 0x91, 0x32, 0xd3, 0x7c, 0x06, 0x92, 0x23, 0x8e, 0x73, 0xb6, 0x45, 0x97, - 0x0b, 0xc5, 0xe9, 0x88, 0xf7, 0x7e, 0x77, 0xa0, 0x55, 0x9d, 0x31, 0x21, 0xd0, 0x88, 0xb9, 0x8a, - 0x50, 0xec, 0x52, 0xfc, 0x36, 0x31, 0x1c, 0xb9, 0x76, 0x3c, 0xe3, 0x37, 0xd9, 0x00, 0x50, 0x9a, - 0x49, 0x8d, 0x33, 0x1e, 0x87, 0x71, 0x83, 0xba, 0x18, 0x31, 0xa3, 0x9d, 0x3c, 0x01, 0x57, 0x72, - 0x36, 0xb1, 0x68, 0x03, 0xd1, 0x96, 0x09, 0x20, 0xb8, 0x01, 0x90, 0xf2, 0x54, 0xc8, 0x9b, 0xb0, - 0x50, 0x1c, 0x47, 0x6d, 0x83, 0xba, 0x36, 0x72, 0xae, 0x78, 0xef, 0x4f, 0x07, 0x3a, 0xc7, 0x22, - 0x2e, 0x26, 0xfc, 0xec, 0x26, 0xe7, 0x98, 0xd5, 0xaf, 0xd5, 0xd5, 0xa8, 0x1b, 0xa5, 0x79, 0x8a, - 0xd9, 0x75, 0xb6, 0x5f, 0xcc, 0x9f, 0x21, 0xb7, 0xa4, 0xf6, 0xa6, 0x4e, 0x51, 0x56, 0x9b, 0x26, - 0xa3, 0x59, 0x94, 0x7c, 0x0d, 0x5e, 0x8a, 0x9a, 0x50, 0xdf, 0xe4, 0x55, 0x95, 0x90, 0x4e, 0x6d, - 0xc8, 0x37, 0xd0, 0xc9, 0x8a, 0x34, 0x14, 0xe3, 0xd0, 0x06, 0x15, 0xd6, 0xdb, 0xa6, 0x2b, 0x59, - 0x91, 0x0e, 0xc7, 0x76, 0x3f, 0xd5, 0x7b, 0x51, 0xde, 0x44, 0xe9, 0x7a, 0xeb, 0x3a, 0x5d, 0x58, - 0x3a, 0x1d, 0x0e, 0x4f, 0xcc, 0xbd, 0xb7, 0xa0, 0x71, 0xdc, 0x3f, 0x3a, 0xf0, 0x17, 0x7a, 0x13, - 0x78, 0x3c, 0x90, 0x89, 0x4e, 0x22, 0x36, 0x39, 0x57, 0x5c, 0xfe, 0x24, 0x0a, 0x99, 0xf1, 0x9b, - 0xaa, 0x1b, 0xab, 0x43, 0x77, 0x6a, 0x87, 0xbe, 0x0b, 0xcd, 0xaa, 0xdb, 0x17, 0xfe, 0xa7, 0x39, - 0x6b, 0x53, 0x94, 0x56, 0x82, 0xde, 0x08, 0x9e, 0xcc, 0xd9, 0x4d, 0xcd, 0x9a, 0xbf, 0x11, 0x15, - 0x1f, 0x54, 0xe0, 0xe0, 0x0b, 0x9e, 0x7f, 0xb2, 0xff, 0x9d, 0x2d, 0x45, 0x71, 0xef, 0x0f, 0x07, - 0x56, 0xff, 0xf5, 0xd4, 0x48, 0x00, 0xcd, 0xea, 0xdc, 0x1c, 0x3c, 0xb7, 0x6a, 0x49, 0x1e, 0x43, - 0xab, 0xfc, 0x2d, 0xb2, 0x05, 0xb5, 0xe9, 0x74, 0x4d, 0xbe, 0x85, 0x55, 0x7c, 0xee, 0x21, 0x9b, - 0x4c, 0x44, 0x14, 0x46, 0xa2, 0xc8, 0x74, 0xd9, 0x67, 0xf7, 0x11, 0xe8, 0x9b, 0xf8, 0xc0, 0x84, - 0xc9, 0x26, 0xf8, 0x75, 0xae, 0x4a, 0x3e, 0x55, 0x4d, 0xd7, 0x99, 0x51, 0x4f, 0x93, 0x4f, 0xdc, - 0x0c, 0xff, 0x94, 0x5d, 0x87, 0x57, 0x9c, 0xe5, 0x96, 0x66, 0xbb, 0xcf, 0x4b, 0xd9, 0xf5, 0x8f, - 0x9c, 0xe5, 0x86, 0xb3, 0xf7, 0xf0, 0x97, 0x72, 0xbe, 0x94, 0x75, 0x87, 0xf8, 0xff, 0xe7, 0xef, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x03, 0x26, 0x59, 0x0f, 0x09, 0x00, 0x00, + // 1036 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xef, 0x4e, 0x1b, 0x47, + 0x10, 0xcf, 0x61, 0x83, 0x7d, 0x73, 0xd8, 0x1c, 0x0b, 0x29, 0x97, 0x44, 0xa8, 0x96, 0xd5, 0x44, + 0xa8, 0x6a, 0x48, 0x44, 0x23, 0x14, 0xa1, 0xa8, 0x12, 0x18, 0x44, 0x53, 0x04, 0x8e, 0x16, 0x4c, + 0xa3, 0xf6, 0xc3, 0x69, 0x7d, 0xb7, 0x86, 0x4b, 0x7d, 0xb7, 0xd6, 0xee, 0x5e, 0x04, 0x79, 0x87, + 0x3e, 0x55, 0x9f, 0xa5, 0xaf, 0x51, 0x55, 0x3b, 0x7b, 0x67, 0x1f, 0xad, 0xdb, 0xa0, 0x7c, 0xf3, + 0xce, 0xef, 0xcf, 0xce, 0xec, 0xce, 0xce, 0x19, 0x5a, 0x29, 0xd7, 0x32, 0x89, 0xd4, 0xf6, 0x44, + 0x0a, 0x2d, 0xc8, 0x9a, 0x12, 0x22, 0xbb, 0x0a, 0x87, 0x79, 0x32, 0x8e, 0xc3, 0x02, 0xea, 0xfe, + 0x05, 0xe0, 0x9d, 0xda, 0xdf, 0x07, 0x4c, 0x71, 0xf2, 0x12, 0xd6, 0x2d, 0x21, 0x66, 0x9a, 0x87, + 0x3a, 0x49, 0xb9, 0xd2, 0x2c, 0x9d, 0x04, 0x4e, 0xc7, 0xd9, 0xaa, 0x51, 0x82, 0xd8, 0x21, 0xd3, + 0xfc, 0xa2, 0x44, 0xc8, 0x23, 0x68, 0x5a, 0x45, 0x12, 0x07, 0x0b, 0x1d, 0x67, 0xcb, 0xa5, 0x0d, + 0x5c, 0xbf, 0x8d, 0xc9, 0x1e, 0x3c, 0x9a, 0x8c, 0x99, 0x1e, 0x09, 0x99, 0x86, 0x1f, 0xb9, 0x54, + 0x89, 0xc8, 0xc2, 0x48, 0xc4, 0x3c, 0x63, 0x29, 0x0f, 0x6a, 0xc8, 0xdd, 0x28, 0x09, 0x97, 0x16, + 0xef, 0x15, 0x30, 0x79, 0x0a, 0x6d, 0xcd, 0xe4, 0x15, 0xd7, 0xe1, 0x44, 0x8a, 0x38, 0x8f, 0x74, + 0x50, 0x47, 0x41, 0xcb, 0x46, 0xdf, 0xd9, 0x20, 0x89, 0x61, 0xbd, 0xa0, 0xd9, 0x24, 0x3e, 0x32, + 0x99, 0xb0, 0x4c, 0x07, 0x8b, 0x1d, 0x67, 0xab, 0xbd, 0xf3, 0x7c, 0x7b, 0x4e, 0xcd, 0xdb, 0x95, + 0x7a, 0xb7, 0x0f, 0x0c, 0x72, 0x69, 0x45, 0x7b, 0xb5, 0xa3, 0xb3, 0x63, 0x4a, 0xac, 0x5f, 0x15, + 0x20, 0x7d, 0xf0, 0x8a, 0x5d, 0x98, 0x8c, 0xae, 0x83, 0x25, 0x34, 0x7f, 0xfa, 0x59, 0xf3, 0x7d, + 0x19, 0x5d, 0xef, 0x35, 0x06, 0x67, 0x27, 0x67, 0xfd, 0x9f, 0xcf, 0x28, 0x58, 0x0b, 0x13, 0x24, + 0xdb, 0xb0, 0x56, 0x31, 0x9c, 0x66, 0xdd, 0xc0, 0x12, 0x57, 0x67, 0xc4, 0x32, 0x81, 0xef, 0xa0, + 0x48, 0x2b, 0x8c, 0x26, 0xf9, 0x94, 0xde, 0x44, 0xba, 0x6f, 0x91, 0xde, 0x24, 0x2f, 0xd9, 0x27, + 0xe0, 0x5e, 0x0b, 0x55, 0x24, 0xeb, 0x7e, 0x51, 0xb2, 0x4d, 0x63, 0x80, 0xa9, 0x52, 0x68, 0xa1, + 0xd9, 0x4e, 0x16, 0x5b, 0x43, 0xf8, 0x22, 0x43, 0xcf, 0x98, 0xec, 0x64, 0x31, 0x7a, 0x6e, 0x40, + 0x03, 0x3d, 0x85, 0x0a, 0x3c, 0xac, 0x61, 0xc9, 0x2c, 0xfb, 0x8a, 0x74, 0x8b, 0xcd, 0x84, 0x0a, + 0xf9, 0x8d, 0x96, 0x2c, 0x58, 0x46, 0xd8, 0xb3, 0xf0, 0x91, 0x09, 0x4d, 0x39, 0x91, 0x14, 0x4a, + 0x19, 0x8b, 0xd6, 0x8c, 0xd3, 0x33, 0xb1, 0xbe, 0x22, 0xcf, 0x60, 0xa5, 0xc2, 0xc1, 0xb4, 0xdb, + 0xb6, 0x7d, 0xa6, 0x2c, 0x4c, 0xe4, 0x39, 0xac, 0x55, 0x78, 0xd3, 0x12, 0x57, 0xec, 0xc1, 0x4e, + 0xb9, 0x95, 0xbc, 0x45, 0xae, 0xc3, 0x38, 0x91, 0x81, 0x6f, 0xf3, 0x16, 0xb9, 0x3e, 0x4c, 0x24, + 0xf9, 0x01, 0x3c, 0xc5, 0x75, 0x3e, 0x09, 0xb5, 0x10, 0x63, 0x15, 0xac, 0x76, 0x6a, 0x5b, 0xde, + 0xce, 0xe6, 0xdc, 0x23, 0x7a, 0xc7, 0xe5, 0xe8, 0x6d, 0x36, 0x12, 0x14, 0x50, 0x71, 0x61, 0x04, + 0x64, 0x0f, 0xdc, 0xdf, 0x98, 0x4e, 0x42, 0x99, 0x67, 0x2a, 0x20, 0xf7, 0x51, 0x37, 0x0d, 0x9f, + 0xe6, 0x99, 0x22, 0x6f, 0x00, 0x2c, 0x13, 0xc5, 0x6b, 0xf7, 0x11, 0xbb, 0x88, 0x96, 0xea, 0x2c, + 0xc9, 0x3e, 0x30, 0xab, 0x5e, 0xbf, 0x97, 0x1a, 0x05, 0xa8, 0xfe, 0x1e, 0x16, 0xb5, 0xd0, 0x6c, + 0x1c, 0x3c, 0xec, 0x38, 0x9f, 0x17, 0x5a, 0x2e, 0xb9, 0x84, 0x79, 0xa3, 0x28, 0xf8, 0x0a, 0x2d, + 0x9e, 0xcd, 0xb5, 0x38, 0x37, 0x31, 0x7c, 0x92, 0x45, 0x87, 0xd1, 0x55, 0xf5, 0xcf, 0x10, 0xe9, + 0xc1, 0xb2, 0x55, 0x45, 0x22, 0x1b, 0x25, 0x57, 0xc1, 0x06, 0x1a, 0x76, 0xe6, 0x1a, 0xa2, 0xb0, + 0x87, 0x3c, 0xea, 0x0d, 0x67, 0x8b, 0xee, 0x4b, 0x58, 0xbe, 0xf3, 0xf4, 0x9b, 0x50, 0x1f, 0x9c, + 0x1f, 0x51, 0xff, 0x01, 0x69, 0x81, 0x6b, 0x7e, 0x1d, 0x1e, 0x1d, 0x0c, 0x8e, 0x7d, 0x87, 0x34, + 0xc0, 0x8c, 0x0b, 0x7f, 0xa1, 0xfb, 0x06, 0xea, 0xd8, 0x1c, 0x1e, 0x94, 0xcd, 0xee, 0x3f, 0x30, + 0xe8, 0x3e, 0x3d, 0xf5, 0x1d, 0xe2, 0xc2, 0xe2, 0x3e, 0x3d, 0xdd, 0x7d, 0xe5, 0x2f, 0x98, 0xd8, + 0xfb, 0xd7, 0xbb, 0x7e, 0x8d, 0x00, 0x2c, 0xbd, 0x7f, 0xbd, 0x1b, 0xee, 0xbe, 0xf2, 0xeb, 0xdd, + 0x2b, 0xf0, 0x2a, 0xb9, 0x98, 0x69, 0x9a, 0x2b, 0x1e, 0x5e, 0x89, 0x94, 0xe1, 0xcc, 0x6d, 0xd2, + 0x46, 0xae, 0xf8, 0xb1, 0x48, 0x99, 0x69, 0x3e, 0x03, 0xc9, 0x21, 0xc7, 0x39, 0xdb, 0xa4, 0x4b, + 0xb9, 0xe2, 0x74, 0xc8, 0xc9, 0x37, 0xd0, 0x1e, 0x09, 0x19, 0xf1, 0x70, 0xaa, 0xac, 0x21, 0xbe, + 0x8c, 0xd1, 0x81, 0x95, 0x77, 0x7f, 0x77, 0xa0, 0x59, 0xde, 0x04, 0x21, 0x50, 0x8f, 0xb9, 0x8a, + 0x70, 0x0b, 0x97, 0xe2, 0x6f, 0x13, 0xc3, 0xc1, 0x6c, 0x87, 0x38, 0xfe, 0x26, 0x9b, 0x00, 0x4a, + 0x33, 0xa9, 0xf1, 0x4b, 0x80, 0xb6, 0x75, 0xea, 0x62, 0xc4, 0x7c, 0x00, 0xc8, 0x13, 0x70, 0x25, + 0x67, 0x63, 0x8b, 0xd6, 0x11, 0x6d, 0x9a, 0x00, 0x82, 0x9b, 0x00, 0x29, 0x4f, 0x85, 0xbc, 0x35, + 0x79, 0xe1, 0x40, 0xae, 0x53, 0xd7, 0x46, 0x06, 0x8a, 0x77, 0xff, 0x74, 0xa0, 0x7d, 0x2a, 0xe2, + 0x7c, 0xcc, 0x2f, 0x6e, 0x27, 0x1c, 0xb3, 0xfa, 0xb5, 0xbc, 0x40, 0x75, 0xab, 0x34, 0x4f, 0x31, + 0xbb, 0xf6, 0xce, 0x8b, 0xf9, 0x93, 0xe6, 0x8e, 0xd4, 0xde, 0xe7, 0x39, 0xca, 0x2a, 0x33, 0x67, + 0x38, 0x8b, 0x92, 0xaf, 0xc1, 0x4b, 0x51, 0x13, 0xea, 0xdb, 0x49, 0x59, 0x25, 0xa4, 0x53, 0x1b, + 0x73, 0x8c, 0x59, 0x9e, 0x86, 0x62, 0x14, 0xda, 0xa0, 0xc2, 0x7a, 0x5b, 0x74, 0x39, 0xcb, 0xd3, + 0xfe, 0xc8, 0xee, 0xa7, 0xba, 0x2f, 0x8a, 0xfb, 0x2a, 0x5c, 0xef, 0x5c, 0xba, 0x0b, 0x8b, 0xe7, + 0xfd, 0xfe, 0x99, 0xe9, 0x8e, 0x26, 0xd4, 0x4f, 0xf7, 0x4f, 0x8e, 0xfc, 0x85, 0xee, 0x18, 0x1e, + 0xf7, 0x64, 0xa2, 0x93, 0x88, 0x8d, 0x07, 0x8a, 0xcb, 0x9f, 0x44, 0x2e, 0x33, 0x7e, 0x5b, 0xf6, + 0x6c, 0x79, 0xe8, 0x4e, 0xe5, 0xd0, 0xf7, 0xa0, 0x51, 0xbe, 0x89, 0x85, 0xff, 0x69, 0xe1, 0xca, + 0xac, 0xa5, 0xa5, 0xa0, 0x3b, 0x84, 0x27, 0x73, 0x76, 0x53, 0xb3, 0x27, 0x52, 0x8f, 0xf2, 0x0f, + 0x2a, 0x70, 0xf0, 0x9d, 0xcf, 0x3f, 0xd9, 0xff, 0xce, 0x96, 0xa2, 0xb8, 0xfb, 0x87, 0x03, 0xab, + 0xff, 0x7a, 0x90, 0x24, 0x80, 0x46, 0x79, 0x6e, 0x0e, 0x9e, 0x5b, 0xb9, 0x24, 0x8f, 0xa1, 0x59, + 0x7c, 0xb1, 0x6c, 0x41, 0x2d, 0x3a, 0x5d, 0x93, 0x6f, 0x61, 0x15, 0x87, 0x42, 0xc8, 0xc6, 0x63, + 0x11, 0x85, 0x91, 0xc8, 0x33, 0x5d, 0xf4, 0xd9, 0x0a, 0x02, 0xfb, 0x26, 0xde, 0x33, 0x61, 0xb2, + 0x05, 0x7e, 0x95, 0xab, 0x92, 0x4f, 0x65, 0xd3, 0xb5, 0x67, 0xd4, 0xf3, 0xe4, 0x13, 0x37, 0x9f, + 0x88, 0x94, 0xdd, 0x84, 0xd7, 0x9c, 0x4d, 0x2c, 0xcd, 0x76, 0x9f, 0x97, 0xb2, 0x9b, 0x1f, 0x39, + 0x9b, 0x18, 0xce, 0xc1, 0xc3, 0x5f, 0x8a, 0x29, 0x54, 0xd4, 0x1d, 0xe2, 0xbf, 0xa4, 0xbf, 0x03, + 0x00, 0x00, 0xff, 0xff, 0x85, 0xc5, 0xe0, 0x4b, 0x35, 0x09, 0x00, 0x00, } diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto index 6559ba334..4d6118b1d 100644 --- a/ui/metrics/metrics_proto/metrics.proto +++ b/ui/metrics/metrics_proto/metrics.proto @@ -102,6 +102,8 @@ message BuildConfig { optional bool use_goma = 1; optional bool use_rbe = 2; + + optional bool force_use_goma = 3; } message PerfInfo { |