1// Copyright 2016 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 15package android 16 17import ( 18 "fmt" 19 "reflect" 20 21 "github.com/google/blueprint" 22 "github.com/google/blueprint/proptools" 23) 24 25// This file implements common functionality for handling modules that may exist as prebuilts, 26// source, or both. 27 28func RegisterPrebuiltMutators(ctx RegistrationContext) { 29 ctx.PreArchMutators(RegisterPrebuiltsPreArchMutators) 30 ctx.PostDepsMutators(RegisterPrebuiltsPostDepsMutators) 31} 32 33// Marks a dependency tag as possibly preventing a reference to a source from being 34// replaced with the prebuilt. 35type ReplaceSourceWithPrebuilt interface { 36 blueprint.DependencyTag 37 38 // Return true if the dependency defined by this tag should be replaced with the 39 // prebuilt. 40 ReplaceSourceWithPrebuilt() bool 41} 42 43type prebuiltDependencyTag struct { 44 blueprint.BaseDependencyTag 45} 46 47var PrebuiltDepTag prebuiltDependencyTag 48 49// Mark this tag so dependencies that use it are excluded from visibility enforcement. 50func (t prebuiltDependencyTag) ExcludeFromVisibilityEnforcement() {} 51 52// Mark this tag so dependencies that use it are excluded from APEX contents. 53func (t prebuiltDependencyTag) ExcludeFromApexContents() {} 54 55var _ ExcludeFromVisibilityEnforcementTag = PrebuiltDepTag 56var _ ExcludeFromApexContentsTag = PrebuiltDepTag 57 58type PrebuiltProperties struct { 59 // When prefer is set to true the prebuilt will be used instead of any source module with 60 // a matching name. 61 Prefer *bool `android:"arch_variant"` 62 63 SourceExists bool `blueprint:"mutated"` 64 UsePrebuilt bool `blueprint:"mutated"` 65 66 // Set if the module has been renamed to remove the "prebuilt_" prefix. 67 PrebuiltRenamedToSource bool `blueprint:"mutated"` 68} 69 70type Prebuilt struct { 71 properties PrebuiltProperties 72 73 srcsSupplier PrebuiltSrcsSupplier 74 srcsPropertyName string 75} 76 77func (p *Prebuilt) Name(name string) string { 78 return "prebuilt_" + name 79} 80 81func (p *Prebuilt) ForcePrefer() { 82 p.properties.Prefer = proptools.BoolPtr(true) 83} 84 85func (p *Prebuilt) Prefer() bool { 86 return proptools.Bool(p.properties.Prefer) 87} 88 89// The below source-related functions and the srcs, src fields are based on an assumption that 90// prebuilt modules have a static source property at the moment. Currently there is only one 91// exception, android_app_import, which chooses a source file depending on the product's DPI 92// preference configs. We'll want to add native support for dynamic source cases if we end up having 93// more modules like this. 94func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path { 95 if p.srcsSupplier != nil { 96 srcs := p.srcsSupplier() 97 98 if len(srcs) == 0 { 99 ctx.PropertyErrorf(p.srcsPropertyName, "missing prebuilt source file") 100 return nil 101 } 102 103 if len(srcs) > 1 { 104 ctx.PropertyErrorf(p.srcsPropertyName, "multiple prebuilt source files") 105 return nil 106 } 107 108 // Return the singleton source after expanding any filegroup in the 109 // sources. 110 src := srcs[0] 111 return PathForModuleSrc(ctx, src) 112 } else { 113 ctx.ModuleErrorf("prebuilt source was not set") 114 return nil 115 } 116} 117 118func (p *Prebuilt) UsePrebuilt() bool { 119 return p.properties.UsePrebuilt 120} 121 122// Called to provide the srcs value for the prebuilt module. 123// 124// Return the src value or nil if it is not available. 125type PrebuiltSrcsSupplier func() []string 126 127// Initialize the module as a prebuilt module that uses the provided supplier to access the 128// prebuilt sources of the module. 129// 130// The supplier will be called multiple times and must return the same values each time it 131// is called. If it returns an empty array (or nil) then the prebuilt module will not be used 132// as a replacement for a source module with the same name even if prefer = true. 133// 134// If the Prebuilt.SingleSourcePath() is called on the module then this must return an array 135// containing exactly one source file. 136// 137// The provided property name is used to provide helpful error messages in the event that 138// a problem arises, e.g. calling SingleSourcePath() when more than one source is provided. 139func InitPrebuiltModuleWithSrcSupplier(module PrebuiltInterface, srcsSupplier PrebuiltSrcsSupplier, srcsPropertyName string) { 140 p := module.Prebuilt() 141 module.AddProperties(&p.properties) 142 143 if srcsSupplier == nil { 144 panic(fmt.Errorf("srcsSupplier must not be nil")) 145 } 146 if srcsPropertyName == "" { 147 panic(fmt.Errorf("srcsPropertyName must not be empty")) 148 } 149 150 p.srcsSupplier = srcsSupplier 151 p.srcsPropertyName = srcsPropertyName 152} 153 154func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) { 155 if srcs == nil { 156 panic(fmt.Errorf("srcs must not be nil")) 157 } 158 159 srcsSupplier := func() []string { 160 return *srcs 161 } 162 163 InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs") 164} 165 166func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) { 167 srcPropsValue := reflect.ValueOf(srcProps).Elem() 168 srcStructField, _ := srcPropsValue.Type().FieldByName(srcField) 169 if !srcPropsValue.IsValid() || srcStructField.Name == "" { 170 panic(fmt.Errorf("invalid single source prebuilt %+v", module)) 171 } 172 173 if srcPropsValue.Kind() != reflect.Struct && srcPropsValue.Kind() != reflect.Interface { 174 panic(fmt.Errorf("invalid single source prebuilt %+v", srcProps)) 175 } 176 177 srcFieldIndex := srcStructField.Index 178 srcPropertyName := proptools.PropertyNameForField(srcField) 179 180 srcsSupplier := func() []string { 181 value := srcPropsValue.FieldByIndex(srcFieldIndex) 182 if value.Kind() == reflect.Ptr { 183 value = value.Elem() 184 } 185 if value.Kind() != reflect.String { 186 panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one but was %d %q", srcPropertyName, value.Kind(), value)) 187 } 188 src := value.String() 189 if src == "" { 190 return nil 191 } 192 return []string{src} 193 } 194 195 InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, srcPropertyName) 196} 197 198type PrebuiltInterface interface { 199 Module 200 Prebuilt() *Prebuilt 201} 202 203func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) { 204 ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).Parallel() 205} 206 207func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) { 208 ctx.BottomUp("prebuilt_source", PrebuiltSourceDepsMutator).Parallel() 209 ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel() 210 ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).Parallel() 211} 212 213// PrebuiltRenameMutator ensures that there always is a module with an 214// undecorated name. 215func PrebuiltRenameMutator(ctx BottomUpMutatorContext) { 216 if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil { 217 name := m.base().BaseModuleName() 218 if !ctx.OtherModuleExists(name) { 219 ctx.Rename(name) 220 m.Prebuilt().properties.PrebuiltRenamedToSource = true 221 } 222 } 223} 224 225// PrebuiltSourceDepsMutator adds dependencies to the prebuilt module from the 226// corresponding source module, if one exists for the same variant. 227func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) { 228 if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Enabled() && m.Prebuilt() != nil { 229 p := m.Prebuilt() 230 if !p.properties.PrebuiltRenamedToSource { 231 name := m.base().BaseModuleName() 232 if ctx.OtherModuleReverseDependencyVariantExists(name) { 233 ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name) 234 p.properties.SourceExists = true 235 } 236 } 237 } 238} 239 240// PrebuiltSelectModuleMutator marks prebuilts that are used, either overriding source modules or 241// because the source module doesn't exist. It also disables installing overridden source modules. 242func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) { 243 if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil { 244 p := m.Prebuilt() 245 if p.srcsSupplier == nil { 246 panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it")) 247 } 248 if !p.properties.SourceExists { 249 p.properties.UsePrebuilt = p.usePrebuilt(ctx, nil) 250 } 251 } else if s, ok := ctx.Module().(Module); ok { 252 ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(m Module) { 253 p := m.(PrebuiltInterface).Prebuilt() 254 if p.usePrebuilt(ctx, s) { 255 p.properties.UsePrebuilt = true 256 s.SkipInstall() 257 } 258 }) 259 } 260} 261 262// PrebuiltPostDepsMutator does two operations. It replace dependencies on the 263// source module with dependencies on the prebuilt when both modules exist and 264// the prebuilt should be used. When the prebuilt should not be used, disable 265// installing it. Secondly, it also adds a sourcegroup to any filegroups found 266// in the prebuilt's 'Srcs' property. 267func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) { 268 if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil { 269 p := m.Prebuilt() 270 name := m.base().BaseModuleName() 271 if p.properties.UsePrebuilt { 272 if p.properties.SourceExists { 273 ctx.ReplaceDependenciesIf(name, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool { 274 if t, ok := tag.(ReplaceSourceWithPrebuilt); ok { 275 return t.ReplaceSourceWithPrebuilt() 276 } 277 278 return true 279 }) 280 } 281 } else { 282 m.SkipInstall() 283 } 284 } 285} 286 287// usePrebuilt returns true if a prebuilt should be used instead of the source module. The prebuilt 288// will be used if it is marked "prefer" or if the source module is disabled. 289func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool { 290 if p.srcsSupplier != nil && len(p.srcsSupplier()) == 0 { 291 return false 292 } 293 294 // TODO: use p.Properties.Name and ctx.ModuleDir to override preference 295 if Bool(p.properties.Prefer) { 296 return true 297 } 298 299 return source == nil || !source.Enabled() 300} 301 302func (p *Prebuilt) SourceExists() bool { 303 return p.properties.SourceExists 304} 305