1// Copyright 2020 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 "strings" 19 "sync" 20 21 "github.com/google/blueprint" 22) 23 24var phonyMapOnceKey = NewOnceKey("phony") 25 26type phonyMap map[string]Paths 27 28var phonyMapLock sync.Mutex 29 30type ModulePhonyInfo struct { 31 Phonies map[string]Paths 32} 33 34var ModulePhonyProvider = blueprint.NewProvider[ModulePhonyInfo]() 35 36func getSingletonPhonyMap(config Config) phonyMap { 37 return config.Once(phonyMapOnceKey, func() interface{} { 38 return make(phonyMap) 39 }).(phonyMap) 40} 41 42func addSingletonPhony(config Config, name string, deps ...Path) { 43 phonyMap := getSingletonPhonyMap(config) 44 phonyMapLock.Lock() 45 defer phonyMapLock.Unlock() 46 phonyMap[name] = append(phonyMap[name], deps...) 47} 48 49type phonySingleton struct { 50 phonyMap phonyMap 51 phonyList []string 52} 53 54var _ SingletonMakeVarsProvider = (*phonySingleton)(nil) 55 56func (p *phonySingleton) GenerateBuildActions(ctx SingletonContext) { 57 p.phonyMap = getSingletonPhonyMap(ctx.Config()) 58 ctx.VisitAllModuleProxies(func(m ModuleProxy) { 59 if info, ok := OtherModuleProvider(ctx, m, ModulePhonyProvider); ok { 60 for k, v := range info.Phonies { 61 p.phonyMap[k] = append(p.phonyMap[k], v...) 62 } 63 } 64 }) 65 66 p.phonyList = SortedKeys(p.phonyMap) 67 for _, phony := range p.phonyList { 68 p.phonyMap[phony] = SortedUniquePaths(p.phonyMap[phony]) 69 } 70 71 if !ctx.Config().KatiEnabled() { 72 // In soong-only builds, the phonies can conflict with dist targets that will 73 // be generated in the packaging step. Instead of emitting a blueprint/ninja phony directly, 74 // create a makefile that defines the phonies that will be included in the packaging step. 75 // Make will dedup the phonies there. 76 var buildPhonyFileContents strings.Builder 77 for _, phony := range p.phonyList { 78 buildPhonyFileContents.WriteString(".PHONY: ") 79 buildPhonyFileContents.WriteString(phony) 80 buildPhonyFileContents.WriteString("\n") 81 buildPhonyFileContents.WriteString(phony) 82 buildPhonyFileContents.WriteString(":") 83 for _, dep := range p.phonyMap[phony] { 84 buildPhonyFileContents.WriteString(" ") 85 buildPhonyFileContents.WriteString(dep.String()) 86 } 87 buildPhonyFileContents.WriteString("\n") 88 } 89 buildPhonyFile := PathForOutput(ctx, "soong_phony_targets.mk") 90 writeValueIfChanged(ctx, absolutePath(buildPhonyFile.String()), buildPhonyFileContents.String()) 91 } 92} 93 94func (p phonySingleton) MakeVars(ctx MakeVarsContext) { 95 for _, phony := range p.phonyList { 96 ctx.Phony(phony, p.phonyMap[phony]...) 97 } 98} 99 100func phonySingletonFactory() Singleton { 101 return &phonySingleton{} 102} 103