diff options
Diffstat (limited to 'cc')
49 files changed, 1674 insertions, 742 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 c899cdd72..f0e615217 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -83,6 +83,13 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries { if len(c.Properties.Logtags) > 0 { entries.AddStrings("LOCAL_LOGTAGS_FILES", c.Properties.Logtags...) } + // Note: Pass the exact value of AndroidMkSystemSharedLibs to the Make + // world, even if it is an empty list. In the Make world, + // LOCAL_SYSTEM_SHARED_LIBRARIES defaults to "none", which is expanded + // to the default list of system shared libs by the build system. + // Soong computes the exact list of system shared libs, so we have to + // override the default value when the list of libs is actually empty. + entries.SetString("LOCAL_SYSTEM_SHARED_LIBRARIES", strings.Join(c.Properties.AndroidMkSystemSharedLibs, " ")) if len(c.Properties.AndroidMkSharedLibs) > 0 { entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...) } @@ -377,6 +384,7 @@ func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android. if !BoolDefault(test.Properties.Auto_gen_config, true) { entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true) } + entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", test.Properties.Test_mainline_modules...) }) androidMkWriteTestData(test.data, ctx, entries) @@ -450,7 +458,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.go b/cc/binary.go index 6769fa778..b3ce5ff1c 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -83,7 +83,7 @@ func binaryHostFactory() android.Module { type binaryDecorator struct { *baseLinker *baseInstaller - stripper + stripper Stripper Properties BinaryLinkerProperties @@ -317,14 +317,14 @@ func (binary *binaryDecorator) link(ctx ModuleContext, } builderFlags := flagsToBuilderFlags(flags) - - if binary.stripper.needsStrip(ctx) { + stripFlags := flagsToStripFlags(flags) + if binary.stripper.NeedsStrip(ctx) { if ctx.Darwin() { - builderFlags.stripUseGnuStrip = true + stripFlags.StripUseGnuStrip = true } strippedOutputFile := outputFile outputFile = android.PathForModuleOut(ctx, "unstripped", fileName) - binary.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags) + binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, stripFlags) } binary.unstrippedOutputFile = outputFile @@ -333,7 +333,7 @@ func (binary *binaryDecorator) link(ctx ModuleContext, afterPrefixSymbols := outputFile outputFile = android.PathForModuleOut(ctx, "unprefixed", fileName) TransformBinaryPrefixSymbols(ctx, String(binary.Properties.Prefix_symbols), outputFile, - flagsToBuilderFlags(flags), afterPrefixSymbols) + builderFlags, afterPrefixSymbols) } outputFile = maybeInjectBoringSSLHash(ctx, outputFile, binary.Properties.Inject_bssl_hash, fileName) @@ -347,10 +347,10 @@ func (binary *binaryDecorator) link(ctx ModuleContext, versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName) binary.distFiles = android.MakeDefaultDistFiles(versionedOutputFile) - if binary.stripper.needsStrip(ctx) { + if binary.stripper.NeedsStrip(ctx) { out := android.PathForModuleOut(ctx, "versioned-stripped", fileName) binary.distFiles = android.MakeDefaultDistFiles(out) - binary.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags) + binary.stripper.StripExecutableOrSharedLib(ctx, versionedOutputFile, out, stripFlags) } binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile) @@ -445,7 +445,7 @@ func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) { // The original path becomes a symlink to the corresponding file in the // runtime APEX. translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled - if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() { + if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() { if ctx.Device() && isBionic(ctx.baseModuleName()) { binary.installSymlinkToRuntimeApex(ctx, file) } diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go index 337de55b3..55e400e8e 100644 --- a/cc/binary_sdk_member.go +++ b/cc/binary_sdk_member.go @@ -44,11 +44,15 @@ func (mt *binarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorConte for _, target := range targets { name, version := StubsLibNameAndVersion(lib) if version == "" { - version = LatestStubsVersionFor(mctx.Config(), name) + version = "latest" } - mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ - {Mutator: "version", Variation: version}, - }...), dependencyTag, name) + variations := target.Variations() + if mctx.Device() { + variations = append(variations, + blueprint.Variation{Mutator: "image", Variation: android.CoreVariation}, + blueprint.Variation{Mutator: "version", Variation: version}) + } + mctx.AddFarVariationDependencies(variations, dependencyTag, name) } } } diff --git a/cc/builder.go b/cc/builder.go index 2177a4498..81c09b1a1 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -69,12 +69,12 @@ var ( &remoteexec.REParams{ Labels: map[string]string{"type": "link", "tool": "clang"}, ExecStrategy: "${config.RECXXLinksExecStrategy}", - Inputs: []string{"${out}.rsp"}, + Inputs: []string{"${out}.rsp", "$implicitInputs"}, RSPFile: "${out}.rsp", OutputFiles: []string{"${out}", "$implicitOutputs"}, ToolchainInputs: []string{"$ldCmd"}, Platform: map[string]string{remoteexec.PoolKey: "${config.RECXXLinksPool}"}, - }, []string{"ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags", "extraLibFlags"}, []string{"implicitOutputs"}) + }, []string{"ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags", "extraLibFlags"}, []string{"implicitInputs", "implicitOutputs"}) partialLd, partialLdRE = remoteexec.StaticRules(pctx, "partialLd", blueprint.RuleParams{ @@ -83,12 +83,13 @@ var ( Command: "$reTemplate$ldCmd -fuse-ld=lld -nostdlib -no-pie -Wl,-r ${in} -o ${out} ${ldFlags}", CommandDeps: []string{"$ldCmd"}, }, &remoteexec.REParams{ - Labels: map[string]string{"type": "link", "tool": "clang"}, - ExecStrategy: "${config.RECXXLinksExecStrategy}", Inputs: []string{"$inCommaList"}, + Labels: map[string]string{"type": "link", "tool": "clang"}, + ExecStrategy: "${config.RECXXLinksExecStrategy}", + Inputs: []string{"$inCommaList", "$implicitInputs"}, OutputFiles: []string{"${out}", "$implicitOutputs"}, ToolchainInputs: []string{"$ldCmd"}, Platform: map[string]string{remoteexec.PoolKey: "${config.RECXXLinksPool}"}, - }, []string{"ldCmd", "ldFlags"}, []string{"inCommaList", "implicitOutputs"}) + }, []string{"ldCmd", "ldFlags"}, []string{"implicitInputs", "inCommaList", "implicitOutputs"}) ar = pctx.AndroidStaticRule("ar", blueprint.RuleParams{ @@ -186,8 +187,8 @@ var ( // OutputFile here is $in for remote-execution since its possible that // clang-tidy modifies the given input file itself and $out refers to the // ".tidy" file generated for ninja-dependency reasons. - OutputFiles: []string{"$in"}, - Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"}, + OutputFiles: []string{"$in"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"}, }, []string{"cFlags", "tidyFlags"}, []string{}) _ = pctx.SourcePathVariable("yasmCmd", "prebuilts/misc/${config.HostPrebuiltTag}/yasm/yasm") @@ -235,12 +236,12 @@ var ( }, &remoteexec.REParams{ Labels: map[string]string{"type": "tool", "name": "abi-linker"}, ExecStrategy: "${config.REAbiLinkerExecStrategy}", - Inputs: []string{"$sAbiLinkerLibs", "${out}.rsp", "$implicits"}, + Inputs: []string{"$sAbiLinkerLibs", "${out}.rsp", "$implicitInputs"}, RSPFile: "${out}.rsp", OutputFiles: []string{"$out"}, ToolchainInputs: []string{"$sAbiLinker"}, Platform: map[string]string{remoteexec.PoolKey: "${config.RECXXPool}"}, - }, []string{"symbolFilter", "arch", "exportedHeaderFlags"}, []string{"implicits"}) + }, []string{"symbolFilter", "arch", "exportedHeaderFlags"}, []string{"implicitInputs"}) _ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/header-abi-diff") @@ -264,9 +265,9 @@ var ( zip = pctx.AndroidStaticRule("zip", blueprint.RuleParams{ - Command: "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp", + Command: "${SoongZipCmd} -o ${out} -C $$OUT_DIR -r ${out}.rsp", CommandDeps: []string{"${SoongZipCmd}"}, - Rspfile: "$out.rsp", + Rspfile: "${out}.rsp", RspfileContent: "$in", }) @@ -348,18 +349,22 @@ type builderFlags struct { groupStaticLibs bool - stripKeepSymbols bool - stripKeepSymbolsList string - stripKeepSymbolsAndDebugFrame bool - stripKeepMiniDebugInfo bool - stripAddGnuDebuglink bool - stripUseGnuStrip bool - proto android.ProtoFlags protoC bool protoOptionsFile bool yacc *YaccProperties + lex *LexProperties +} + +type StripFlags struct { + Toolchain config.Toolchain + StripKeepSymbols bool + StripKeepSymbolsList string + StripKeepSymbolsAndDebugFrame bool + StripKeepMiniDebugInfo bool + StripAddGnuDebuglink bool + StripUseGnuStrip bool } type Objects struct { @@ -578,7 +583,7 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and tidyFiles = append(tidyFiles, tidyFile) rule := clangTidy - if ctx.Config().IsEnvTrue("RBE_CLANG_TIDY") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CLANG_TIDY") { rule = clangTidyRE } @@ -604,7 +609,7 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and sAbiDumpFiles = append(sAbiDumpFiles, sAbiDumpFile) dumpRule := sAbiDump - if ctx.Config().IsEnvTrue("RBE_ABI_DUMPER") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_DUMPER") { dumpRule = sAbiDumpRE } ctx.Build(pctx, android.BuildParams{ @@ -739,9 +744,10 @@ func TransformObjToDynamicBinary(ctx android.ModuleContext, "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags, "crtEnd": crtEnd.String(), } - if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") { rule = ldRE args["implicitOutputs"] = strings.Join(implicitOutputs.Strings(), ",") + args["implicitInputs"] = strings.Join(deps.Strings(), ",") } ctx.Build(pctx, android.BuildParams{ @@ -782,7 +788,7 @@ func TransformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Path "arch": ctx.Arch().ArchType.Name, "exportedHeaderFlags": exportedHeaderFlags, } - if ctx.Config().IsEnvTrue("RBE_ABI_LINKER") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_LINKER") { rule = sAbiLinkRE rbeImplicits := implicits.Strings() for _, p := range strings.Split(exportedHeaderFlags, " ") { @@ -791,7 +797,7 @@ func TransformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Path rbeImplicits = append(rbeImplicits, p[2:]) } } - args["implicits"] = strings.Join(rbeImplicits, ",") + args["implicitInputs"] = strings.Join(rbeImplicits, ",") } ctx.Build(pctx, android.BuildParams{ Rule: rule, @@ -905,9 +911,10 @@ func TransformObjsToObj(ctx android.ModuleContext, objFiles android.Paths, "ldCmd": ldCmd, "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags, } - if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") { rule = partialLdRE args["inCommaList"] = strings.Join(objFiles.Strings(), ",") + args["implicitInputs"] = strings.Join(deps.Strings(), ",") } ctx.Build(pctx, android.BuildParams{ Rule: rule, @@ -938,26 +945,26 @@ func TransformBinaryPrefixSymbols(ctx android.ModuleContext, prefix string, inpu } func TransformStrip(ctx android.ModuleContext, inputFile android.Path, - outputFile android.WritablePath, flags builderFlags) { + outputFile android.WritablePath, flags StripFlags) { - crossCompile := gccCmd(flags.toolchain, "") + crossCompile := gccCmd(flags.Toolchain, "") args := "" - if flags.stripAddGnuDebuglink { + if flags.StripAddGnuDebuglink { args += " --add-gnu-debuglink" } - if flags.stripKeepMiniDebugInfo { + if flags.StripKeepMiniDebugInfo { args += " --keep-mini-debug-info" } - if flags.stripKeepSymbols { + if flags.StripKeepSymbols { args += " --keep-symbols" } - if flags.stripKeepSymbolsList != "" { - args += " -k" + flags.stripKeepSymbolsList + if flags.StripKeepSymbolsList != "" { + args += " -k" + flags.StripKeepSymbolsList } - if flags.stripKeepSymbolsAndDebugFrame { + if flags.StripKeepSymbolsAndDebugFrame { args += " --keep-symbols-and-debug-frame" } - if flags.stripUseGnuStrip { + if flags.StripUseGnuStrip { args += " --use-gnu-strip" } @@ -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 @@ -210,6 +214,7 @@ type Flags struct { protoOptionsFile bool // Whether to look for a .options file next to the .proto Yacc *YaccProperties + Lex *LexProperties } // Properties used to compile all C or C++ modules @@ -236,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"` @@ -279,6 +287,13 @@ type BaseProperties struct { // Set when both SDK and platform variants are exported to Make to trigger renaming the SDK // variant to have a ".sdk" suffix. SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"` + + // Normally Soong uses the directory structure to decide which modules + // should be included (framework) or excluded (non-framework) from the + // vendor snapshot, but this property allows a partner to exclude a + // module normally thought of as a framework module from the vendor + // snapshot. + Exclude_from_vendor_snapshot *bool } type VendorProperties struct { @@ -345,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 @@ -606,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 { @@ -621,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())) @@ -776,7 +791,28 @@ func (c *Module) BuildStubs() bool { 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 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 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 @@ -787,7 +823,7 @@ func (c *Module) SetStubsVersions(version string) { 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 { @@ -920,9 +956,9 @@ func (c *Module) Init() android.Module { c.AddProperties(feature.props()...) } - c.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool { + c.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, os android.OsType) bool { // Windows builds always prefer 32-bit - return class == android.HostCross + return os == android.Windows }) android.InitAndroidArchModule(c, c.hod, c.multilib) android.InitApexModule(c) @@ -1107,6 +1143,10 @@ func (c *Module) ExportedGeneratedHeaders() android.Paths { return nil } +func (c *Module) ExcludeFromVendorSnapshot() bool { + return Bool(c.Properties.Exclude_from_vendor_snapshot) +} + func isBionic(name string) bool { switch name { case "libc", "libm", "libdl", "libdl_android", "linker": @@ -1294,7 +1334,7 @@ func (ctx *moduleContextImpl) apexVariationName() string { return ctx.mod.ApexVariationName() } -func (ctx *moduleContextImpl) apexSdkVersion() int { +func (ctx *moduleContextImpl) apexSdkVersion() android.ApiLevel { return ctx.mod.apexSdkVersion } @@ -1670,11 +1710,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) } } @@ -1803,6 +1845,8 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { deps := c.deps(ctx) + c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs + variantNdkLibs := []string{} variantLateNdkLibs := []string{} if ctx.Os() == android.Android { @@ -1982,18 +2026,20 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) depTag.explicitlyVersioned = true } - actx.AddVariationDependencies(variations, depTag, name) + deps := 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) + if dep, ok := deps[0].(*Module); ok { + for _, ver := range dep.AllStubsVersions() { + // Note that depTag.ExplicitlyVersioned is false in this case. + ctx.AddVariationDependencies([]blueprint.Variation{ + {Mutator: "link", Variation: "shared"}, + {Mutator: "version", Variation: ver}, + }, depTag, name) + } } } } @@ -2279,7 +2325,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // For the dependency from platform to apex, use the latest stubs c.apexSdkVersion = android.FutureApiLevel if !c.IsForPlatform() { - c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion + c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion(ctx) } if android.InList("hwaddress", ctx.Config().SanitizeDevice()) { @@ -2383,7 +2429,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if libDepTag, ok := depTag.(libraryDependencyTag); ok { // Only use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859) - if libDepTag.staticUnwinder && c.apexSdkVersion > android.SdkVersion_Android10 { + if libDepTag.staticUnwinder && c.apexSdkVersion.GreaterThan(android.SdkVersion_Android10) { return } @@ -2427,7 +2473,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // when to use (unspecified) stubs, check min_sdk_version and choose the right one if useThisDep && depIsStubs && !libDepTag.explicitlyVersioned { - versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), c.apexSdkVersion) + versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), c.apexSdkVersion.FinalOrFutureInt()) if err != nil { ctx.OtherModuleErrorf(dep, err.Error()) return @@ -2445,12 +2491,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(versions, c.apexSdkVersion.FinalOrFutureInt()) if err != nil { ctx.OtherModuleErrorf(dep, err.Error()) return @@ -2974,21 +3020,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 @@ -3012,11 +3045,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 @@ -3107,13 +3146,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 77b5c527b..132d09136 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -258,7 +258,8 @@ func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string } } -func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { +func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string, include bool) { + t.Helper() mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer) if !ok { t.Errorf("%q must have output\n", moduleName) @@ -271,12 +272,27 @@ func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.Tes } snapshotPath := filepath.Join(subDir, snapshotFilename) - out := singleton.Output(snapshotPath) - if out.Input.String() != outputFiles[0].String() { - t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0]) + if include { + out := singleton.Output(snapshotPath) + if out.Input.String() != outputFiles[0].String() { + t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0]) + } + } else { + out := singleton.MaybeOutput(snapshotPath) + if out.Rule != nil { + t.Errorf("There must be no rule for module %q output file %q", moduleName, outputFiles[0]) + } } } +func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { + checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true) +} + +func checkSnapshotExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { + checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, false) +} + func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) { t.Helper() assertString(t, params.Rule.String(), android.WriteFile.String()) @@ -930,7 +946,7 @@ func TestDoubleLoadbleDep(t *testing.T) { `) } -func TestVendorSnapshot(t *testing.T) { +func TestVendorSnapshotCapture(t *testing.T) { bp := ` cc_library { name: "libvndk", @@ -1063,6 +1079,215 @@ func TestVendorSnapshot(t *testing.T) { } } +func TestVendorSnapshotUse(t *testing.T) { + frameworkBp := ` + cc_library { + name: "libvndk", + vendor_available: true, + vndk: { + enabled: true, + }, + nocrt: true, + compile_multilib: "64", + } + + cc_library { + name: "libvendor", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + compile_multilib: "64", + } + + cc_binary { + name: "bin", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + compile_multilib: "64", + } +` + + vndkBp := ` + vndk_prebuilt_shared { + name: "libvndk", + version: "BOARD", + target_arch: "arm64", + vendor_available: true, + vndk: { + enabled: true, + }, + arch: { + arm64: { + srcs: ["libvndk.so"], + }, + }, + } +` + + vendorProprietaryBp := ` + cc_library { + name: "libvendor_without_snapshot", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + compile_multilib: "64", + } + + cc_library_shared { + name: "libclient", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + shared_libs: ["libvndk"], + static_libs: ["libvendor", "libvendor_without_snapshot"], + compile_multilib: "64", + } + + cc_binary { + name: "bin_without_snapshot", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + static_libs: ["libvndk"], + compile_multilib: "64", + } + + vendor_snapshot_static { + name: "libvndk", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "libvndk.a", + }, + }, + } + + vendor_snapshot_shared { + name: "libvendor", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "libvendor.so", + }, + }, + } + + vendor_snapshot_static { + name: "libvendor", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "libvendor.a", + }, + }, + } + + vendor_snapshot_binary { + name: "bin", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "bin", + }, + }, + } +` + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "framework/Android.bp": []byte(frameworkBp), + "vendor/Android.bp": []byte(vendorProprietaryBp), + "vendor/libvndk.a": nil, + "vendor/libvendor.a": nil, + "vendor/libvendor.so": nil, + "vendor/bin": nil, + "vndk/Android.bp": []byte(vndkBp), + "vndk/libvndk.so": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext() + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "vendor/Android.bp", "vndk/Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + sharedVariant := "android_vendor.BOARD_arm64_armv8-a_shared" + staticVariant := "android_vendor.BOARD_arm64_armv8-a_static" + binaryVariant := "android_vendor.BOARD_arm64_armv8-a" + + // libclient uses libvndk.vndk.BOARD.arm64, libvendor.vendor_static.BOARD.arm64, libvendor_without_snapshot + libclientLdRule := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld") + libclientFlags := libclientLdRule.Args["libFlags"] + + for _, input := range [][]string{ + []string{sharedVariant, "libvndk.vndk.BOARD.arm64"}, + []string{staticVariant, "libvendor.vendor_static.BOARD.arm64"}, + []string{staticVariant, "libvendor_without_snapshot"}, + } { + outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */) + if !strings.Contains(libclientFlags, outputPaths[0].String()) { + t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientFlags) + } + } + + // bin_without_snapshot uses libvndk.vendor_static.BOARD.arm64 + binWithoutSnapshotLdRule := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld") + binWithoutSnapshotFlags := binWithoutSnapshotLdRule.Args["libFlags"] + libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.BOARD.arm64"}) + if !strings.Contains(binWithoutSnapshotFlags, libVndkStaticOutputPaths[0].String()) { + t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v", + libVndkStaticOutputPaths[0], binWithoutSnapshotFlags) + } + + // libvendor.so is installed by libvendor.vendor_shared.BOARD.arm64 + ctx.ModuleForTests("libvendor.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor.so") + + // libvendor_without_snapshot.so is installed by libvendor_without_snapshot + ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so") + + // bin is installed by bin.vendor_binary.BOARD.arm64 + ctx.ModuleForTests("bin.vendor_binary.BOARD.arm64", binaryVariant).Output("bin") + + // bin_without_snapshot is installed by bin_without_snapshot + ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot") + + // libvendor and bin don't have vendor.BOARD variant + libvendorVariants := ctx.ModuleVariantsForTests("libvendor") + if inList(sharedVariant, libvendorVariants) { + t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant) + } + + binVariants := ctx.ModuleVariantsForTests("bin") + if inList(binaryVariant, binVariants) { + t.Errorf("bin must not have variant %#v, but it does", sharedVariant) + } +} + func TestVendorSnapshotSanitizer(t *testing.T) { bp := ` vendor_snapshot_static { @@ -1096,6 +1321,203 @@ func TestVendorSnapshotSanitizer(t *testing.T) { assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a") } +func assertExcludeFromVendorSnapshotIs(t *testing.T, c *Module, expected bool) { + t.Helper() + if c.ExcludeFromVendorSnapshot() != expected { + t.Errorf("expected %q ExcludeFromVendorSnapshot to be %t", c.String(), expected) + } +} + +func TestVendorSnapshotExclude(t *testing.T) { + + // This test verifies that the exclude_from_vendor_snapshot property + // makes its way from the Android.bp source file into the module data + // structure. It also verifies that modules are correctly included or + // excluded in the vendor snapshot based on their path (framework or + // vendor) and the exclude_from_vendor_snapshot property. + + frameworkBp := ` + cc_library_shared { + name: "libinclude", + srcs: ["src/include.cpp"], + vendor_available: true, + } + cc_library_shared { + name: "libexclude", + srcs: ["src/exclude.cpp"], + vendor: true, + exclude_from_vendor_snapshot: true, + } + ` + + vendorProprietaryBp := ` + cc_library_shared { + name: "libvendor", + srcs: ["vendor.cpp"], + vendor: true, + } + ` + + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "framework/Android.bp": []byte(frameworkBp), + "framework/include.cpp": nil, + "framework/exclude.cpp": nil, + "device/Android.bp": []byte(vendorProprietaryBp), + "device/vendor.cpp": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext() + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + // Test an include and exclude framework module. + assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libinclude", coreVariant).Module().(*Module), false) + assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libinclude", vendorVariant).Module().(*Module), false) + assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libexclude", vendorVariant).Module().(*Module), true) + + // A vendor module is excluded, but by its path, not the + // exclude_from_vendor_snapshot property. + assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libvendor", vendorVariant).Module().(*Module), false) + + // Verify the content of the vendor snapshot. + + snapshotDir := "vendor-snapshot" + snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") + + var includeJsonFiles []string + var excludeJsonFiles []string + + for _, arch := range [][]string{ + []string{"arm64", "armv8-a"}, + []string{"arm", "armv7-a-neon"}, + } { + archType := arch[0] + archVariant := arch[1] + archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) + + sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + + // Included modules + checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) + + // Excluded modules + checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json")) + checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json")) + } + + // Verify that each json file for an included module has a rule. + for _, jsonFile := range includeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { + t.Errorf("include json file %q not found", jsonFile) + } + } + + // Verify that each json file for an excluded module has no rule. + for _, jsonFile := range excludeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil { + t.Errorf("exclude json file %q found", jsonFile) + } + } +} + +func TestVendorSnapshotExcludeInVendorProprietaryPathErrors(t *testing.T) { + + // This test verifies that using the exclude_from_vendor_snapshot + // property on a module in a vendor proprietary path generates an + // error. These modules are already excluded, so we prohibit using the + // property in this way, which could add to confusion. + + vendorProprietaryBp := ` + cc_library_shared { + name: "libvendor", + srcs: ["vendor.cpp"], + vendor: true, + exclude_from_vendor_snapshot: true, + } + ` + + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "device/Android.bp": []byte(vendorProprietaryBp), + "device/vendor.cpp": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext() + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "device/Android.bp"}) + android.FailIfErrored(t, errs) + + _, errs = ctx.PrepareBuildActions(config) + android.CheckErrorsAgainstExpectations(t, errs, []string{ + `module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, + `module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, + }) +} + +func TestVendorSnapshotExcludeWithVendorAvailable(t *testing.T) { + + // This test verifies that using the exclude_from_vendor_snapshot + // property on a module that is vendor available generates an error. A + // vendor available module must be captured in the vendor snapshot and + // must not built from source when building the vendor image against + // the vendor snapshot. + + frameworkBp := ` + cc_library_shared { + name: "libinclude", + srcs: ["src/include.cpp"], + vendor_available: true, + exclude_from_vendor_snapshot: true, + } + ` + + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "framework/Android.bp": []byte(frameworkBp), + "framework/include.cpp": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext() + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp"}) + android.FailIfErrored(t, errs) + + _, errs = ctx.PrepareBuildActions(config) + android.CheckErrorsAgainstExpectations(t, errs, []string{ + `module "libinclude\{.+,image:,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, + `module "libinclude\{.+,image:,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, + `module "libinclude\{.+,image:vendor.+,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, + `module "libinclude\{.+,image:vendor.+,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, + }) +} + func TestDoubleLoadableDepError(t *testing.T) { // Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` @@ -2603,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"+ diff --git a/cc/compiler.go b/cc/compiler.go index e06243b50..bb5c7bf2a 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -111,6 +111,7 @@ type BaseCompilerProperties struct { Gnu_extensions *bool Yacc *YaccProperties + Lex *LexProperties Aidl struct { // list of directories that will be added to the aidl include paths. @@ -189,8 +190,14 @@ type BaseCompilerProperties struct { // Build and link with OpenMP Openmp *bool `android:"arch_variant"` + // Deprecated. // Adds __ANDROID_APEX_<APEX_MODULE_NAME>__ macro defined for apex variants in addition to __ANDROID_APEX__ Use_apex_name_macro *bool + + // Adds two macros for apex variants in addition to __ANDROID_APEX__ + // * __ANDROID_APEX_COM_ANDROID_FOO__ + // * __ANDROID_APEX_NAME__="com.android.foo" + UseApexNameMacro bool `blueprint:"mutated"` } func NewBaseCompiler() *baseCompiler { @@ -254,6 +261,10 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { return deps } +func (compiler *baseCompiler) useApexNameMacro() bool { + return Bool(compiler.Properties.Use_apex_name_macro) || compiler.Properties.UseApexNameMacro +} + // Return true if the module is in the WarningAllowedProjects. func warningsAreAllowed(subdir string) bool { subdir += "/" @@ -289,6 +300,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Local.YasmFlags = append(flags.Local.YasmFlags, esc(compiler.Properties.Asflags)...) flags.Yacc = compiler.Properties.Yacc + flags.Lex = compiler.Properties.Lex // Include dir cflags localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs) @@ -337,14 +349,21 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps if ctx.apexVariationName() != "" { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX__") - if Bool(compiler.Properties.Use_apex_name_macro) { + if compiler.useApexNameMacro() { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexVariationName())+"__") + 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 @@ -373,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 } @@ -557,13 +576,15 @@ func (compiler *baseCompiler) hasSrcExt(ext string) bool { } func (compiler *baseCompiler) uniqueApexVariations() bool { - return Bool(compiler.Properties.Use_apex_name_macro) + return compiler.useApexNameMacro() } +var invalidDefineCharRegex = regexp.MustCompile("[^a-zA-Z0-9_]") + // makeDefineString transforms a name of an APEX module into a value to be used as value for C define // For example, com.android.foo => COM_ANDROID_FOO func makeDefineString(name string) string { - return strings.ReplaceAll(strings.ToUpper(name), ".", "_") + return invalidDefineCharRegex.ReplaceAllString(strings.ToUpper(name), "_") } var gnuToCReplacer = strings.NewReplacer("gnu", "c") diff --git a/cc/config/Android.bp b/cc/config/Android.bp index 6275064f5..ce4bdfb50 100644 --- a/cc/config/Android.bp +++ b/cc/config/Android.bp @@ -23,6 +23,8 @@ bootstrap_go_package { "x86_linux_host.go", "x86_linux_bionic_host.go", "x86_windows_host.go", + + "arm64_linux_host.go", ], testSrcs: [ "tidy_test.go", 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/arm64_linux_host.go b/cc/config/arm64_linux_host.go new file mode 100644 index 000000000..74642c2cf --- /dev/null +++ b/cc/config/arm64_linux_host.go @@ -0,0 +1,94 @@ +// 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 config + +import ( + "android/soong/android" + "strings" +) + +var ( + // This is a host toolchain but flags for device toolchain are required + // as the flags are actually for Bionic-based builds. + linuxCrossCflags = ClangFilterUnknownCflags(append(deviceGlobalCflags, + // clang by default enables PIC when the clang triple is set to *-android. + // See toolchain/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp#920. + // However, for this host target, we don't set "-android" to avoid __ANDROID__ macro + // which stands for "Android device target". Keeping PIC on is required because + // many modules we have (e.g. Bionic) assume PIC. + "-fpic", + )) + + linuxCrossLdflags = ClangFilterUnknownCflags([]string{ + "-Wl,-z,noexecstack", + "-Wl,-z,relro", + "-Wl,-z,now", + "-Wl,--build-id=md5", + "-Wl,--warn-shared-textrel", + "-Wl,--fatal-warnings", + "-Wl,--hash-style=gnu", + "-Wl,--no-undefined-version", + }) +) + +func init() { + pctx.StaticVariable("LinuxBionicArm64Cflags", strings.Join(linuxCrossCflags, " ")) + pctx.StaticVariable("LinuxBionicArm64Ldflags", strings.Join(linuxCrossLdflags, " ")) +} + +// toolchain config for ARM64 Linux CrossHost. Almost everything is the same as the ARM64 Android +// target. The overridden methods below show the differences. +type toolchainLinuxArm64 struct { + toolchainArm64 +} + +func (toolchainLinuxArm64) ClangTriple() string { + // Note the absence of "-android" suffix. The compiler won't define __ANDROID__ + return "aarch64-linux" +} + +func (toolchainLinuxArm64) ClangCflags() string { + // The inherited flags + extra flags + return "${config.Arm64ClangCflags} ${config.LinuxBionicArm64Cflags}" +} + +func linuxArm64ToolchainFactory(arch android.Arch) Toolchain { + archVariant := "armv8-a" // for host, default to armv8-a + toolchainClangCflags := []string{arm64ClangArchVariantCflagsVar[archVariant]} + + // We don't specify CPU architecture for host. Conservatively assume + // the host CPU needs the fix + extraLdflags := "-Wl,--fix-cortex-a53-843419" + + ret := toolchainLinuxArm64{} + + // add the extra ld and lld flags + ret.toolchainArm64.ldflags = strings.Join([]string{ + "${config.Arm64Ldflags}", + "${config.LinuxBionicArm64Ldflags}", + extraLdflags, + }, " ") + ret.toolchainArm64.lldflags = strings.Join([]string{ + "${config.Arm64Lldflags}", + "${config.LinuxBionicArm64Ldflags}", + extraLdflags, + }, " ") + ret.toolchainArm64.toolchainClangCflags = strings.Join(toolchainClangCflags, " ") + return &ret +} + +func init() { + registerToolchainFactory(android.LinuxBionic, android.Arm64, linuxArm64ToolchainFactory) +} 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..f9b3cc8dd 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-r399163" + ClangDefaultShortVersion = "11.0.4" // Directories with warnings from Android.bp files. WarningAllowedProjects = []string{ diff --git a/cc/config/vndk.go b/cc/config/vndk.go index 54f693e0b..6f2e80741 100644 --- a/cc/config/vndk.go +++ b/cc/config/vndk.go @@ -18,10 +18,12 @@ package config // For these libraries, the vendor variants must be installed even if the device // has VndkUseCoreVariant set. var VndkMustUseVendorVariantList = []string{ + "android.hardware.automotive.occupant_awareness-ndk_platform", "android.hardware.light-ndk_platform", "android.hardware.identity-ndk_platform", "android.hardware.nfc@1.2", "android.hardware.power-ndk_platform", + "android.hardware.rebootescrow-ndk_platform", "android.hardware.vibrator-ndk_platform", "libbinder", "libcrypto", diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go index cd0a50837..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{}...) @@ -49,7 +52,11 @@ var ( windowsClangCppflags = []string{} - windowsX86ClangCppflags = []string{} + windowsX86ClangCppflags = []string{ + // Use SjLj exceptions for 32-bit. libgcc_eh implements SjLj + // exception model for 32-bit. + "-fsjlj-exceptions", + } windowsX8664ClangCppflags = []string{} diff --git a/cc/fuzz.go b/cc/fuzz.go index 58c1888ad..529541859 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -402,7 +402,7 @@ func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { command := builder.Command().BuiltTool(ctx, "soong_zip"). Flag("-j"). FlagWithOutput("-o ", corpusZip) - command.FlagWithRspFileInputList("-l ", fuzzModule.corpus) + command.FlagWithRspFileInputList("-r ", fuzzModule.corpus) files = append(files, fileToZip{corpusZip, ""}) } @@ -34,9 +34,9 @@ func init() { var ( lex = pctx.AndroidStaticRule("lex", blueprint.RuleParams{ - Command: "M4=$m4Cmd $lexCmd -o$out $in", + Command: "M4=$m4Cmd $lexCmd $flags -o$out $in", CommandDeps: []string{"$lexCmd", "$m4Cmd"}, - }) + }, "flags") sysprop = pctx.AndroidStaticRule("sysprop", blueprint.RuleParams{ @@ -153,12 +153,23 @@ func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile andr } } -func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath) { +type LexProperties struct { + // list of module-specific flags that will be used for .l and .ll compiles + Flags []string +} + +func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath, props *LexProperties) { + var flags []string + if props != nil { + flags = props.Flags + } + flagsString := strings.Join(flags[:], " ") ctx.Build(pctx, android.BuildParams{ Rule: lex, Description: "lex " + lexFile.Rel(), Output: outFile, Input: lexFile, + Args: map[string]string{"flags": flagsString}, }) } @@ -235,11 +246,11 @@ func genSources(ctx android.ModuleContext, srcFiles android.Paths, case ".l": cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c") srcFiles[i] = cFile - genLex(ctx, srcFile, cFile) + genLex(ctx, srcFile, cFile, buildFlags.lex) case ".ll": cppFile := android.GenPathWithExt(ctx, "lex", srcFile, "cpp") srcFiles[i] = cppFile - genLex(ctx, srcFile, cppFile) + genLex(ctx, srcFile, cppFile, buildFlags.lex) case ".proto": ccFile, headerFile := genProto(ctx, srcFile, buildFlags) srcFiles[i] = ccFile diff --git a/cc/genrule.go b/cc/genrule.go index 66d178456..cce4a83d3 100644 --- a/cc/genrule.go +++ b/cc/genrule.go @@ -84,7 +84,7 @@ func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleCont // If not, we assume modules under proprietary paths are compatible for // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is // PLATFORM_VNDK_VERSION. - if vndkVersion == "current" || !isVendorProprietaryPath(ctx.ModuleDir()) { + if vndkVersion == "current" || !isVendorProprietaryModule(ctx) { variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion()) } else { variants = append(variants, VendorVariationPrefix+vndkVersion) diff --git a/cc/image.go b/cc/image.go index 4daed7c00..ea6f5675c 100644 --- a/cc/image.go +++ b/cc/image.go @@ -223,7 +223,7 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { // We assume that modules under proprietary paths are compatible for // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or // PLATFORM_VNDK_VERSION. - if isVendorProprietaryPath(mctx.ModuleDir()) { + if isVendorProprietaryModule(mctx) { vendorVariants = append(vendorVariants, boardVndkVersion) } else { vendorVariants = append(vendorVariants, platformVndkVersion) @@ -249,7 +249,7 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { platformVndkVersion, boardVndkVersion, ) - } else if isVendorProprietaryPath(mctx.ModuleDir()) { + } else if isVendorProprietaryModule(mctx) { vendorVariants = append(vendorVariants, boardVndkVersion) } else { vendorVariants = append(vendorVariants, platformVndkVersion) diff --git a/cc/library.go b/cc/library.go index 1c2b1ee88..8048f0002 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 { @@ -336,7 +336,7 @@ type libraryDecorator struct { tocFile android.OptionalPath flagExporter - stripper + stripper Stripper // If we're used as a whole_static_lib, our missing dependencies need // to be given @@ -955,13 +955,14 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, library.tocFile = android.OptionalPathForPath(tocFile) TransformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags) - if library.stripper.needsStrip(ctx) { + stripFlags := flagsToStripFlags(flags) + if library.stripper.NeedsStrip(ctx) { if ctx.Darwin() { - builderFlags.stripUseGnuStrip = true + stripFlags.StripUseGnuStrip = true } strippedOutputFile := outputFile outputFile = android.PathForModuleOut(ctx, "unstripped", fileName) - library.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags) + library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, stripFlags) } library.unstrippedOutputFile = outputFile @@ -976,10 +977,10 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName) library.distFile = versionedOutputFile - if library.stripper.needsStrip(ctx) { + if library.stripper.NeedsStrip(ctx) { out := android.PathForModuleOut(ctx, "versioned-stripped", fileName) library.distFile = out - library.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags) + library.stripper.StripExecutableOrSharedLib(ctx, versionedOutputFile, out, stripFlags) } library.injectVersionSymbol(ctx, outputFile, versionedOutputFile) @@ -1027,6 +1028,10 @@ func (library *libraryDecorator) unstrippedOutputFilePath() android.Path { return library.unstrippedOutputFile } +func (library *libraryDecorator) disableStripping() { + library.stripper.StripProperties.Strip.None = BoolPtr(true) +} + func (library *libraryDecorator) nativeCoverage() bool { if library.header() || library.buildStubs() { return false @@ -1512,56 +1517,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 { @@ -1572,44 +1560,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 cff00b668..2f1554427 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -80,20 +80,21 @@ 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() { + variations = append(variations, + blueprint.Variation{Mutator: "image", Variation: android.CoreVariation}, + blueprint.Variation{Mutator: "version", Variation: version}) } if mt.linkTypes == nil { - mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ - {Mutator: "image", Variation: android.CoreVariation}, - {Mutator: "version", Variation: version}, - }...), dependencyTag, name) + mctx.AddFarVariationDependencies(variations, dependencyTag, name) } else { for _, linkType := range mt.linkTypes { - mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ - {Mutator: "image", Variation: android.CoreVariation}, - {Mutator: "link", Variation: linkType}, - {Mutator: "version", Variation: version}, - }...), dependencyTag, name) + libVariations := append(variations, + blueprint.Variation{Mutator: "link", Variation: linkType}) + mctx.AddFarVariationDependencies(libVariations, dependencyTag, name) } } } @@ -118,6 +119,14 @@ func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, ccModule := member.Variants()[0].(*Module) + if proptools.Bool(ccModule.Properties.Recovery_available) { + pbm.AddProperty("recovery_available", true) + } + + if proptools.Bool(ccModule.VendorProperties.Vendor_available) { + pbm.AddProperty("vendor_available", true) + } + sdkVersion := ccModule.SdkVersion() if sdkVersion != "" { pbm.AddProperty("sdk_version", sdkVersion) @@ -212,6 +221,11 @@ 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) + } + // Copy the generated library to the snapshot and add a reference to it in the .bp module. if libInfo.outputFile != nil { nativeLibraryPath := nativeLibraryPathFor(libInfo) @@ -277,8 +291,8 @@ func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, b } // Add the collated include dir properties to the output. - for property, dirs := range includeDirs { - outputProperties.AddProperty(property, dirs) + for _, property := range android.SortedStringKeys(includeDirs) { + outputProperties.AddProperty(property, includeDirs[property]) } if len(libInfo.StubsVersion) > 0 { @@ -359,6 +373,9 @@ type nativeLibInfoProperties struct { // not vary by arch so cannot be android specific. StubsVersion string `sdk:"ignored-on-host"` + // Value of SanitizeProperties.Sanitize.Never. Needs to be propagated for CRT objects. + SanitizeNever bool `android:"arch_variant"` + // outputFile is not exported as it is always arch specific. outputFile android.Path } @@ -405,6 +422,10 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte if ccModule.HasStubsVariants() { p.StubsVersion = ccModule.StubsVersion() } + + if ccModule.sanitize != nil && proptools.Bool(ccModule.sanitize.Properties.Sanitize.Never) { + p.SanitizeNever = true + } } func getRequiredMemberOutputFile(ctx android.SdkMemberContext, ccModule *Module) android.Path { 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/llndk_library.go b/cc/llndk_library.go index 71c92042a..b3f9d6177 100644 --- a/cc/llndk_library.go +++ b/cc/llndk_library.go @@ -179,7 +179,7 @@ func NewLLndkStubLibrary() *Module { library.BuildOnlyShared() module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() stub := &llndkStubDecorator{ libraryDecorator: library, @@ -45,6 +45,8 @@ type LTOProperties struct { Thin *bool `android:"arch_variant"` } `android:"arch_variant"` + GlobalThin *bool `blueprint:"mutated"` + // Dep properties indicate that this module needs to be built with LTO // since it is an object dependency of an LTO module. FullDep bool `blueprint:"mutated"` @@ -52,6 +54,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 +70,8 @@ func (lto *lto) props() []interface{} { func (lto *lto) begin(ctx BaseModuleContext) { if ctx.Config().IsEnvTrue("DISABLE_LTO") { lto.Properties.Lto.Never = boolPtr(true) + } else if ctx.Config().IsEnvTrue("GLOBAL_THINLTO") { + lto.Properties.GlobalThin = boolPtr(true) } } @@ -88,7 +95,7 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { if lto.LTO() { var ltoFlag string - if Bool(lto.Properties.Lto.Thin) { + if lto.ThinLTO() { ltoFlag = "-flto=thin -fsplit-lto-unit" } else { ltoFlag = "-flto" @@ -97,7 +104,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 +121,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 @@ -127,9 +137,21 @@ func (lto *lto) LTO() bool { return false } - full := Bool(lto.Properties.Lto.Full) - thin := Bool(lto.Properties.Lto.Thin) - return full || thin + return lto.FullLTO() || lto.ThinLTO() +} + +func (lto *lto) FullLTO() bool { + return Bool(lto.Properties.Lto.Full) +} + +func (lto *lto) ThinLTO() bool { + if Bool(lto.Properties.GlobalThin) { + if !lto.Disabled() && !lto.FullLTO() { + return true + } + } + + return Bool(lto.Properties.Lto.Thin) } // Is lto.never explicitly set to true? @@ -140,8 +162,8 @@ func (lto *lto) Disabled() bool { // 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") } @@ -163,10 +185,10 @@ 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) { + 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 +205,19 @@ func ltoMutator(mctx android.BottomUpMutatorContext) { // Create variations for LTO types required as static // dependencies variationNames := []string{""} - if m.lto.Properties.FullDep && !Bool(m.lto.Properties.Lto.Full) { + if m.lto.Properties.FullDep && !m.lto.FullLTO() { variationNames = append(variationNames, "lto-full") } - if m.lto.Properties.ThinDep && !Bool(m.lto.Properties.Lto.Thin) { + if m.lto.Properties.ThinDep && !m.lto.ThinLTO() { variationNames = append(variationNames, "lto-thin") } // Use correct dependencies if LTO property is explicitly set // (mutually exclusive) - if Bool(m.lto.Properties.Lto.Full) { + if m.lto.FullLTO() { mctx.SetDependencyVariation("lto-full") } - if Bool(m.lto.Properties.Lto.Thin) { + if m.lto.ThinLTO() { mctx.SetDependencyVariation("lto-thin") } diff --git a/cc/ndk_library.go b/cc/ndk_library.go index 58e742e5f..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) } @@ -405,7 +343,7 @@ func newStubLibrary() *Module { library.BuildOnlyShared() module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() stub := &stubDecorator{ libraryDecorator: library, 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) @@ -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,21 +288,52 @@ 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() { - props.addInstrumentationProfileGatherFlags(ctx, flags) + if (props.ShouldProfileModule && props.isInstrumentation()) || props.PgoInstrLink { // Instrumentation PGO use and gather flags cannot coexist. - return flags + return props.addInstrumentationProfileGatherFlags(ctx, flags) } else if props.ShouldProfileModule && props.isSampling() { - props.addSamplingProfileGatherFlags(ctx, flags) + flags = props.addSamplingProfileGatherFlags(ctx, flags) } else if ctx.DeviceConfig().SamplingPGO() { - props.addSamplingProfileGatherFlags(ctx, flags) + flags = props.addSamplingProfileGatherFlags(ctx, flags) } if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") { - props.addProfileUseFlags(ctx, flags) + flags = props.addProfileUseFlags(ctx, flags) } return flags diff --git a/cc/prebuilt.go b/cc/prebuilt.go index baf43ce0f..9d1b01608 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -16,6 +16,7 @@ package cc import ( "android/soong/android" + "path/filepath" ) func init() { @@ -125,9 +126,10 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, outputFile := android.PathForModuleOut(ctx, libName) var implicits android.Paths - if p.needsStrip(ctx) { + if p.stripper.NeedsStrip(ctx) { + stripFlags := flagsToStripFlags(flags) stripped := android.PathForModuleOut(ctx, "stripped", libName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags) in = stripped } @@ -323,35 +325,73 @@ func prebuiltObjectFactory() android.Module { type prebuiltBinaryLinker struct { *binaryDecorator prebuiltLinker + + toolPath android.OptionalPath } var _ prebuiltLinkerInterface = (*prebuiltBinaryLinker)(nil) +func (p *prebuiltBinaryLinker) hostToolPath() android.OptionalPath { + return p.toolPath +} + func (p *prebuiltBinaryLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { // TODO(ccross): verify shared library dependencies if len(p.properties.Srcs) > 0 { - builderFlags := flagsToBuilderFlags(flags) - fileName := p.getStem(ctx) + flags.Toolchain.ExecutableSuffix() in := p.Prebuilt.SingleSourcePath(ctx) - + outputFile := android.PathForModuleOut(ctx, fileName) p.unstrippedOutputFile = in - if p.needsStrip(ctx) { - stripped := android.PathForModuleOut(ctx, "stripped", fileName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) - in = stripped - } + if ctx.Host() { + // Host binaries are symlinked to their prebuilt source locations. That + // way they are executed directly from there so the linker resolves their + // shared library dependencies relative to that location (using + // $ORIGIN/../lib(64):$ORIGIN/lib(64) as RUNPATH). This way the prebuilt + // repository can supply the expected versions of the shared libraries + // without interference from what is in the out tree. + + // These shared lib paths may point to copies of the libs in + // .intermediates, which isn't where the binary will load them from, but + // it's fine for dependency tracking. If a library dependency is updated, + // the symlink will get a new timestamp, along with any installed symlinks + // handled in make. + sharedLibPaths := deps.EarlySharedLibs + sharedLibPaths = append(sharedLibPaths, deps.SharedLibs...) + sharedLibPaths = append(sharedLibPaths, deps.LateSharedLibs...) + + var fromPath = in.String() + if !filepath.IsAbs(fromPath) { + fromPath = "$$PWD/" + fromPath + } - // Copy binaries to a name matching the final installed name - outputFile := android.PathForModuleOut(ctx, fileName) - ctx.Build(pctx, android.BuildParams{ - Rule: android.CpExecutable, - Description: "prebuilt", - Output: outputFile, - Input: in, - }) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Symlink, + Output: outputFile, + Input: in, + Implicits: sharedLibPaths, + Args: map[string]string{ + "fromPath": fromPath, + }, + }) + + p.toolPath = android.OptionalPathForPath(outputFile) + } else { + if p.stripper.NeedsStrip(ctx) { + stripped := android.PathForModuleOut(ctx, "stripped", fileName) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, flagsToStripFlags(flags)) + in = stripped + } + + // Copy binaries to a name matching the final installed name + ctx.Build(pctx, android.BuildParams{ + Rule: android.CpExecutable, + Description: "prebuilt", + Output: outputFile, + Input: in, + }) + } return outputFile } @@ -378,6 +418,7 @@ func NewPrebuiltBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecor binaryDecorator: binary, } module.linker = prebuilt + module.installer = prebuilt module.AddProperties(&prebuilt.properties) diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go index adb44bd71..52416ac3b 100644 --- a/cc/prebuilt_test.go +++ b/cc/prebuilt_test.go @@ -15,6 +15,7 @@ package cc import ( + "path/filepath" "testing" "android/soong/android" @@ -271,3 +272,52 @@ func TestPrebuiltLibrarySharedStem(t *testing.T) { shared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*Module) assertString(t, shared.OutputFile().Path().Base(), "libbar.so") } + +func TestPrebuiltSymlinkedHostBinary(t *testing.T) { + if android.BuildOs != android.Linux { + t.Skipf("Skipping host prebuilt testing that is only supported on %s not %s", android.Linux, android.BuildOs) + } + + ctx := testPrebuilt(t, ` + cc_prebuilt_library_shared { + name: "libfoo", + device_supported: false, + host_supported: true, + target: { + linux_glibc_x86_64: { + srcs: ["linux_glibc_x86_64/lib64/libfoo.so"], + }, + }, + } + + cc_prebuilt_binary { + name: "foo", + device_supported: false, + host_supported: true, + shared_libs: ["libfoo"], + target: { + linux_glibc_x86_64: { + srcs: ["linux_glibc_x86_64/bin/foo"], + }, + }, + } + `, map[string][]byte{ + "libfoo.so": nil, + "foo": nil, + }) + + fooRule := ctx.ModuleForTests("foo", "linux_glibc_x86_64").Rule("Symlink") + assertString(t, fooRule.Output.String(), + filepath.Join(buildDir, ".intermediates/foo/linux_glibc_x86_64/foo")) + assertString(t, fooRule.Args["fromPath"], "$$PWD/linux_glibc_x86_64/bin/foo") + + var libfooDep android.Path + for _, dep := range fooRule.Implicits { + if dep.Base() == "libfoo.so" { + libfooDep = dep + break + } + } + assertString(t, libfooDep.String(), + filepath.Join(buildDir, ".intermediates/libfoo/linux_glibc_x86_64_shared/libfoo.so")) +} diff --git a/cc/sanitize.go b/cc/sanitize.go index 2243082ad..174dcfea5 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -48,6 +48,10 @@ var ( // higher number of "optimized out" stack variables. // b/112437883. "-mllvm", "-instcombine-lower-dbg-declare=0", + // TODO(b/159343917): HWASan and GlobalISel don't play nicely, and + // GlobalISel is the default at -O0 on aarch64. + "-mllvm", "--aarch64-enable-global-isel-at-O=-1", + "-mllvm", "-fast-isel=false", } cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso", @@ -738,7 +742,7 @@ func isSanitizableDependencyTag(tag blueprint.DependencyTag) bool { // as vendor snapshot. Such modules must create both cfi and non-cfi variants, // except for ones which explicitly disable cfi. func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool { - if isVendorProprietaryPath(mctx.ModuleDir()) { + if isVendorProprietaryModule(mctx) { return false } @@ -1011,10 +1015,12 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { // static executable gets static runtime libs depTag := libraryDependencyTag{Kind: staticLibraryDependency} - mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{ - {Mutator: "link", Variation: "static"}, - c.ImageVariation(), - }...), depTag, deps...) + variations := append(mctx.Target().Variations(), + blueprint.Variation{Mutator: "link", Variation: "static"}) + if c.Device() { + variations = append(variations, c.ImageVariation()) + } + mctx.AddFarVariationDependencies(variations, depTag, deps...) } else if !c.static() && !c.header() { // If we're using snapshots and in vendor, redirect to snapshot whenever possible if c.VndkVersion() == mctx.DeviceConfig().VndkVersion() { @@ -1026,10 +1032,12 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { // dynamic executable and shared libs get shared runtime libs depTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: earlyLibraryDependency} - mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{ - {Mutator: "link", Variation: "shared"}, - c.ImageVariation(), - }...), depTag, runtimeLibrary) + variations := append(mctx.Target().Variations(), + blueprint.Variation{Mutator: "link", Variation: "shared"}) + if c.Device() { + variations = append(variations, c.ImageVariation()) + } + mctx.AddFarVariationDependencies(variations, depTag, runtimeLibrary) } // 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/snapshot_utils.go b/cc/snapshot_utils.go index 4012def52..f27d166f4 100644 --- a/cc/snapshot_utils.go +++ b/cc/snapshot_utils.go @@ -61,7 +61,7 @@ func (s *snapshotMap) get(name string, arch android.ArchType) (snapshot string, func isSnapshotAware(ctx android.ModuleContext, m *Module) bool { if _, _, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m); ok { return ctx.Config().VndkSnapshotBuildArtifacts() - } else if isVendorSnapshotModule(m, ctx.ModuleDir()) { + } else if isVendorSnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir())) { return true } return false @@ -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 { @@ -239,11 +223,6 @@ func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags { flags.Local.CppFlags = append(flags.Local.CppFlags, "-nostdinc++") flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++") if ctx.Windows() { - // Use SjLj exceptions for 32-bit. libgcc_eh implements SjLj - // exception model for 32-bit. - if ctx.Arch().ArchType == android.X86 { - flags.Local.CppFlags = append(flags.Local.CppFlags, "-fsjlj-exceptions") - } flags.Local.CppFlags = append(flags.Local.CppFlags, // Disable visiblity annotations since we're using static // libc++. diff --git a/cc/strip.go b/cc/strip.go index 7e560ec9c..18150dc8d 100644 --- a/cc/strip.go +++ b/cc/strip.go @@ -30,42 +30,42 @@ type StripProperties struct { } `android:"arch_variant"` } -type stripper struct { +type Stripper struct { StripProperties StripProperties } -func (stripper *stripper) needsStrip(ctx ModuleContext) bool { +func (stripper *Stripper) NeedsStrip(actx android.ModuleContext) bool { // TODO(ccross): enable host stripping when embedded in make? Make never had support for stripping host binaries. - return (!ctx.Config().EmbeddedInMake() || ctx.Device()) && !Bool(stripper.StripProperties.Strip.None) + return (!actx.Config().EmbeddedInMake() || actx.Device()) && !Bool(stripper.StripProperties.Strip.None) } -func (stripper *stripper) strip(ctx ModuleContext, in android.Path, out android.ModuleOutPath, - flags builderFlags, isStaticLib bool) { - if ctx.Darwin() { - TransformDarwinStrip(ctx, in, out) +func (stripper *Stripper) strip(actx android.ModuleContext, in android.Path, out android.ModuleOutPath, + flags StripFlags, isStaticLib bool) { + if actx.Darwin() { + TransformDarwinStrip(actx, in, out) } else { if Bool(stripper.StripProperties.Strip.Keep_symbols) { - flags.stripKeepSymbols = true + flags.StripKeepSymbols = true } else if Bool(stripper.StripProperties.Strip.Keep_symbols_and_debug_frame) { - flags.stripKeepSymbolsAndDebugFrame = true + flags.StripKeepSymbolsAndDebugFrame = true } else if len(stripper.StripProperties.Strip.Keep_symbols_list) > 0 { - flags.stripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",") + flags.StripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",") } else if !Bool(stripper.StripProperties.Strip.All) { - flags.stripKeepMiniDebugInfo = true + flags.StripKeepMiniDebugInfo = true } - if ctx.Config().Debuggable() && !flags.stripKeepMiniDebugInfo && !isStaticLib { - flags.stripAddGnuDebuglink = true + if actx.Config().Debuggable() && !flags.StripKeepMiniDebugInfo && !isStaticLib { + flags.StripAddGnuDebuglink = true } - TransformStrip(ctx, in, out, flags) + TransformStrip(actx, in, out, flags) } } -func (stripper *stripper) stripExecutableOrSharedLib(ctx ModuleContext, in android.Path, - out android.ModuleOutPath, flags builderFlags) { - stripper.strip(ctx, in, out, flags, false) +func (stripper *Stripper) StripExecutableOrSharedLib(actx android.ModuleContext, in android.Path, + out android.ModuleOutPath, flags StripFlags) { + stripper.strip(actx, in, out, flags, false) } -func (stripper *stripper) stripStaticLib(ctx ModuleContext, in android.Path, out android.ModuleOutPath, - flags builderFlags) { - stripper.strip(ctx, in, out, flags, true) +func (stripper *Stripper) StripStaticLib(actx android.ModuleContext, in android.Path, out android.ModuleOutPath, + flags StripFlags) { + stripper.strip(actx, in, out, flags, true) } diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py index faa3823f3..5678e7d83 100644 --- a/cc/symbolfile/__init__.py +++ b/cc/symbolfile/__init__.py @@ -14,15 +14,31 @@ # limitations under the License. # """Parser for Android's version script information.""" +from dataclasses import dataclass import logging import re +from typing import ( + Dict, + Iterable, + List, + Mapping, + NewType, + Optional, + TextIO, + Tuple, +) + + +ApiMap = Mapping[str, int] +Arch = NewType('Arch', str) +Tag = NewType('Tag', str) ALL_ARCHITECTURES = ( - 'arm', - 'arm64', - 'x86', - 'x86_64', + Arch('arm'), + Arch('arm64'), + Arch('x86'), + Arch('x86_64'), ) @@ -30,18 +46,36 @@ ALL_ARCHITECTURES = ( FUTURE_API_LEVEL = 10000 -def logger(): +def logger() -> logging.Logger: """Return the main logger for this module.""" return logging.getLogger(__name__) -def get_tags(line): +@dataclass +class Symbol: + """A symbol definition from a symbol file.""" + + name: str + tags: List[Tag] + + +@dataclass +class Version: + """A version block of a symbol file.""" + + name: str + base: Optional[str] + tags: List[Tag] + symbols: List[Symbol] + + +def get_tags(line: str) -> List[Tag]: """Returns a list of all tags on this line.""" _, _, all_tags = line.strip().partition('#') - return [e for e in re.split(r'\s+', all_tags) if e.strip()] + return [Tag(e) for e in re.split(r'\s+', all_tags) if e.strip()] -def is_api_level_tag(tag): +def is_api_level_tag(tag: Tag) -> bool: """Returns true if this tag has an API level that may need decoding.""" if tag.startswith('introduced='): return True @@ -52,7 +86,7 @@ def is_api_level_tag(tag): return False -def decode_api_level(api, api_map): +def decode_api_level(api: str, api_map: ApiMap) -> int: """Decodes the API level argument into the API level number. For the average case, this just decodes the integer value from the string, @@ -70,12 +104,13 @@ def decode_api_level(api, api_map): return api_map[api] -def decode_api_level_tags(tags, api_map): +def decode_api_level_tags(tags: Iterable[Tag], api_map: ApiMap) -> List[Tag]: """Decodes API level code names in a list of tags. Raises: ParseError: An unknown version name was found in a tag. """ + decoded_tags = list(tags) for idx, tag in enumerate(tags): if not is_api_level_tag(tag): continue @@ -83,13 +118,13 @@ def decode_api_level_tags(tags, api_map): try: decoded = str(decode_api_level(value, api_map)) - tags[idx] = '='.join([name, decoded]) + decoded_tags[idx] = Tag('='.join([name, decoded])) except KeyError: - raise ParseError('Unknown version name in tag: {}'.format(tag)) - return tags + raise ParseError(f'Unknown version name in tag: {tag}') + return decoded_tags -def split_tag(tag): +def split_tag(tag: Tag) -> Tuple[str, str]: """Returns a key/value tuple of the tag. Raises: @@ -103,7 +138,7 @@ def split_tag(tag): return key, value -def get_tag_value(tag): +def get_tag_value(tag: Tag) -> str: """Returns the value of a key/value tag. Raises: @@ -114,12 +149,13 @@ def get_tag_value(tag): return split_tag(tag)[1] -def version_is_private(version): +def version_is_private(version: str) -> bool: """Returns True if the version name should be treated as private.""" return version.endswith('_PRIVATE') or version.endswith('_PLATFORM') -def should_omit_version(version, arch, api, llndk, apex): +def should_omit_version(version: Version, arch: Arch, api: int, llndk: bool, + apex: bool) -> bool: """Returns True if the version section should be ommitted. We want to omit any sections that do not have any symbols we'll have in the @@ -145,7 +181,8 @@ def should_omit_version(version, arch, api, llndk, apex): return False -def should_omit_symbol(symbol, arch, api, llndk, apex): +def should_omit_symbol(symbol: Symbol, arch: Arch, api: int, llndk: bool, + apex: bool) -> bool: """Returns True if the symbol should be omitted.""" no_llndk_no_apex = 'llndk' not in symbol.tags and 'apex' not in symbol.tags keep = no_llndk_no_apex or \ @@ -160,7 +197,7 @@ def should_omit_symbol(symbol, arch, api, llndk, apex): return False -def symbol_in_arch(tags, arch): +def symbol_in_arch(tags: Iterable[Tag], arch: Arch) -> bool: """Returns true if the symbol is present for the given architecture.""" has_arch_tags = False for tag in tags: @@ -175,7 +212,7 @@ def symbol_in_arch(tags, arch): return not has_arch_tags -def symbol_in_api(tags, arch, api): +def symbol_in_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool: """Returns true if the symbol is present for the given API level.""" introduced_tag = None arch_specific = False @@ -197,7 +234,7 @@ def symbol_in_api(tags, arch, api): return api >= int(get_tag_value(introduced_tag)) -def symbol_versioned_in_api(tags, api): +def symbol_versioned_in_api(tags: Iterable[Tag], api: int) -> bool: """Returns true if the symbol should be versioned for the given API. This models the `versioned=API` tag. This should be a very uncommonly @@ -223,68 +260,40 @@ class ParseError(RuntimeError): class MultiplyDefinedSymbolError(RuntimeError): """A symbol name was multiply defined.""" - def __init__(self, multiply_defined_symbols): - super(MultiplyDefinedSymbolError, self).__init__( + def __init__(self, multiply_defined_symbols: Iterable[str]) -> None: + super().__init__( 'Version script contains multiple definitions for: {}'.format( ', '.join(multiply_defined_symbols))) self.multiply_defined_symbols = multiply_defined_symbols -class Version: - """A version block of a symbol file.""" - def __init__(self, name, base, tags, symbols): - self.name = name - self.base = base - self.tags = tags - self.symbols = symbols - - def __eq__(self, other): - if self.name != other.name: - return False - if self.base != other.base: - return False - if self.tags != other.tags: - return False - if self.symbols != other.symbols: - return False - return True - - -class Symbol: - """A symbol definition from a symbol file.""" - def __init__(self, name, tags): - self.name = name - self.tags = tags - - def __eq__(self, other): - return self.name == other.name and set(self.tags) == set(other.tags) - - class SymbolFileParser: """Parses NDK symbol files.""" - def __init__(self, input_file, api_map, arch, api, llndk, apex): + def __init__(self, input_file: TextIO, api_map: ApiMap, arch: Arch, + api: int, llndk: bool, apex: bool) -> None: self.input_file = input_file self.api_map = api_map self.arch = arch self.api = api self.llndk = llndk self.apex = apex - self.current_line = None + self.current_line: Optional[str] = None - def parse(self): + def parse(self) -> List[Version]: """Parses the symbol file and returns a list of Version objects.""" versions = [] while self.next_line() != '': + assert self.current_line is not None if '{' in self.current_line: versions.append(self.parse_version()) else: raise ParseError( - 'Unexpected contents at top level: ' + self.current_line) + f'Unexpected contents at top level: {self.current_line}') self.check_no_duplicate_symbols(versions) return versions - def check_no_duplicate_symbols(self, versions): + def check_no_duplicate_symbols(self, versions: Iterable[Version]) -> None: """Raises errors for multiply defined symbols. This situation is the normal case when symbol versioning is actually @@ -312,12 +321,13 @@ class SymbolFileParser: raise MultiplyDefinedSymbolError( sorted(list(multiply_defined_symbols))) - def parse_version(self): + def parse_version(self) -> Version: """Parses a single version section and returns a Version object.""" + assert self.current_line is not None name = self.current_line.split('{')[0].strip() tags = get_tags(self.current_line) tags = decode_api_level_tags(tags, self.api_map) - symbols = [] + symbols: List[Symbol] = [] global_scope = True cpp_symbols = False while self.next_line() != '': @@ -333,9 +343,7 @@ class SymbolFileParser: cpp_symbols = False else: base = base.rstrip(';').rstrip() - if base == '': - base = None - return Version(name, base, tags, symbols) + return Version(name, base or None, tags, symbols) elif 'extern "C++" {' in self.current_line: cpp_symbols = True elif not cpp_symbols and ':' in self.current_line: @@ -354,8 +362,9 @@ class SymbolFileParser: pass raise ParseError('Unexpected EOF in version block.') - def parse_symbol(self): + def parse_symbol(self) -> Symbol: """Parses a single symbol line and returns a Symbol object.""" + assert self.current_line is not None if ';' not in self.current_line: raise ParseError( 'Expected ; to terminate symbol: ' + self.current_line) @@ -368,7 +377,7 @@ class SymbolFileParser: tags = decode_api_level_tags(tags, self.api_map) return Symbol(name, tags) - def next_line(self): + def next_line(self) -> str: """Returns the next non-empty non-comment line. A return value of '' indicates EOF. diff --git a/cc/symbolfile/mypy.ini b/cc/symbolfile/mypy.ini new file mode 100644 index 000000000..82aa7eb9d --- /dev/null +++ b/cc/symbolfile/mypy.ini @@ -0,0 +1,2 @@ +[mypy] +disallow_untyped_defs = True diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py index c91131fee..92b13999e 100644 --- a/cc/symbolfile/test_symbolfile.py +++ b/cc/symbolfile/test_symbolfile.py @@ -19,12 +19,13 @@ import textwrap import unittest import symbolfile +from symbolfile import Arch, Tag # pylint: disable=missing-docstring class DecodeApiLevelTest(unittest.TestCase): - def test_decode_api_level(self): + def test_decode_api_level(self) -> None: self.assertEqual(9, symbolfile.decode_api_level('9', {})) self.assertEqual(9000, symbolfile.decode_api_level('O', {'O': 9000})) @@ -33,70 +34,73 @@ class DecodeApiLevelTest(unittest.TestCase): class TagsTest(unittest.TestCase): - def test_get_tags_no_tags(self): + def test_get_tags_no_tags(self) -> None: self.assertEqual([], symbolfile.get_tags('')) self.assertEqual([], symbolfile.get_tags('foo bar baz')) - def test_get_tags(self): + def test_get_tags(self) -> None: self.assertEqual(['foo', 'bar'], symbolfile.get_tags('# foo bar')) self.assertEqual(['bar', 'baz'], symbolfile.get_tags('foo # bar baz')) - def test_split_tag(self): - self.assertTupleEqual(('foo', 'bar'), symbolfile.split_tag('foo=bar')) - self.assertTupleEqual(('foo', 'bar=baz'), symbolfile.split_tag('foo=bar=baz')) + def test_split_tag(self) -> None: + self.assertTupleEqual(('foo', 'bar'), + symbolfile.split_tag(Tag('foo=bar'))) + self.assertTupleEqual(('foo', 'bar=baz'), + symbolfile.split_tag(Tag('foo=bar=baz'))) with self.assertRaises(ValueError): - symbolfile.split_tag('foo') + symbolfile.split_tag(Tag('foo')) - def test_get_tag_value(self): - self.assertEqual('bar', symbolfile.get_tag_value('foo=bar')) - self.assertEqual('bar=baz', symbolfile.get_tag_value('foo=bar=baz')) + def test_get_tag_value(self) -> None: + self.assertEqual('bar', symbolfile.get_tag_value(Tag('foo=bar'))) + self.assertEqual('bar=baz', + symbolfile.get_tag_value(Tag('foo=bar=baz'))) with self.assertRaises(ValueError): - symbolfile.get_tag_value('foo') + symbolfile.get_tag_value(Tag('foo')) - def test_is_api_level_tag(self): - self.assertTrue(symbolfile.is_api_level_tag('introduced=24')) - self.assertTrue(symbolfile.is_api_level_tag('introduced-arm=24')) - self.assertTrue(symbolfile.is_api_level_tag('versioned=24')) + def test_is_api_level_tag(self) -> None: + self.assertTrue(symbolfile.is_api_level_tag(Tag('introduced=24'))) + self.assertTrue(symbolfile.is_api_level_tag(Tag('introduced-arm=24'))) + self.assertTrue(symbolfile.is_api_level_tag(Tag('versioned=24'))) # Shouldn't try to process things that aren't a key/value tag. - self.assertFalse(symbolfile.is_api_level_tag('arm')) - self.assertFalse(symbolfile.is_api_level_tag('introduced')) - self.assertFalse(symbolfile.is_api_level_tag('versioned')) + self.assertFalse(symbolfile.is_api_level_tag(Tag('arm'))) + self.assertFalse(symbolfile.is_api_level_tag(Tag('introduced'))) + self.assertFalse(symbolfile.is_api_level_tag(Tag('versioned'))) # We don't support arch specific `versioned` tags. - self.assertFalse(symbolfile.is_api_level_tag('versioned-arm=24')) + self.assertFalse(symbolfile.is_api_level_tag(Tag('versioned-arm=24'))) - def test_decode_api_level_tags(self): + def test_decode_api_level_tags(self) -> None: api_map = { 'O': 9000, 'P': 9001, } tags = [ - 'introduced=9', - 'introduced-arm=14', - 'versioned=16', - 'arm', - 'introduced=O', - 'introduced=P', + Tag('introduced=9'), + Tag('introduced-arm=14'), + Tag('versioned=16'), + Tag('arm'), + Tag('introduced=O'), + Tag('introduced=P'), ] expected_tags = [ - 'introduced=9', - 'introduced-arm=14', - 'versioned=16', - 'arm', - 'introduced=9000', - 'introduced=9001', + Tag('introduced=9'), + Tag('introduced-arm=14'), + Tag('versioned=16'), + Tag('arm'), + Tag('introduced=9000'), + Tag('introduced=9001'), ] self.assertListEqual( expected_tags, symbolfile.decode_api_level_tags(tags, api_map)) with self.assertRaises(symbolfile.ParseError): - symbolfile.decode_api_level_tags(['introduced=O'], {}) + symbolfile.decode_api_level_tags([Tag('introduced=O')], {}) class PrivateVersionTest(unittest.TestCase): - def test_version_is_private(self): + def test_version_is_private(self) -> None: self.assertFalse(symbolfile.version_is_private('foo')) self.assertFalse(symbolfile.version_is_private('PRIVATE')) self.assertFalse(symbolfile.version_is_private('PLATFORM')) @@ -110,191 +114,227 @@ class PrivateVersionTest(unittest.TestCase): class SymbolPresenceTest(unittest.TestCase): - def test_symbol_in_arch(self): - self.assertTrue(symbolfile.symbol_in_arch([], 'arm')) - self.assertTrue(symbolfile.symbol_in_arch(['arm'], 'arm')) - - self.assertFalse(symbolfile.symbol_in_arch(['x86'], 'arm')) - - def test_symbol_in_api(self): - self.assertTrue(symbolfile.symbol_in_api([], 'arm', 9)) - self.assertTrue(symbolfile.symbol_in_api(['introduced=9'], 'arm', 9)) - self.assertTrue(symbolfile.symbol_in_api(['introduced=9'], 'arm', 14)) - self.assertTrue(symbolfile.symbol_in_api(['introduced-arm=9'], 'arm', 14)) - self.assertTrue(symbolfile.symbol_in_api(['introduced-arm=9'], 'arm', 14)) - self.assertTrue(symbolfile.symbol_in_api(['introduced-x86=14'], 'arm', 9)) - self.assertTrue(symbolfile.symbol_in_api( - ['introduced-arm=9', 'introduced-x86=21'], 'arm', 14)) - self.assertTrue(symbolfile.symbol_in_api( - ['introduced=9', 'introduced-x86=21'], 'arm', 14)) - self.assertTrue(symbolfile.symbol_in_api( - ['introduced=21', 'introduced-arm=9'], 'arm', 14)) - self.assertTrue(symbolfile.symbol_in_api( - ['future'], 'arm', symbolfile.FUTURE_API_LEVEL)) - - self.assertFalse(symbolfile.symbol_in_api(['introduced=14'], 'arm', 9)) - self.assertFalse(symbolfile.symbol_in_api(['introduced-arm=14'], 'arm', 9)) - self.assertFalse(symbolfile.symbol_in_api(['future'], 'arm', 9)) - self.assertFalse(symbolfile.symbol_in_api( - ['introduced=9', 'future'], 'arm', 14)) - self.assertFalse(symbolfile.symbol_in_api( - ['introduced-arm=9', 'future'], 'arm', 14)) - self.assertFalse(symbolfile.symbol_in_api( - ['introduced-arm=21', 'introduced-x86=9'], 'arm', 14)) - self.assertFalse(symbolfile.symbol_in_api( - ['introduced=9', 'introduced-arm=21'], 'arm', 14)) - self.assertFalse(symbolfile.symbol_in_api( - ['introduced=21', 'introduced-x86=9'], 'arm', 14)) + def test_symbol_in_arch(self) -> None: + self.assertTrue(symbolfile.symbol_in_arch([], Arch('arm'))) + self.assertTrue(symbolfile.symbol_in_arch([Tag('arm')], Arch('arm'))) + + self.assertFalse(symbolfile.symbol_in_arch([Tag('x86')], Arch('arm'))) + + def test_symbol_in_api(self) -> None: + self.assertTrue(symbolfile.symbol_in_api([], Arch('arm'), 9)) + self.assertTrue( + symbolfile.symbol_in_api([Tag('introduced=9')], Arch('arm'), 9)) + self.assertTrue( + symbolfile.symbol_in_api([Tag('introduced=9')], Arch('arm'), 14)) + self.assertTrue( + symbolfile.symbol_in_api([Tag('introduced-arm=9')], Arch('arm'), + 14)) + self.assertTrue( + symbolfile.symbol_in_api([Tag('introduced-arm=9')], Arch('arm'), + 14)) + self.assertTrue( + symbolfile.symbol_in_api([Tag('introduced-x86=14')], Arch('arm'), + 9)) + self.assertTrue( + symbolfile.symbol_in_api( + [Tag('introduced-arm=9'), + Tag('introduced-x86=21')], Arch('arm'), 14)) + self.assertTrue( + symbolfile.symbol_in_api( + [Tag('introduced=9'), + Tag('introduced-x86=21')], Arch('arm'), 14)) + self.assertTrue( + symbolfile.symbol_in_api( + [Tag('introduced=21'), + Tag('introduced-arm=9')], Arch('arm'), 14)) + self.assertTrue( + symbolfile.symbol_in_api([Tag('future')], Arch('arm'), + symbolfile.FUTURE_API_LEVEL)) + + self.assertFalse( + symbolfile.symbol_in_api([Tag('introduced=14')], Arch('arm'), 9)) + self.assertFalse( + symbolfile.symbol_in_api([Tag('introduced-arm=14')], Arch('arm'), + 9)) + self.assertFalse( + symbolfile.symbol_in_api([Tag('future')], Arch('arm'), 9)) + self.assertFalse( + symbolfile.symbol_in_api( + [Tag('introduced=9'), Tag('future')], Arch('arm'), 14)) + self.assertFalse( + symbolfile.symbol_in_api([Tag('introduced-arm=9'), + Tag('future')], Arch('arm'), 14)) + self.assertFalse( + symbolfile.symbol_in_api( + [Tag('introduced-arm=21'), + Tag('introduced-x86=9')], Arch('arm'), 14)) + self.assertFalse( + symbolfile.symbol_in_api( + [Tag('introduced=9'), + Tag('introduced-arm=21')], Arch('arm'), 14)) + self.assertFalse( + symbolfile.symbol_in_api( + [Tag('introduced=21'), + Tag('introduced-x86=9')], Arch('arm'), 14)) # Interesting edge case: this symbol should be omitted from the # library, but this call should still return true because none of the # tags indiciate that it's not present in this API level. - self.assertTrue(symbolfile.symbol_in_api(['x86'], 'arm', 9)) + self.assertTrue(symbolfile.symbol_in_api([Tag('x86')], Arch('arm'), 9)) - def test_verioned_in_api(self): + def test_verioned_in_api(self) -> None: self.assertTrue(symbolfile.symbol_versioned_in_api([], 9)) - self.assertTrue(symbolfile.symbol_versioned_in_api(['versioned=9'], 9)) - self.assertTrue(symbolfile.symbol_versioned_in_api(['versioned=9'], 14)) + self.assertTrue( + symbolfile.symbol_versioned_in_api([Tag('versioned=9')], 9)) + self.assertTrue( + symbolfile.symbol_versioned_in_api([Tag('versioned=9')], 14)) - self.assertFalse(symbolfile.symbol_versioned_in_api(['versioned=14'], 9)) + self.assertFalse( + symbolfile.symbol_versioned_in_api([Tag('versioned=14')], 9)) class OmitVersionTest(unittest.TestCase): - def test_omit_private(self): + def test_omit_private(self) -> None: self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, [], []), 'arm', 9, False, + symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False, False)) self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo_PRIVATE', None, [], []), 'arm', 9, - False, False)) + symbolfile.Version('foo_PRIVATE', None, [], []), Arch('arm'), + 9, False, False)) self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo_PLATFORM', None, [], []), 'arm', 9, - False, False)) + symbolfile.Version('foo_PLATFORM', None, [], []), Arch('arm'), + 9, False, False)) self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['platform-only'], []), 'arm', - 9, False, False)) + symbolfile.Version('foo', None, [Tag('platform-only')], []), + Arch('arm'), 9, False, False)) - def test_omit_llndk(self): + def test_omit_llndk(self) -> None: self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['llndk'], []), 'arm', 9, - False, False)) + symbolfile.Version('foo', None, [Tag('llndk')], []), + Arch('arm'), 9, False, False)) self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, [], []), 'arm', 9, True, + symbolfile.Version('foo', None, [], []), Arch('arm'), 9, True, False)) self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['llndk'], []), 'arm', 9, True, - False)) + symbolfile.Version('foo', None, [Tag('llndk')], []), + Arch('arm'), 9, True, False)) - def test_omit_apex(self): + def test_omit_apex(self) -> None: self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['apex'], []), 'arm', 9, False, - False)) + symbolfile.Version('foo', None, [Tag('apex')], []), + Arch('arm'), 9, False, False)) self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, [], []), 'arm', 9, False, + symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False, True)) self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['apex'], []), 'arm', 9, False, - True)) + symbolfile.Version('foo', None, [Tag('apex')], []), + Arch('arm'), 9, False, True)) - def test_omit_arch(self): + def test_omit_arch(self) -> None: self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, [], []), 'arm', 9, False, + symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False, False)) self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['arm'], []), 'arm', 9, False, - False)) + symbolfile.Version('foo', None, [Tag('arm')], []), Arch('arm'), + 9, False, False)) self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['x86'], []), 'arm', 9, False, - False)) + symbolfile.Version('foo', None, [Tag('x86')], []), Arch('arm'), + 9, False, False)) - def test_omit_api(self): + def test_omit_api(self) -> None: self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, [], []), 'arm', 9, False, + symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False, False)) self.assertFalse( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['introduced=9'], []), 'arm', - 9, False, False)) + symbolfile.Version('foo', None, [Tag('introduced=9')], []), + Arch('arm'), 9, False, False)) self.assertTrue( symbolfile.should_omit_version( - symbolfile.Version('foo', None, ['introduced=14'], []), 'arm', - 9, False, False)) + symbolfile.Version('foo', None, [Tag('introduced=14')], []), + Arch('arm'), 9, False, False)) class OmitSymbolTest(unittest.TestCase): - def test_omit_llndk(self): + def test_omit_llndk(self) -> None: self.assertTrue( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['llndk']), - 'arm', 9, False, False)) + symbolfile.should_omit_symbol( + symbolfile.Symbol('foo', [Tag('llndk')]), Arch('arm'), 9, + False, False)) self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm', - 9, True, False)) + symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), + Arch('arm'), 9, True, False)) self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['llndk']), - 'arm', 9, True, False)) + symbolfile.should_omit_symbol( + symbolfile.Symbol('foo', [Tag('llndk')]), Arch('arm'), 9, True, + False)) - def test_omit_apex(self): + def test_omit_apex(self) -> None: self.assertTrue( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['apex']), - 'arm', 9, False, False)) + symbolfile.should_omit_symbol( + symbolfile.Symbol('foo', [Tag('apex')]), Arch('arm'), 9, False, + False)) self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm', - 9, False, True)) + symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), + Arch('arm'), 9, False, True)) self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['apex']), - 'arm', 9, False, True)) + symbolfile.should_omit_symbol( + symbolfile.Symbol('foo', [Tag('apex')]), Arch('arm'), 9, False, + True)) - def test_omit_arch(self): + def test_omit_arch(self) -> None: self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm', - 9, False, False)) + symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), + Arch('arm'), 9, False, False)) self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['arm']), - 'arm', 9, False, False)) + symbolfile.should_omit_symbol( + symbolfile.Symbol('foo', [Tag('arm')]), Arch('arm'), 9, False, + False)) self.assertTrue( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['x86']), - 'arm', 9, False, False)) + symbolfile.should_omit_symbol( + symbolfile.Symbol('foo', [Tag('x86')]), Arch('arm'), 9, False, + False)) - def test_omit_api(self): + def test_omit_api(self) -> None: self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm', - 9, False, False)) + symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), + Arch('arm'), 9, False, False)) self.assertFalse( symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', ['introduced=9']), 'arm', 9, False, - False)) + symbolfile.Symbol('foo', [Tag('introduced=9')]), Arch('arm'), + 9, False, False)) self.assertTrue( symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', ['introduced=14']), 'arm', 9, False, - False)) + symbolfile.Symbol('foo', [Tag('introduced=14')]), Arch('arm'), + 9, False, False)) class SymbolFileParseTest(unittest.TestCase): - def test_next_line(self): + def test_next_line(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ foo @@ -302,10 +342,12 @@ class SymbolFileParseTest(unittest.TestCase): # baz qux """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) self.assertIsNone(parser.current_line) self.assertEqual('foo', parser.next_line().strip()) + assert parser.current_line is not None self.assertEqual('foo', parser.current_line.strip()) self.assertEqual('bar', parser.next_line().strip()) @@ -317,7 +359,7 @@ class SymbolFileParseTest(unittest.TestCase): self.assertEqual('', parser.next_line()) self.assertEqual('', parser.current_line) - def test_parse_version(self): + def test_parse_version(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { # foo bar baz; @@ -327,7 +369,8 @@ class SymbolFileParseTest(unittest.TestCase): VERSION_2 { } VERSION_1; # asdf """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() version = parser.parse_version() @@ -337,7 +380,7 @@ class SymbolFileParseTest(unittest.TestCase): expected_symbols = [ symbolfile.Symbol('baz', []), - symbolfile.Symbol('qux', ['woodly', 'doodly']), + symbolfile.Symbol('qux', [Tag('woodly'), Tag('doodly')]), ] self.assertEqual(expected_symbols, version.symbols) @@ -347,32 +390,35 @@ class SymbolFileParseTest(unittest.TestCase): self.assertEqual('VERSION_1', version.base) self.assertEqual([], version.tags) - def test_parse_version_eof(self): + def test_parse_version_eof(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() - def test_unknown_scope_label(self): + def test_unknown_scope_label(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { foo: } """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() - def test_parse_symbol(self): + def test_parse_symbol(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ foo; bar; # baz qux """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() symbol = parser.parse_symbol() @@ -384,48 +430,51 @@ class SymbolFileParseTest(unittest.TestCase): self.assertEqual('bar', symbol.name) self.assertEqual(['baz', 'qux'], symbol.tags) - def test_wildcard_symbol_global(self): + def test_wildcard_symbol_global(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() - def test_wildcard_symbol_local(self): + def test_wildcard_symbol_local(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { local: *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() version = parser.parse_version() self.assertEqual([], version.symbols) - def test_missing_semicolon(self): + def test_missing_semicolon(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { foo }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() - def test_parse_fails_invalid_input(self): + def test_parse_fails_invalid_input(self) -> None: with self.assertRaises(symbolfile.ParseError): input_file = io.StringIO('foo') - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), + 16, False, False) parser.parse() - def test_parse(self): + def test_parse(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { local: @@ -443,23 +492,24 @@ class SymbolFileParseTest(unittest.TestCase): qwerty; } VERSION_1; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, False) versions = parser.parse() expected = [ symbolfile.Version('VERSION_1', None, [], [ symbolfile.Symbol('foo', []), - symbolfile.Symbol('bar', ['baz']), + symbolfile.Symbol('bar', [Tag('baz')]), ]), - symbolfile.Version('VERSION_2', 'VERSION_1', ['wasd'], [ + symbolfile.Version('VERSION_2', 'VERSION_1', [Tag('wasd')], [ symbolfile.Symbol('woodly', []), - symbolfile.Symbol('doodly', ['asdf']), + symbolfile.Symbol('doodly', [Tag('asdf')]), ]), ] self.assertEqual(expected, versions) - def test_parse_llndk_apex_symbol(self): + def test_parse_llndk_apex_symbol(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { foo; @@ -468,7 +518,8 @@ class SymbolFileParseTest(unittest.TestCase): qux; # apex }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, True) + parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, + False, True) parser.next_line() version = parser.parse_version() @@ -477,14 +528,14 @@ class SymbolFileParseTest(unittest.TestCase): expected_symbols = [ symbolfile.Symbol('foo', []), - symbolfile.Symbol('bar', ['llndk']), - symbolfile.Symbol('baz', ['llndk', 'apex']), - symbolfile.Symbol('qux', ['apex']), + symbolfile.Symbol('bar', [Tag('llndk')]), + symbolfile.Symbol('baz', [Tag('llndk'), Tag('apex')]), + symbolfile.Symbol('qux', [Tag('apex')]), ] self.assertEqual(expected_symbols, version.symbols) -def main(): +def main() -> None: suite = unittest.TestLoader().loadTestsFromName(__name__) unittest.TextTestRunner(verbosity=3).run(suite) diff --git a/cc/test.go b/cc/test.go index a8056479f..619dc4d00 100644 --- a/cc/test.go +++ b/cc/test.go @@ -223,6 +223,7 @@ func TestPerSrcMutator(mctx android.BottomUpMutatorContext) { tests[i].(*Module).linker.(testPerSrc).setSrc(testNames[i], src) mctx.AddInterVariantDependency(testPerSrcDepTag, all_tests, tests[i]) } + mctx.AliasVariation("") } } } @@ -344,6 +345,12 @@ func (test *testBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { } func (test *testBinary) install(ctx ModuleContext, file android.Path) { + // TODO: (b/167308193) Switch to /data/local/tests/unrestricted as the default install base. + testInstallBase := "/data/local/tmp" + if ctx.inVendor() || ctx.useVndk() { + testInstallBase = "/data/local/tests/vendor" + } + dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data) for _, dataSrcPath := range dataSrcPaths { @@ -411,7 +418,7 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { } test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config, - test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config) + test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config, testInstallBase) test.extraTestConfigs = android.PathsForModuleSrc(ctx, test.Properties.Test_options.Extra_test_configs) diff --git a/cc/testing.go b/cc/testing.go index 06e5f832c..52f082990 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -527,7 +527,9 @@ func CreateTestContext() *android.TestContext { ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory) ctx.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory) + ctx.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory) ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory) + ctx.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) android.RegisterPrebuiltMutators(ctx) RegisterRequiredBuildComponentsForTest(ctx) diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go index 042e012d9..19f5ea4f7 100644 --- a/cc/toolchain_library.go +++ b/cc/toolchain_library.go @@ -36,8 +36,7 @@ type toolchainLibraryProperties struct { type toolchainLibraryDecorator struct { *libraryDecorator - - stripper + stripper Stripper Properties toolchainLibraryProperties } @@ -89,8 +88,8 @@ func (library *toolchainLibraryDecorator) link(ctx ModuleContext, if library.stripper.StripProperties.Strip.Keep_symbols_list != nil { fileName := ctx.ModuleName() + staticLibraryExtension outputFile := android.PathForModuleOut(ctx, fileName) - buildFlags := flagsToBuilderFlags(flags) - library.stripper.stripStaticLib(ctx, srcPath, outputFile, buildFlags) + stripFlags := flagsToStripFlags(flags) + library.stripper.StripStaticLib(ctx, srcPath, outputFile, stripFlags) return outputFile } diff --git a/cc/util.go b/cc/util.go index af26268e2..40374bff7 100644 --- a/cc/util.go +++ b/cc/util.go @@ -97,9 +97,14 @@ func flagsToBuilderFlags(in Flags) builderFlags { protoOptionsFile: in.protoOptionsFile, yacc: in.Yacc, + lex: in.Lex, } } +func flagsToStripFlags(in Flags) StripFlags { + return StripFlags{Toolchain: in.Toolchain} +} + func addPrefix(list []string, prefix string) []string { for i := range list { list[i] = prefix + list[i] diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go index e9d1c7378..85f514c83 100644 --- a/cc/vendor_public_library.go +++ b/cc/vendor_public_library.go @@ -144,7 +144,7 @@ func vendorPublicLibraryFactory() android.Module { library.BuildOnlyShared() module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() stub := &vendorPublicLibraryStubDecorator{ libraryDecorator: library, diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index e17a6d0b3..2819f4958 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -264,7 +264,7 @@ func vendorSnapshotLibrary(suffix string) (*Module, *vendorSnapshotLibraryDecora module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() prebuilt := &vendorSnapshotLibraryDecorator{ libraryDecorator: library, @@ -340,12 +340,12 @@ func (p *vendorSnapshotBinaryDecorator) link(ctx ModuleContext, } in := android.PathForModuleSrc(ctx, *p.properties.Src) - builderFlags := flagsToBuilderFlags(flags) + stripFlags := flagsToStripFlags(flags) p.unstrippedOutputFile = in binName := in.Base() - if p.needsStrip(ctx) { + if p.stripper.NeedsStrip(ctx) { stripped := android.PathForModuleOut(ctx, "stripped", binName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags) in = stripped } @@ -508,18 +508,51 @@ func isVendorProprietaryPath(dir string) bool { return false } +func isVendorProprietaryModule(ctx android.BaseModuleContext) bool { + + // Any module in a vendor proprietary path is a vendor proprietary + // module. + + if isVendorProprietaryPath(ctx.ModuleDir()) { + return true + } + + // However if the module is not in a vendor proprietary path, it may + // still be a vendor proprietary module. This happens for cc modules + // that are excluded from the vendor snapshot, and it means that the + // vendor has assumed control of the framework-provided module. + + if c, ok := ctx.Module().(*Module); ok { + if c.ExcludeFromVendorSnapshot() { + return true + } + } + + return false +} + // Determine if a module is going to be included in vendor snapshot or not. // // Targets of vendor snapshot are "vendor: true" or "vendor_available: true" modules in // AOSP. They are not guaranteed to be compatible with older vendor images. (e.g. might // depend on newer VNDK) So they are captured as vendor snapshot To build older vendor // image and newer system image altogether. -func isVendorSnapshotModule(m *Module, moduleDir string) bool { +func isVendorSnapshotModule(m *Module, inVendorProprietaryPath bool) bool { if !m.Enabled() || m.Properties.HideFromMake { return false } + // When android/prebuilt.go selects between source and prebuilt, it sets + // SkipInstall on the other one to avoid duplicate install rules in make. + if m.IsSkipInstall() { + return false + } // skip proprietary modules, but include all VNDK (static) - if isVendorProprietaryPath(moduleDir) && !m.IsVndk() { + if inVendorProprietaryPath && !m.IsVndk() { + return false + } + // If the module would be included based on its path, check to see if + // the module is marked to be excluded. If so, skip it. + if m.ExcludeFromVendorSnapshot() { return false } if m.Target().Os.Class != android.Device { @@ -791,7 +824,25 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont } moduleDir := ctx.ModuleDir(module) - if !isVendorSnapshotModule(m, moduleDir) { + inVendorProprietaryPath := isVendorProprietaryPath(moduleDir) + + if m.ExcludeFromVendorSnapshot() { + if inVendorProprietaryPath { + // Error: exclude_from_vendor_snapshot applies + // to framework-path modules only. + ctx.Errorf("module %q in vendor proprietary path %q may not use \"exclude_from_vendor_snapshot: true\"", m.String(), moduleDir) + return + } + if Bool(m.VendorProperties.Vendor_available) { + // Error: may not combine "vendor_available: + // true" with "exclude_from_vendor_snapshot: + // true". + ctx.Errorf("module %q may not use both \"vendor_available: true\" and \"exclude_from_vendor_snapshot: true\"", m.String()) + return + } + } + + if !isVendorSnapshotModule(m, inVendorProprietaryPath) { return } diff --git a/cc/vndk.go b/cc/vndk.go index 23bb095bc..9a2fa09d4 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -505,18 +505,25 @@ func (txt *vndkLibrariesTxt) AndroidMkEntries() []android.AndroidMkEntries { }} } +// PrebuiltEtcModule interface func (txt *vndkLibrariesTxt) OutputFile() android.OutputPath { return txt.outputFile } -func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) { - return android.Paths{txt.outputFile}, nil +// PrebuiltEtcModule interface +func (txt *vndkLibrariesTxt) BaseDir() string { + return "etc" } +// PrebuiltEtcModule interface func (txt *vndkLibrariesTxt) SubDir() string { return "" } +func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) { + return android.Paths{txt.outputFile}, nil +} + func VndkSnapshotSingleton() android.Singleton { return &vndkSnapshotSingleton{} } diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go index 5a44c4663..94847601e 100644 --- a/cc/vndk_prebuilt.go +++ b/cc/vndk_prebuilt.go @@ -142,9 +142,10 @@ func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, builderFlags := flagsToBuilderFlags(flags) p.unstrippedOutputFile = in libName := in.Base() - if p.needsStrip(ctx) { + if p.stripper.NeedsStrip(ctx) { + stripFlags := flagsToStripFlags(flags) stripped := android.PathForModuleOut(ctx, "stripped", libName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags) in = stripped } @@ -213,7 +214,7 @@ func vndkPrebuiltSharedLibrary() *Module { library.BuildOnlyShared() module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() prebuilt := &vndkPrebuiltLibraryDecorator{ libraryDecorator: library, |