summaryrefslogtreecommitdiff
path: root/cc
diff options
context:
space:
mode:
Diffstat (limited to 'cc')
-rw-r--r--cc/Android.bp1
-rw-r--r--cc/androidmk.go33
-rw-r--r--cc/api_level.go71
-rw-r--r--cc/binary_sdk_member.go2
-rw-r--r--cc/builder.go1
-rw-r--r--cc/cc.go231
-rw-r--r--cc/cc_test.go44
-rw-r--r--cc/check.go2
-rw-r--r--cc/compiler.go50
-rw-r--r--cc/config/arm64_device.go6
-rw-r--r--cc/config/clang.go14
-rw-r--r--cc/config/global.go12
-rw-r--r--cc/config/x86_windows_host.go3
-rw-r--r--cc/fuzz.go3
-rw-r--r--cc/library.go111
-rw-r--r--cc/library_sdk_member.go35
-rw-r--r--cc/library_test.go10
-rw-r--r--cc/linkable.go4
-rw-r--r--cc/linker.go16
-rw-r--r--cc/lto.go62
-rw-r--r--cc/ndk_library.go200
-rwxr-xr-xcc/ndkstubgen/__init__.py29
-rw-r--r--cc/ndkstubgen/mypy.ini2
-rwxr-xr-xcc/ndkstubgen/test_ndkstubgen.py79
-rw-r--r--cc/pgo.go52
-rw-r--r--cc/prebuilt.go8
-rw-r--r--cc/sanitize.go97
-rw-r--r--cc/stl.go20
-rw-r--r--cc/symbolfile/__init__.py139
-rw-r--r--cc/symbolfile/mypy.ini2
-rw-r--r--cc/symbolfile/test_symbolfile.py381
31 files changed, 1007 insertions, 713 deletions
diff --git a/cc/Android.bp b/cc/Android.bp
index 831911e45..ff2cdf374 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -13,6 +13,7 @@ bootstrap_go_package {
],
srcs: [
"androidmk.go",
+ "api_level.go",
"builder.go",
"cc.go",
"ccdeps.go",
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 380b4e92f..d92fabc0d 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -33,7 +33,7 @@ var (
)
type AndroidMkContext interface {
- Name() string
+ BaseModuleName() string
Target() android.Target
subAndroidMk(*android.AndroidMkEntries, interface{})
Arch() android.Arch
@@ -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...)
}
@@ -149,24 +156,6 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries {
return []android.AndroidMkEntries{entries}
}
-func AndroidMkDataPaths(data []android.DataPath) []string {
- var testFiles []string
- for _, d := range data {
- rel := d.SrcPath.Rel()
- path := d.SrcPath.String()
- if !strings.HasSuffix(path, rel) {
- panic(fmt.Errorf("path %q does not end with %q", path, rel))
- }
- path = strings.TrimSuffix(path, rel)
- testFileString := path + ":" + rel
- if len(d.RelativeInstallPath) > 0 {
- testFileString += ":" + d.RelativeInstallPath
- }
- testFiles = append(testFiles, testFileString)
- }
- return testFiles
-}
-
func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) {
if len(extraTestConfigs) > 0 {
entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
@@ -176,7 +165,7 @@ func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *and
}
func androidMkWriteTestData(data []android.DataPath, ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- testFiles := AndroidMkDataPaths(data)
+ testFiles := android.AndroidMkDataPaths(data)
if len(testFiles) > 0 {
entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
entries.AddStrings("LOCAL_TEST_DATA", testFiles...)
@@ -289,7 +278,7 @@ func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries
})
}
if len(library.Properties.Stubs.Versions) > 0 &&
- android.DirectlyInAnyApex(ctx, ctx.Name()) && !ctx.InRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() &&
+ android.DirectlyInAnyApex(ctx, ctx.BaseModuleName()) && !ctx.InRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() &&
!ctx.static() {
if library.buildStubs() && library.isLatestStubVersion() {
// reference the latest version via its name without suffix when it is provided by apex
@@ -451,7 +440,7 @@ func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *
}
func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- entries.SubName = ndkLibrarySuffix + "." + c.properties.ApiLevel
+ entries.SubName = ndkLibrarySuffix + "." + c.apiLevel.String()
entries.Class = "SHARED_LIBRARIES"
entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
diff --git a/cc/api_level.go b/cc/api_level.go
new file mode 100644
index 000000000..c93d6eda3
--- /dev/null
+++ b/cc/api_level.go
@@ -0,0 +1,71 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+ "fmt"
+
+ "android/soong/android"
+)
+
+func minApiForArch(ctx android.BaseModuleContext,
+ arch android.ArchType) android.ApiLevel {
+
+ switch arch {
+ case android.Arm, android.X86:
+ return ctx.Config().MinSupportedSdkVersion()
+ case android.Arm64, android.X86_64:
+ return android.FirstLp64Version
+ default:
+ panic(fmt.Errorf("Unknown arch %q", arch))
+ }
+}
+
+func nativeApiLevelFromUser(ctx android.BaseModuleContext,
+ raw string) (android.ApiLevel, error) {
+
+ min := minApiForArch(ctx, ctx.Arch().ArchType)
+ if raw == "minimum" {
+ return min, nil
+ }
+
+ value, err := android.ApiLevelFromUser(ctx, raw)
+ if err != nil {
+ return android.NoneApiLevel, err
+ }
+
+ if value.LessThan(min) {
+ return min, nil
+ }
+
+ return value, nil
+}
+
+func nativeApiLevelFromUserWithDefault(ctx android.BaseModuleContext,
+ raw string, defaultValue string) (android.ApiLevel, error) {
+ if raw == "" {
+ raw = defaultValue
+ }
+ return nativeApiLevelFromUser(ctx, raw)
+}
+
+func nativeApiLevelOrPanic(ctx android.BaseModuleContext,
+ raw string) android.ApiLevel {
+ value, err := nativeApiLevelFromUser(ctx, raw)
+ if err != nil {
+ panic(err.Error())
+ }
+ return value
+}
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index a1abc728a..55e400e8e 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -44,7 +44,7 @@ func (mt *binarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorConte
for _, target := range targets {
name, version := StubsLibNameAndVersion(lib)
if version == "" {
- version = LatestStubsVersionFor(mctx.Config(), name)
+ version = "latest"
}
variations := target.Variations()
if mctx.Device() {
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)
diff --git a/cc/cc.go b/cc/cc.go
index 70229be5a..e18349c61 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -47,7 +47,8 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) {
ctx.BottomUp("link", LinkageMutator).Parallel()
ctx.BottomUp("ndk_api", NdkApiMutator).Parallel()
ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel()
- ctx.BottomUp("version", VersionMutator).Parallel()
+ ctx.BottomUp("version_selector", versionSelectorMutator).Parallel()
+ ctx.BottomUp("version", versionMutator).Parallel()
ctx.BottomUp("begin", BeginMutator).Parallel()
ctx.BottomUp("sysprop_cc", SyspropMutator).Parallel()
ctx.BottomUp("vendor_snapshot", VendorSnapshotMutator).Parallel()
@@ -99,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
@@ -237,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"`
@@ -353,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
@@ -614,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 {
@@ -629,7 +636,7 @@ func (c *Module) Toc() android.OptionalPath {
func (c *Module) ApiLevel() string {
if c.linker != nil {
if stub, ok := c.linker.(*stubDecorator); ok {
- return stub.properties.ApiLevel
+ return stub.apiLevel.String()
}
}
panic(fmt.Errorf("ApiLevel() called on non-stub library module: %q", c.BaseModuleName()))
@@ -733,6 +740,9 @@ func (c *Module) StubsVersions() []string {
if library, ok := c.linker.(*libraryDecorator); ok {
return library.Properties.Stubs.Versions
}
+ if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ return library.Properties.Stubs.Versions
+ }
}
panic(fmt.Errorf("StubsVersions called on non-library module: %q", c.BaseModuleName()))
}
@@ -742,6 +752,9 @@ func (c *Module) CcLibrary() bool {
if _, ok := c.linker.(*libraryDecorator); ok {
return true
}
+ if _, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ return true
+ }
}
return false
}
@@ -767,6 +780,14 @@ func (c *Module) SetBuildStubs() {
c.Properties.PreventInstall = true
return
}
+ if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ library.MutatedProperties.BuildStubs = true
+ c.Properties.HideFromMake = true
+ c.sanitize = nil
+ c.stl = nil
+ c.Properties.PreventInstall = true
+ return
+ }
if _, ok := c.linker.(*llndkStubDecorator); ok {
c.Properties.HideFromMake = true
return
@@ -780,22 +801,57 @@ func (c *Module) BuildStubs() bool {
if library, ok := c.linker.(*libraryDecorator); ok {
return library.buildStubs()
}
+ if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ return library.buildStubs()
+ }
}
panic(fmt.Errorf("BuildStubs called on non-library module: %q", c.BaseModuleName()))
}
-func (c *Module) SetStubsVersions(version string) {
+func (c *Module) SetAllStubsVersions(versions []string) {
+ if library, ok := c.linker.(*libraryDecorator); ok {
+ library.MutatedProperties.AllStubsVersions = versions
+ return
+ }
+ if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ library.MutatedProperties.AllStubsVersions = versions
+ return
+ }
+ if llndk, ok := c.linker.(*llndkStubDecorator); ok {
+ llndk.libraryDecorator.MutatedProperties.AllStubsVersions = versions
+ return
+ }
+}
+
+func (c *Module) AllStubsVersions() []string {
+ if library, ok := c.linker.(*libraryDecorator); ok {
+ return library.MutatedProperties.AllStubsVersions
+ }
+ if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ return library.MutatedProperties.AllStubsVersions
+ }
+ if llndk, ok := c.linker.(*llndkStubDecorator); ok {
+ return llndk.libraryDecorator.MutatedProperties.AllStubsVersions
+ }
+ return nil
+}
+
+func (c *Module) SetStubsVersion(version string) {
if c.linker != nil {
if library, ok := c.linker.(*libraryDecorator); ok {
library.MutatedProperties.StubsVersion = version
return
}
+ if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ library.MutatedProperties.StubsVersion = version
+ return
+ }
if llndk, ok := c.linker.(*llndkStubDecorator); ok {
llndk.libraryDecorator.MutatedProperties.StubsVersion = version
return
}
}
- panic(fmt.Errorf("SetStubsVersions called on non-library module: %q", c.BaseModuleName()))
+ panic(fmt.Errorf("SetStubsVersion called on non-library module: %q", c.BaseModuleName()))
}
func (c *Module) StubsVersion() string {
@@ -803,6 +859,9 @@ func (c *Module) StubsVersion() string {
if library, ok := c.linker.(*libraryDecorator); ok {
return library.MutatedProperties.StubsVersion
}
+ if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ return library.MutatedProperties.StubsVersion
+ }
if llndk, ok := c.linker.(*llndkStubDecorator); ok {
return llndk.libraryDecorator.MutatedProperties.StubsVersion
}
@@ -928,9 +987,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)
@@ -1045,6 +1104,8 @@ func (c *Module) getVndkExtendsModuleName() string {
func (c *Module) IsStubs() bool {
if library, ok := c.linker.(*libraryDecorator); ok {
return library.buildStubs()
+ } else if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ return library.buildStubs()
} else if _, ok := c.linker.(*llndkStubDecorator); ok {
return true
}
@@ -1306,7 +1367,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
}
@@ -1682,11 +1743,13 @@ func (c *Module) begin(ctx BaseModuleContext) {
feature.begin(ctx)
}
if ctx.useSdk() && c.IsSdkVariant() {
- version, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch())
+ version, err := nativeApiLevelFromUser(ctx, ctx.sdkVersion())
if err != nil {
ctx.PropertyErrorf("sdk_version", err.Error())
+ c.Properties.Sdk_version = nil
+ } else {
+ c.Properties.Sdk_version = StringPtr(version.String())
}
- c.Properties.Sdk_version = StringPtr(version)
}
}
@@ -1800,6 +1863,42 @@ func GetCrtVariations(ctx android.BottomUpMutatorContext,
}
}
+func (c *Module) addSharedLibDependenciesWithVersions(ctx android.BottomUpMutatorContext,
+ variations []blueprint.Variation, depTag libraryDependencyTag, name, version string, far bool) {
+
+ variations = append([]blueprint.Variation(nil), variations...)
+
+ if version != "" && VersionVariantAvailable(c) {
+ // Version is explicitly specified. i.e. libFoo#30
+ variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
+ depTag.explicitlyVersioned = true
+ }
+ var deps []blueprint.Module
+ if far {
+ deps = ctx.AddFarVariationDependencies(variations, depTag, name)
+ } else {
+ deps = ctx.AddVariationDependencies(variations, depTag, name)
+ }
+
+ // If the version is not specified, add dependency to all stubs libraries.
+ // The stubs library will be used when the depending module is built for APEX and
+ // the dependent module is not in the same APEX.
+ if version == "" && VersionVariantAvailable(c) {
+ if dep, ok := deps[0].(*Module); ok {
+ for _, ver := range dep.AllStubsVersions() {
+ // Note that depTag.ExplicitlyVersioned is false in this case.
+ versionVariations := append(variations,
+ blueprint.Variation{Mutator: "version", Variation: ver})
+ if far {
+ ctx.AddFarVariationDependencies(versionVariations, depTag, name)
+ } else {
+ ctx.AddVariationDependencies(versionVariations, depTag, name)
+ }
+ }
+ }
+ }
+}
+
func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
if !c.Enabled() {
return
@@ -1815,6 +1914,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 {
@@ -1898,6 +1999,11 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
buildStubs = true
}
}
+ if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ if library.buildStubs() {
+ buildStubs = true
+ }
+ }
}
rewriteSnapshotLibs := func(lib string, snapshotMap *snapshotMap) string {
@@ -1986,30 +2092,6 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
}, depTag, rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs))
}
- addSharedLibDependencies := func(depTag libraryDependencyTag, name string, version string) {
- var variations []blueprint.Variation
- variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
- if version != "" && VersionVariantAvailable(c) {
- // Version is explicitly specified. i.e. libFoo#30
- variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
- depTag.explicitlyVersioned = true
- }
- actx.AddVariationDependencies(variations, depTag, name)
-
- // If the version is not specified, add dependency to all stubs libraries.
- // The stubs library will be used when the depending module is built for APEX and
- // the dependent module is not in the same APEX.
- if version == "" && VersionVariantAvailable(c) {
- for _, ver := range stubsVersionsFor(actx.Config())[name] {
- // Note that depTag.ExplicitlyVersioned is false in this case.
- actx.AddVariationDependencies([]blueprint.Variation{
- {Mutator: "link", Variation: "shared"},
- {Mutator: "version", Variation: ver},
- }, depTag, name)
- }
- }
- }
-
// shared lib names without the #version suffix
var sharedLibNames []string
@@ -2026,7 +2108,10 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
name, version := StubsLibNameAndVersion(lib)
sharedLibNames = append(sharedLibNames, name)
- addSharedLibDependencies(depTag, name, version)
+ variations := []blueprint.Variation{
+ {Mutator: "link", Variation: "shared"},
+ }
+ c.addSharedLibDependenciesWithVersions(ctx, variations, depTag, name, version, false)
}
for _, lib := range deps.LateSharedLibs {
@@ -2037,7 +2122,10 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
continue
}
depTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: lateLibraryDependency}
- addSharedLibDependencies(depTag, lib, "")
+ variations := []blueprint.Variation{
+ {Mutator: "link", Variation: "shared"},
+ }
+ c.addSharedLibDependenciesWithVersions(ctx, variations, depTag, lib, "", false)
}
actx.AddVariationDependencies([]blueprint.Variation{
@@ -2291,7 +2379,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()) {
@@ -2395,7 +2483,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
}
@@ -2439,7 +2527,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
@@ -2457,12 +2545,12 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
if m, ok := ccDep.(*Module); ok && m.IsStubs() { // LLNDK
// by default, use current version of LLNDK
versionToUse := ""
- versions := stubsVersionsFor(ctx.Config())[depName]
+ versions := m.AllStubsVersions()
if c.ApexVariationName() != "" && len(versions) > 0 {
// 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
@@ -2533,17 +2621,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(
@@ -2986,21 +3077,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
@@ -3024,11 +3102,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
@@ -3082,6 +3166,8 @@ func DefaultsFactory(props ...interface{}) android.Module {
&LTOProperties{},
&PgoProperties{},
&android.ProtoProperties{},
+ // RustBindgenProperties is included here so that cc_defaults can be used for rust_bindgen modules.
+ &RustBindgenClangProperties{},
)
android.InitDefaultsModule(module)
@@ -3119,13 +3205,6 @@ func (c *Module) IsSdkVariant() bool {
return c.Properties.IsSdkVariant || c.AlwaysSdk()
}
-func getCurrentNdkPrebuiltVersion(ctx DepsContext) string {
- if ctx.Config().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt {
- return strconv.Itoa(config.NdkMaxPrebuiltVersionInt)
- }
- return ctx.Config().PlatformSdkVersion()
-}
-
func kytheExtractAllFactory() android.Singleton {
return &kytheExtractAllSingleton{}
}
diff --git a/cc/cc_test.go b/cc/cc_test.go
index a4c067772..e0d464093 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -3025,6 +3025,7 @@ func TestStaticLibDepReorderingWithShared(t *testing.T) {
}
func checkEquals(t *testing.T, message string, expected, actual interface{}) {
+ t.Helper()
if !reflect.DeepEqual(actual, expected) {
t.Errorf(message+
"\nactual: %v"+
@@ -3779,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 c268dec2b..21da2fc60 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -354,10 +354,16 @@ 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()))
}
}
+ if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+ flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_NATIVE_BRIDGE__")
+ }
+
instructionSet := String(compiler.Properties.Instruction_set)
if flags.RequiredInstructionSet != "" {
instructionSet = flags.RequiredInstructionSet
@@ -386,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
}
@@ -646,3 +652,43 @@ func isThirdParty(path string) bool {
}
return true
}
+
+// Properties for rust_bindgen related to generating rust bindings.
+// This exists here so these properties can be included in a cc_default
+// which can be used in both cc and rust modules.
+type RustBindgenClangProperties struct {
+ // list of directories relative to the Blueprints file that will
+ // be added to the include path using -I
+ Local_include_dirs []string `android:"arch_variant,variant_prepend"`
+
+ // list of static libraries that provide headers for this binding.
+ Static_libs []string `android:"arch_variant,variant_prepend"`
+
+ // list of shared libraries that provide headers for this binding.
+ Shared_libs []string `android:"arch_variant"`
+
+ // list of clang flags required to correctly interpret the headers.
+ Cflags []string `android:"arch_variant"`
+
+ // list of c++ specific clang flags required to correctly interpret the headers.
+ // This is provided primarily to make sure cppflags defined in cc_defaults are pulled in.
+ Cppflags []string `android:"arch_variant"`
+
+ // 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.
+}
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 62d8cc8fb..e6024aa45 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -34,6 +34,9 @@ var (
"armv8-2a": []string{
"-march=armv8.2-a",
},
+ "armv8-2a-dotprod": []string{
+ "-march=armv8.2-a+dotprod",
+ },
}
arm64Ldflags = []string{
@@ -100,6 +103,7 @@ func init() {
pctx.StaticVariable("Arm64ClangArmv8ACflags", strings.Join(arm64ArchVariantCflags["armv8-a"], " "))
pctx.StaticVariable("Arm64ClangArmv82ACflags", strings.Join(arm64ArchVariantCflags["armv8-2a"], " "))
+ pctx.StaticVariable("Arm64ClangArmv82ADotprodCflags", strings.Join(arm64ArchVariantCflags["armv8-2a-dotprod"], " "))
pctx.StaticVariable("Arm64ClangCortexA53Cflags",
strings.Join(arm64ClangCpuVariantCflags["cortex-a53"], " "))
@@ -121,6 +125,7 @@ var (
arm64ClangArchVariantCflagsVar = map[string]string{
"armv8-a": "${config.Arm64ClangArmv8ACflags}",
"armv8-2a": "${config.Arm64ClangArmv82ACflags}",
+ "armv8-2a-dotprod": "${config.Arm64ClangArmv82ADotprodCflags}",
}
arm64ClangCpuVariantCflagsVar = map[string]string{
@@ -198,6 +203,7 @@ func arm64ToolchainFactory(arch android.Arch) Toolchain {
switch arch.ArchVariant {
case "armv8-a":
case "armv8-2a":
+ case "armv8-2a-dotprod":
// Nothing extra for armv8-a/armv8-2a
default:
panic(fmt.Sprintf("Unknown ARM architecture version: %q", arch.ArchVariant))
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 7db405c2e..441bff2a5 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -42,7 +42,6 @@ var ClangUnknownCflags = sorted([]string{
"-Wno-literal-suffix",
"-Wno-maybe-uninitialized",
"-Wno-old-style-declaration",
- "-Wno-psabi",
"-Wno-unused-but-set-parameter",
"-Wno-unused-but-set-variable",
"-Wno-unused-local-typedefs",
@@ -93,7 +92,9 @@ var ClangLibToolingUnknownCflags = sorted([]string{})
// updated, some checks enabled by this module may be disabled if they have
// become more strict, or if they are a new match for a wildcard group like
// `modernize-*`.
-var ClangTidyDisableChecks = []string{}
+var ClangTidyDisableChecks = []string{
+ "misc-no-recursion",
+}
func init() {
pctx.StaticVariable("ClangExtraCflags", strings.Join([]string{
@@ -103,6 +104,10 @@ func init() {
// not emit the table by default on Android since NDK still uses GNU binutils.
"-faddrsig",
+ // Turn on -fcommon explicitly, since Clang now defaults to -fno-common. The cleanup bug
+ // tracking this is http://b/151457797.
+ "-fcommon",
+
// Help catch common 32/64-bit errors.
"-Werror=int-conversion",
@@ -183,6 +188,8 @@ func init() {
"-Wno-enum-enum-conversion", // http://b/154138986
"-Wno-enum-float-conversion", // http://b/154255917
"-Wno-pessimizing-move", // http://b/154270751
+ // New warnings to be fixed after clang-r399163
+ "-Wno-non-c-typedef-for-linkage", // http://b/161304145
}, " "))
// Extra cflags for external third-party projects to disable warnings that
@@ -205,6 +212,9 @@ func init() {
"-Wno-xor-used-as-pow",
// http://b/145211022
"-Wno-final-dtor-non-final-class",
+
+ // http://b/165945989
+ "-Wno-psabi",
}, " "))
}
diff --git a/cc/config/global.go b/cc/config/global.go
index 32f163d88..d4c626699 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -114,6 +114,12 @@ var (
noOverrideGlobalCflags = []string{
"-Werror=int-to-pointer-cast",
"-Werror=pointer-to-int-cast",
+ // http://b/161386391 for -Wno-void-pointer-to-enum-cast
+ "-Wno-void-pointer-to-enum-cast",
+ // http://b/161386391 for -Wno-void-pointer-to-int-cast
+ "-Wno-void-pointer-to-int-cast",
+ // http://b/161386391 for -Wno-pointer-to-int-cast
+ "-Wno-pointer-to-int-cast",
"-Werror=fortify-source",
}
@@ -126,12 +132,10 @@ var (
ExperimentalCStdVersion = "gnu11"
ExperimentalCppStdVersion = "gnu++2a"
- NdkMaxPrebuiltVersionInt = 27
-
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r383902b"
- ClangDefaultShortVersion = "11.0.2"
+ ClangDefaultVersion = "clang-r399163b"
+ ClangDefaultShortVersion = "11.0.5"
// Directories with warnings from Android.bp files.
WarningAllowedProjects = []string{
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index b5b555322..b77df7906 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -39,6 +39,9 @@ var (
// Get 64-bit off_t and related functions.
"-D_FILE_OFFSET_BITS=64",
+ // Don't adjust the layout of bitfields like msvc does.
+ "-mno-ms-bitfields",
+
"--sysroot ${WindowsGccRoot}/${WindowsGccTriple}",
}
windowsClangCflags = append(ClangFilterUnknownCflags(windowsCflags), []string{}...)
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 529541859..045384718 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -38,6 +38,9 @@ type FuzzConfig struct {
// Specify whether this fuzz target was submitted by a researcher. Defaults
// to false.
Researcher_submitted *bool `json:"researcher_submitted,omitempty"`
+ // Specify who should be acknowledged for CVEs in the Android Security
+ // Bulletin.
+ Acknowledgement []string `json:"acknowledgement,omitempty"`
}
func (f *FuzzConfig) String() string {
diff --git a/cc/library.go b/cc/library.go
index 92853b5d3..bf7868ff7 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -19,8 +19,6 @@ import (
"io"
"path/filepath"
"regexp"
- "sort"
- "strconv"
"strings"
"sync"
@@ -152,6 +150,8 @@ type LibraryMutatedProperties struct {
BuildStubs bool `blueprint:"mutated"`
// Version of the stubs lib
StubsVersion string `blueprint:"mutated"`
+ // List of all stubs versions associated with an implementation lib
+ AllStubsVersions []string `blueprint:"mutated"`
}
type FlagExporterProperties struct {
@@ -338,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
@@ -682,7 +678,6 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
}
type libraryInterface interface {
- getWholeStaticMissingDeps() []string
static() bool
shared() bool
objs() Objects
@@ -889,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
@@ -1182,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
}
@@ -1517,56 +1506,39 @@ func LinkageMutator(mctx android.BottomUpMutatorContext) {
}
}
-var stubVersionsKey = android.NewOnceKey("stubVersions")
-
-// maps a module name to the list of stubs versions available for the module
-func stubsVersionsFor(config android.Config) map[string][]string {
- return config.Once(stubVersionsKey, func() interface{} {
- return make(map[string][]string)
- }).(map[string][]string)
-}
-
-var stubsVersionsLock sync.Mutex
-
-func LatestStubsVersionFor(config android.Config, name string) string {
- versions, ok := stubsVersionsFor(config)[name]
- if ok && len(versions) > 0 {
- // the versions are alreay sorted in ascending order
- return versions[len(versions)-1]
- }
- return ""
-}
-
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
}
}
func createVersionVariations(mctx android.BottomUpMutatorContext, versions []string) {
- // "" is for the non-stubs variant
- versions = append([]string{""}, versions...)
+ // "" is for the non-stubs (implementation) variant.
+ variants := append([]string{""}, versions...)
- modules := mctx.CreateLocalVariations(versions...)
+ modules := mctx.CreateLocalVariations(variants...)
for i, m := range modules {
- if versions[i] != "" {
+ if variants[i] != "" {
m.(LinkableInterface).SetBuildStubs()
- m.(LinkableInterface).SetStubsVersions(versions[i])
+ m.(LinkableInterface).SetStubsVersion(variants[i])
}
}
mctx.AliasVariation("")
+ latestVersion := ""
+ if len(versions) > 0 {
+ latestVersion = versions[len(versions)-1]
+ }
+ mctx.CreateAliasVariation("latest", latestVersion)
}
func VersionVariantAvailable(module interface {
@@ -1577,44 +1549,41 @@ func VersionVariantAvailable(module interface {
return !module.Host() && !module.InRamdisk() && !module.InRecovery()
}
-// VersionMutator splits a module into the mandatory non-stubs variant
-// (which is unnamed) and zero or more stubs variants.
-func VersionMutator(mctx android.BottomUpMutatorContext) {
+// versionSelector normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions,
+// and propagates the value from implementation libraries to llndk libraries with the same name.
+func versionSelectorMutator(mctx android.BottomUpMutatorContext) {
if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 &&
!library.IsSdkVariant() {
+
versions := library.StubsVersions()
normalizeVersions(mctx, versions)
if mctx.Failed() {
return
}
-
- stubsVersionsLock.Lock()
- defer stubsVersionsLock.Unlock()
- // save the list of versions for later use
- stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = versions
-
- createVersionVariations(mctx, versions)
+ // Set the versions on the pre-mutated module so they can be read by any llndk modules that
+ // depend on the implementation library and haven't been mutated yet.
+ library.SetAllStubsVersions(versions)
return
}
if c, ok := library.(*Module); ok && c.IsStubs() {
- stubsVersionsLock.Lock()
- defer stubsVersionsLock.Unlock()
- // For LLNDK llndk_library, we borrow stubs.versions from its implementation library.
- // Since llndk_library has dependency to its implementation library,
- // we can safely access stubsVersionsFor() with its baseModuleName.
- versions := stubsVersionsFor(mctx.Config())[c.BaseModuleName()]
- // save the list of versions for later use
- stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = versions
-
- createVersionVariations(mctx, versions)
- return
+ // Get the versions from the implementation module.
+ impls := mctx.GetDirectDepsWithTag(llndkImplDep)
+ if len(impls) > 1 {
+ panic(fmt.Errorf("Expected single implmenetation library, got %d", len(impls)))
+ } else if len(impls) == 1 {
+ c.SetAllStubsVersions(impls[0].(*Module).AllStubsVersions())
+ }
}
+ }
+}
- mctx.CreateLocalVariations("")
- mctx.AliasVariation("")
- return
+// versionMutator splits a module into the mandatory non-stubs variant
+// (which is unnamed) and zero or more stubs variants.
+func versionMutator(mctx android.BottomUpMutatorContext) {
+ if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
+ createVersionVariations(mctx, library.AllStubsVersions())
}
}
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index ecfdc9977..41ce29422 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -80,7 +80,7 @@ func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorCont
for _, target := range targets {
name, version := StubsLibNameAndVersion(lib)
if version == "" {
- version = LatestStubsVersionFor(mctx.Config(), name)
+ version = "latest"
}
variations := target.Variations()
if mctx.Device() {
@@ -221,10 +221,7 @@ var includeDirProperties = []includeDirsProperty{
// Add properties that may, or may not, be arch specific.
func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) {
- if libInfo.SanitizeNever {
- sanitizeSet := outputProperties.AddPropertySet("sanitize")
- sanitizeSet.AddProperty("never", true)
- }
+ outputProperties.AddProperty("sanitize", &libInfo.Sanitize)
// Copy the generated library to the snapshot and add a reference to it in the .bp module.
if libInfo.outputFile != nil {
@@ -295,9 +292,9 @@ func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, b
outputProperties.AddProperty(property, includeDirs[property])
}
- if len(libInfo.StubsVersion) > 0 {
+ if len(libInfo.StubsVersions) > 0 {
stubsSet := outputProperties.AddPropertySet("stubs")
- stubsSet.AddProperty("versions", []string{libInfo.StubsVersion})
+ stubsSet.AddProperty("versions", libInfo.StubsVersions)
}
}
@@ -368,13 +365,15 @@ type nativeLibInfoProperties struct {
// The specific stubs version for the lib variant, or empty string if stubs
// are not in use.
//
- // Marked 'ignored-on-host' as the StubsVersion() from which this is initialized is
- // not set on host and the stubs.versions property which this is written to is does
- // not vary by arch so cannot be android specific.
- StubsVersion string `sdk:"ignored-on-host"`
+ // Marked 'ignored-on-host' as the AllStubsVersions() from which this is
+ // initialized is not set on host and the stubs.versions property which this
+ // is written to does not vary by arch so cannot be android specific.
+ StubsVersions []string `sdk:"ignored-on-host"`
- // Value of SanitizeProperties.Sanitize.Never. Needs to be propagated for CRT objects.
- SanitizeNever bool `android:"arch_variant"`
+ // Value of SanitizeProperties.Sanitize. Several - but not all - of these
+ // affect the expanded variants. All are propagated to avoid entangling the
+ // sanitizer logic with the snapshot generation.
+ Sanitize SanitizeUserProps `android:"arch_variant"`
// outputFile is not exported as it is always arch specific.
outputFile android.Path
@@ -420,11 +419,15 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte
p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
if ccModule.HasStubsVariants() {
- p.StubsVersion = ccModule.StubsVersion()
+ // TODO(b/169373910): 1. Only output the specific version (from
+ // ccModule.StubsVersion()) if the module is versioned. 2. Ensure that all
+ // the versioned stub libs are retained in the prebuilt tree; currently only
+ // the stub corresponding to ccModule.StubsVersion() is.
+ p.StubsVersions = ccModule.AllStubsVersions()
}
- if ccModule.sanitize != nil && proptools.Bool(ccModule.sanitize.Properties.Sanitize.Never) {
- p.SanitizeNever = true
+ if ccModule.sanitize != nil {
+ p.Sanitize = ccModule.sanitize.Properties.Sanitize
}
}
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/linkable.go b/cc/linkable.go
index 4c8416347..6d8a4b71e 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -26,8 +26,10 @@ type LinkableInterface interface {
StubsVersions() []string
BuildStubs() bool
SetBuildStubs()
- SetStubsVersions(string)
+ SetStubsVersion(string)
StubsVersion() string
+ SetAllStubsVersions([]string)
+ AllStubsVersions() []string
HasStubsVariants() bool
SelectedStl() string
ApiLevel() string
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() {
diff --git a/cc/lto.go b/cc/lto.go
index 9868cdfb9..abd8dfb9f 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -52,6 +52,9 @@ type LTOProperties struct {
// Use clang lld instead of gnu ld.
Use_clang_lld *bool
+
+ // Use -fwhole-program-vtables cflag.
+ Whole_program_vtables *bool
}
type lto struct {
@@ -65,6 +68,14 @@ 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") {
+ staticLib := ctx.static() && !ctx.staticBinary()
+ hostBin := ctx.Host()
+ if !staticLib && !hostBin {
+ if !lto.Never() && !lto.FullLTO() {
+ lto.Properties.Lto.Thin = boolPtr(true)
+ }
+ }
}
}
@@ -88,7 +99,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"
@@ -97,7 +108,11 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
flags.Local.CFlags = append(flags.Local.CFlags, ltoFlag)
flags.Local.LdFlags = append(flags.Local.LdFlags, ltoFlag)
- if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && Bool(lto.Properties.Lto.Thin) && lto.useClangLld(ctx) {
+ if Bool(lto.Properties.Whole_program_vtables) {
+ flags.Local.CFlags = append(flags.Local.CFlags, "-fwhole-program-vtables")
+ }
+
+ 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()
@@ -110,12 +125,11 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
flags.Local.LdFlags = append(flags.Local.LdFlags, cachePolicyFormat+policy)
}
- // If the module does not have a profile, be conservative and do not inline
- // or unroll loops during LTO, in order to prevent significant size bloat.
+ // If the module does not have a profile, be conservative and limit cross TU inline
+ // limit to 5 LLVM IR instructions, to balance binary size increase and performance.
if !ctx.isPgoCompile() {
flags.Local.LdFlags = append(flags.Local.LdFlags,
- "-Wl,-plugin-opt,-inline-threshold=0",
- "-Wl,-plugin-opt,-unroll-threshold=0")
+ "-Wl,-plugin-opt,-import-instr-limit=5")
}
}
return flags
@@ -123,25 +137,31 @@ 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 {
+ 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")
}
@@ -162,11 +182,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
}
}
@@ -183,19 +203,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 fe3efc01e..5682d1c6b 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -16,7 +16,6 @@ package cc
import (
"fmt"
- "strconv"
"strings"
"sync"
@@ -52,6 +51,10 @@ var (
ndkKnownLibsLock sync.Mutex
)
+// The First_version and Unversioned_until properties of this struct should not
+// be used directly, but rather through the ApiLevel returning methods
+// firstVersion() and unversionedUntil().
+
// Creates a stub shared library based on the provided version file.
//
// Example:
@@ -77,9 +80,7 @@ type libraryProperties struct {
// https://github.com/android-ndk/ndk/issues/265.
Unversioned_until *string
- // Private property for use by the mutator that splits per-API level. Can be
- // one of <number:sdk_version> or <codename> or "current" passed to
- // "ndkstubgen.py" as it is
+ // Use via apiLevel on the stubDecorator.
ApiLevel string `blueprint:"mutated"`
// True if this API is not yet ready to be shipped in the NDK. It will be
@@ -96,125 +97,33 @@ type stubDecorator struct {
versionScriptPath android.ModuleGenPath
parsedCoverageXmlPath android.ModuleOutPath
installPath android.Path
-}
-
-// OMG GO
-func intMax(a int, b int) int {
- if a > b {
- return a
- } else {
- return b
- }
-}
-
-func normalizeNdkApiLevel(ctx android.BaseModuleContext, apiLevel string,
- arch android.Arch) (string, error) {
-
- if apiLevel == "" {
- panic("empty apiLevel not allowed")
- }
-
- if apiLevel == "current" {
- return apiLevel, nil
- }
-
- minVersion := ctx.Config().MinSupportedSdkVersion()
- firstArchVersions := map[android.ArchType]int{
- android.Arm: minVersion,
- android.Arm64: 21,
- android.X86: minVersion,
- android.X86_64: 21,
- }
-
- firstArchVersion, ok := firstArchVersions[arch.ArchType]
- if !ok {
- panic(fmt.Errorf("Arch %q not found in firstArchVersions", arch.ArchType))
- }
-
- if apiLevel == "minimum" {
- return strconv.Itoa(firstArchVersion), nil
- }
- // If the NDK drops support for a platform version, we don't want to have to
- // fix up every module that was using it as its SDK version. Clip to the
- // supported version here instead.
- version, err := strconv.Atoi(apiLevel)
- if err != nil {
- // Non-integer API levels are codenames.
- return apiLevel, nil
- }
- version = intMax(version, minVersion)
-
- return strconv.Itoa(intMax(version, firstArchVersion)), nil
+ apiLevel android.ApiLevel
+ firstVersion android.ApiLevel
+ unversionedUntil android.ApiLevel
}
-func getFirstGeneratedVersion(firstSupportedVersion string, platformVersion int) (int, error) {
- if firstSupportedVersion == "current" {
- return platformVersion + 1, nil
- }
-
- return strconv.Atoi(firstSupportedVersion)
-}
-
-func shouldUseVersionScript(ctx android.BaseModuleContext, stub *stubDecorator) (bool, error) {
- // unversioned_until is normally empty, in which case we should use the version script.
- if String(stub.properties.Unversioned_until) == "" {
- return true, nil
- }
-
- if String(stub.properties.Unversioned_until) == "current" {
- if stub.properties.ApiLevel == "current" {
- return true, nil
- } else {
- return false, nil
- }
- }
-
- if stub.properties.ApiLevel == "current" {
- return true, nil
- }
-
- unversionedUntil, err := android.ApiStrToNum(ctx, String(stub.properties.Unversioned_until))
- if err != nil {
- return true, err
- }
-
- version, err := android.ApiStrToNum(ctx, stub.properties.ApiLevel)
- if err != nil {
- return true, err
- }
-
- return version >= unversionedUntil, nil
+func shouldUseVersionScript(ctx BaseModuleContext, stub *stubDecorator) bool {
+ return stub.apiLevel.GreaterThanOrEqualTo(stub.unversionedUntil)
}
func generatePerApiVariants(ctx android.BottomUpMutatorContext, m *Module,
- propName string, propValue string, perSplit func(*Module, string)) {
- platformVersion := ctx.Config().PlatformSdkVersionInt()
-
- firstSupportedVersion, err := normalizeNdkApiLevel(ctx, propValue,
- ctx.Arch())
- if err != nil {
- ctx.PropertyErrorf(propName, err.Error())
- }
-
- firstGenVersion, err := getFirstGeneratedVersion(firstSupportedVersion,
- platformVersion)
- if err != nil {
- // In theory this is impossible because we've already run this through
- // normalizeNdkApiLevel above.
- ctx.PropertyErrorf(propName, err.Error())
- }
-
- var versionStrs []string
- for version := firstGenVersion; version <= platformVersion; version++ {
- versionStrs = append(versionStrs, strconv.Itoa(version))
+ from android.ApiLevel, perSplit func(*Module, android.ApiLevel)) {
+
+ var versions []android.ApiLevel
+ versionStrs := []string{}
+ for _, version := range ctx.Config().AllSupportedApiLevels() {
+ if version.GreaterThanOrEqualTo(from) {
+ versions = append(versions, version)
+ versionStrs = append(versionStrs, version.String())
+ }
}
- versionStrs = append(versionStrs, ctx.Config().PlatformVersionActiveCodenames()...)
- versionStrs = append(versionStrs, "current")
+ versions = append(versions, android.FutureApiLevel)
+ versionStrs = append(versionStrs, android.FutureApiLevel.String())
modules := ctx.CreateVariations(versionStrs...)
for i, module := range modules {
- perSplit(module.(*Module), versionStrs[i])
+ perSplit(module.(*Module), versions[i])
}
}
@@ -228,25 +137,56 @@ func NdkApiMutator(ctx android.BottomUpMutatorContext) {
ctx.Module().Disable()
return
}
- generatePerApiVariants(ctx, m, "first_version",
- String(compiler.properties.First_version),
- func(m *Module, version string) {
+ firstVersion, err := nativeApiLevelFromUser(ctx,
+ String(compiler.properties.First_version))
+ if err != nil {
+ ctx.PropertyErrorf("first_version", err.Error())
+ return
+ }
+ generatePerApiVariants(ctx, m, firstVersion,
+ func(m *Module, version android.ApiLevel) {
m.compiler.(*stubDecorator).properties.ApiLevel =
- version
+ version.String()
})
} else if m.SplitPerApiLevel() && m.IsSdkVariant() {
if ctx.Os() != android.Android {
return
}
- generatePerApiVariants(ctx, m, "min_sdk_version",
- m.MinSdkVersion(), func(m *Module, version string) {
- m.Properties.Sdk_version = &version
+ from, err := nativeApiLevelFromUser(ctx, m.MinSdkVersion())
+ if err != nil {
+ ctx.PropertyErrorf("min_sdk_version", err.Error())
+ return
+ }
+ generatePerApiVariants(ctx, m, from,
+ func(m *Module, version android.ApiLevel) {
+ m.Properties.Sdk_version = StringPtr(version.String())
})
}
}
}
}
+func (this *stubDecorator) initializeProperties(ctx BaseModuleContext) bool {
+ this.apiLevel = nativeApiLevelOrPanic(ctx, this.properties.ApiLevel)
+
+ var err error
+ this.firstVersion, err = nativeApiLevelFromUser(ctx,
+ String(this.properties.First_version))
+ if err != nil {
+ ctx.PropertyErrorf("first_version", err.Error())
+ return false
+ }
+
+ this.unversionedUntil, err = nativeApiLevelFromUserWithDefault(ctx,
+ String(this.properties.Unversioned_until), "minimum")
+ if err != nil {
+ ctx.PropertyErrorf("unversioned_until", err.Error())
+ return false
+ }
+
+ return true
+}
+
func (c *stubDecorator) compilerInit(ctx BaseModuleContext) {
c.baseCompiler.compilerInit(ctx)
@@ -340,11 +280,16 @@ func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) O
ctx.PropertyErrorf("symbol_file", "must end with .map.txt")
}
+ if !c.initializeProperties(ctx) {
+ // Emits its own errors, so we don't need to.
+ return Objects{}
+ }
+
symbolFile := String(c.properties.Symbol_file)
objs, versionScript := compileStubLibrary(ctx, flags, symbolFile,
- c.properties.ApiLevel, "")
+ c.apiLevel.String(), "")
c.versionScriptPath = versionScript
- if c.properties.ApiLevel == "current" && ctx.PrimaryArch() {
+ if c.apiLevel.IsCurrent() && ctx.PrimaryArch() {
c.parsedCoverageXmlPath = parseSymbolFileForCoverage(ctx, symbolFile)
}
return objs
@@ -366,12 +311,7 @@ func (stub *stubDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
objs Objects) android.Path {
- useVersionScript, err := shouldUseVersionScript(ctx, stub)
- if err != nil {
- ctx.ModuleErrorf(err.Error())
- }
-
- if useVersionScript {
+ if shouldUseVersionScript(ctx, stub) {
linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
flags.Local.LdFlags = append(flags.Local.LdFlags, linkerScriptFlag)
flags.LdFlagsDeps = append(flags.LdFlagsDeps, stub.versionScriptPath)
@@ -386,8 +326,6 @@ func (stub *stubDecorator) nativeCoverage() bool {
func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {
arch := ctx.Target().Arch.ArchType.Name
- apiLevel := stub.properties.ApiLevel
-
// arm64 isn't actually a multilib toolchain, so unlike the other LP64
// architectures it's just installed to lib.
libDir := "lib"
@@ -396,7 +334,7 @@ func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {
}
installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
- "platforms/android-%s/arch-%s/usr/%s", apiLevel, arch, libDir))
+ "platforms/android-%s/arch-%s/usr/%s", stub.apiLevel, arch, libDir))
stub.installPath = ctx.InstallFile(installDir, path.Base(), path)
}
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/pgo.go b/cc/pgo.go
index 6bf0ad0aa..439d2f786 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -70,6 +70,7 @@ type PgoProperties struct {
PgoPresent bool `blueprint:"mutated"`
ShouldProfileModule bool `blueprint:"mutated"`
PgoCompile bool `blueprint:"mutated"`
+ PgoInstrLink bool `blueprint:"mutated"`
}
type pgo struct {
@@ -89,13 +90,12 @@ func (pgo *pgo) props() []interface{} {
}
func (props *PgoProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
- flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
-
- flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
- // The profile runtime is added below in deps(). Add the below
- // flag, which is the only other link-time action performed by
- // the Clang driver during link.
- flags.Local.LdFlags = append(flags.Local.LdFlags, "-u__llvm_profile_runtime")
+ // Add to C flags iff PGO is explicitly enabled for this module.
+ if props.ShouldProfileModule {
+ flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
+ flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
+ }
+ flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrumentFlag)
return flags
}
func (props *PgoProperties) addSamplingProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
@@ -250,10 +250,12 @@ func (pgo *pgo) begin(ctx BaseModuleContext) {
if pgoBenchmarksMap["all"] == true || pgoBenchmarksMap["ALL"] == true {
pgo.Properties.ShouldProfileModule = true
+ pgo.Properties.PgoInstrLink = pgo.Properties.isInstrumentation()
} else {
for _, b := range pgo.Properties.Pgo.Benchmarks {
if pgoBenchmarksMap[b] == true {
pgo.Properties.ShouldProfileModule = true
+ pgo.Properties.PgoInstrLink = pgo.Properties.isInstrumentation()
break
}
}
@@ -286,10 +288,42 @@ func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
return flags
}
- props := pgo.Properties
+ // Deduce PgoInstrLink property i.e. whether this module needs to be
+ // linked with profile-generation flags. Here, we're setting it if any
+ // dependency needs PGO instrumentation. It is initially set in
+ // begin() if PGO is directly enabled for this module.
+ if ctx.static() && !ctx.staticBinary() {
+ // For static libraries, check if any whole_static_libs are
+ // linked with profile generation
+ ctx.VisitDirectDeps(func(m android.Module) {
+ if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok {
+ if depTag.static() && depTag.wholeStatic {
+ if cc, ok := m.(*Module); ok {
+ if cc.pgo.Properties.PgoInstrLink {
+ pgo.Properties.PgoInstrLink = true
+ }
+ }
+ }
+ }
+ })
+ } else {
+ // For executables and shared libraries, check all static dependencies.
+ ctx.VisitDirectDeps(func(m android.Module) {
+ if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok {
+ if depTag.static() {
+ if cc, ok := m.(*Module); ok {
+ if cc.pgo.Properties.PgoInstrLink {
+ pgo.Properties.PgoInstrLink = true
+ }
+ }
+ }
+ }
+ })
+ }
+ props := pgo.Properties
// Add flags to profile this module based on its profile_kind
- if props.ShouldProfileModule && props.isInstrumentation() {
+ if (props.ShouldProfileModule && props.isInstrumentation()) || props.PgoInstrLink {
// Instrumentation PGO use and gather flags cannot coexist.
return props.addInstrumentationProfileGatherFlags(ctx, flags)
} else if props.ShouldProfileModule && props.isSampling() {
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 1ee096e18..9d1b01608 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -16,6 +16,7 @@ package cc
import (
"android/soong/android"
+ "path/filepath"
)
func init() {
@@ -360,13 +361,18 @@ func (p *prebuiltBinaryLinker) link(ctx ModuleContext,
sharedLibPaths = append(sharedLibPaths, deps.SharedLibs...)
sharedLibPaths = append(sharedLibPaths, deps.LateSharedLibs...)
+ var fromPath = in.String()
+ if !filepath.IsAbs(fromPath) {
+ fromPath = "$$PWD/" + fromPath
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: android.Symlink,
Output: outputFile,
Input: in,
Implicits: sharedLibPaths,
Args: map[string]string{
- "fromPath": "$$PWD/" + in.String(),
+ "fromPath": fromPath,
},
})
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 174dcfea5..43198c16e 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -139,56 +139,59 @@ func (t sanitizerType) incompatibleWithCfi() bool {
return t == asan || t == fuzzer || t == hwasan
}
-type SanitizeProperties struct {
- // enable AddressSanitizer, ThreadSanitizer, or UndefinedBehaviorSanitizer
- Sanitize struct {
- Never *bool `android:"arch_variant"`
-
- // main sanitizers
- Address *bool `android:"arch_variant"`
- Thread *bool `android:"arch_variant"`
- Hwaddress *bool `android:"arch_variant"`
-
- // local sanitizers
+type SanitizeUserProps struct {
+ Never *bool `android:"arch_variant"`
+
+ // main sanitizers
+ Address *bool `android:"arch_variant"`
+ Thread *bool `android:"arch_variant"`
+ Hwaddress *bool `android:"arch_variant"`
+
+ // local sanitizers
+ Undefined *bool `android:"arch_variant"`
+ All_undefined *bool `android:"arch_variant"`
+ Misc_undefined []string `android:"arch_variant"`
+ Fuzzer *bool `android:"arch_variant"`
+ Safestack *bool `android:"arch_variant"`
+ Cfi *bool `android:"arch_variant"`
+ Integer_overflow *bool `android:"arch_variant"`
+ Scudo *bool `android:"arch_variant"`
+ Scs *bool `android:"arch_variant"`
+
+ // A modifier for ASAN and HWASAN for write only instrumentation
+ Writeonly *bool `android:"arch_variant"`
+
+ // Sanitizers to run in the diagnostic mode (as opposed to the release mode).
+ // Replaces abort() on error with a human-readable error message.
+ // Address and Thread sanitizers always run in diagnostic mode.
+ Diag struct {
Undefined *bool `android:"arch_variant"`
- All_undefined *bool `android:"arch_variant"`
- Misc_undefined []string `android:"arch_variant"`
- Fuzzer *bool `android:"arch_variant"`
- Safestack *bool `android:"arch_variant"`
Cfi *bool `android:"arch_variant"`
Integer_overflow *bool `android:"arch_variant"`
- Scudo *bool `android:"arch_variant"`
- Scs *bool `android:"arch_variant"`
-
- // A modifier for ASAN and HWASAN for write only instrumentation
- Writeonly *bool `android:"arch_variant"`
-
- // Sanitizers to run in the diagnostic mode (as opposed to the release mode).
- // Replaces abort() on error with a human-readable error message.
- // Address and Thread sanitizers always run in diagnostic mode.
- Diag struct {
- Undefined *bool `android:"arch_variant"`
- Cfi *bool `android:"arch_variant"`
- Integer_overflow *bool `android:"arch_variant"`
- Misc_undefined []string `android:"arch_variant"`
- No_recover []string
- }
+ Misc_undefined []string `android:"arch_variant"`
+ No_recover []string
+ }
+
+ // value to pass to -fsanitize-recover=
+ Recover []string
- // value to pass to -fsanitize-recover=
- Recover []string
-
- // value to pass to -fsanitize-blacklist
- Blocklist *string
- } `android:"arch_variant"`
-
- SanitizerEnabled bool `blueprint:"mutated"`
- SanitizeDep bool `blueprint:"mutated"`
- MinimalRuntimeDep bool `blueprint:"mutated"`
- BuiltinsDep bool `blueprint:"mutated"`
- UbsanRuntimeDep bool `blueprint:"mutated"`
- InSanitizerDir bool `blueprint:"mutated"`
- Sanitizers []string `blueprint:"mutated"`
- DiagSanitizers []string `blueprint:"mutated"`
+ // value to pass to -fsanitize-blacklist
+ Blocklist *string
+}
+
+type SanitizeProperties struct {
+ // Enable AddressSanitizer, ThreadSanitizer, UndefinedBehaviorSanitizer, and
+ // others. Please see SanitizerUserProps in build/soong/cc/sanitize.go for
+ // details.
+ Sanitize SanitizeUserProps `android:"arch_variant"`
+ SanitizerEnabled bool `blueprint:"mutated"`
+ SanitizeDep bool `blueprint:"mutated"`
+ MinimalRuntimeDep bool `blueprint:"mutated"`
+ BuiltinsDep bool `blueprint:"mutated"`
+ UbsanRuntimeDep bool `blueprint:"mutated"`
+ InSanitizerDir bool `blueprint:"mutated"`
+ Sanitizers []string `blueprint:"mutated"`
+ DiagSanitizers []string `blueprint:"mutated"`
}
type sanitize struct {
@@ -1037,7 +1040,7 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) {
if c.Device() {
variations = append(variations, c.ImageVariation())
}
- mctx.AddFarVariationDependencies(variations, depTag, runtimeLibrary)
+ c.addSharedLibDependenciesWithVersions(mctx, variations, depTag, runtimeLibrary, "", true)
}
// static lib does not have dependency to the runtime library. The
// dependency will be added to the executables or shared libs using
diff --git a/cc/stl.go b/cc/stl.go
index e18fe9547..406fa3a3e 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -17,7 +17,6 @@ package cc
import (
"android/soong/android"
"fmt"
- "strconv"
)
func getNdkStlFamily(m LinkableInterface) string {
@@ -136,23 +135,8 @@ func (stl *stl) begin(ctx BaseModuleContext) {
}
func needsLibAndroidSupport(ctx BaseModuleContext) bool {
- versionStr, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch())
- if err != nil {
- ctx.PropertyErrorf("sdk_version", err.Error())
- }
-
- if versionStr == "current" {
- return false
- }
-
- version, err := strconv.Atoi(versionStr)
- if err != nil {
- panic(fmt.Sprintf(
- "invalid API level returned from normalizeNdkApiLevel: %q",
- versionStr))
- }
-
- return version < 21
+ version := nativeApiLevelOrPanic(ctx, ctx.sdkVersion())
+ return version.LessThan(android.FirstNonLibAndroidSupportVersion)
}
func staticUnwinder(ctx android.BaseModuleContext) string {
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)