1// Copyright 2021 Google Inc. All Rights Reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// Package bloaty implements a singleton that measures binary (e.g. ELF 16// executable, shared library or Rust rlib) section sizes at build time. 17package bloaty 18 19import ( 20 "android/soong/android" 21 22 "github.com/google/blueprint" 23) 24 25const bloatyDescriptorExt = ".bloaty.csv" 26const protoFilename = "binary_sizes.pb.gz" 27 28var ( 29 fileSizeMeasurerKey blueprint.ProviderKey 30 pctx = android.NewPackageContext("android/soong/bloaty") 31 32 // bloaty is used to measure a binary section sizes. 33 bloaty = pctx.AndroidStaticRule("bloaty", 34 blueprint.RuleParams{ 35 Command: "${bloaty} -n 0 --csv ${in} > ${out}", 36 CommandDeps: []string{"${bloaty}"}, 37 }) 38 39 // The bloaty merger script is used to combine the outputs from bloaty 40 // into a single protobuf. 41 bloatyMerger = pctx.AndroidStaticRule("bloatyMerger", 42 blueprint.RuleParams{ 43 Command: "${bloatyMerger} ${out}.lst ${out}", 44 CommandDeps: []string{"${bloatyMerger}"}, 45 Rspfile: "${out}.lst", 46 RspfileContent: "${in}", 47 }) 48) 49 50func init() { 51 pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS) 52 pctx.SourcePathVariable("bloaty", "prebuilts/build-tools/${hostPrebuiltTag}/bin/bloaty") 53 pctx.HostBinToolVariable("bloatyMerger", "bloaty_merger") 54 android.RegisterSingletonType("file_metrics", fileSizesSingleton) 55 fileSizeMeasurerKey = blueprint.NewProvider(measuredFiles{}) 56} 57 58// measuredFiles contains the paths of the files measured by a module. 59type measuredFiles struct { 60 paths []android.WritablePath 61} 62 63// MeasureSizeForPaths should be called by binary producers to measure the 64// sizes of artifacts. It must only be called once per module; it will panic 65// otherwise. 66func MeasureSizeForPaths(ctx android.ModuleContext, paths ...android.OptionalPath) { 67 mf := measuredFiles{} 68 for _, p := range paths { 69 if !p.Valid() { 70 continue 71 } 72 if p, ok := p.Path().(android.WritablePath); ok { 73 mf.paths = append(mf.paths, p) 74 } 75 } 76 ctx.SetProvider(fileSizeMeasurerKey, mf) 77} 78 79type sizesSingleton struct{} 80 81func fileSizesSingleton() android.Singleton { 82 return &sizesSingleton{} 83} 84 85func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonContext) { 86 var deps android.Paths 87 ctx.VisitAllModules(func(m android.Module) { 88 if !ctx.ModuleHasProvider(m, fileSizeMeasurerKey) { 89 return 90 } 91 filePaths := ctx.ModuleProvider(m, fileSizeMeasurerKey).(measuredFiles) 92 for _, path := range filePaths.paths { 93 filePath := path.(android.ModuleOutPath) 94 sizeFile := filePath.InSameDir(ctx, filePath.Base()+bloatyDescriptorExt) 95 ctx.Build(pctx, android.BuildParams{ 96 Rule: bloaty, 97 Description: "bloaty " + filePath.Rel(), 98 Input: filePath, 99 Output: sizeFile, 100 }) 101 deps = append(deps, sizeFile) 102 } 103 }) 104 105 ctx.Build(pctx, android.BuildParams{ 106 Rule: bloatyMerger, 107 Inputs: android.SortedUniquePaths(deps), 108 Output: android.PathForOutput(ctx, protoFilename), 109 }) 110} 111 112func (singleton *sizesSingleton) MakeVars(ctx android.MakeVarsContext) { 113 ctx.DistForGoalWithFilename("checkbuild", android.PathForOutput(ctx, protoFilename), protoFilename) 114} 115