singleton_module.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. package android
  15. import (
  16. "fmt"
  17. "sync"
  18. "github.com/google/blueprint"
  19. )
  20. // A SingletonModule is halfway between a Singleton and a Module. It has access to visiting
  21. // other modules via its GenerateSingletonBuildActions method, but must be defined in an Android.bp
  22. // file and can also be depended on like a module. It must be used zero or one times in an
  23. // Android.bp file, and it can only have a single variant.
  24. //
  25. // The SingletonModule's GenerateAndroidBuildActions method will be called before any normal or
  26. // singleton module that depends on it, but its GenerateSingletonBuildActions method will be called
  27. // after all modules, in registration order with other singletons and singleton modules.
  28. // GenerateAndroidBuildActions and GenerateSingletonBuildActions will not be called if the
  29. // SingletonModule was not instantiated in an Android.bp file.
  30. //
  31. // Since the SingletonModule rules likely depend on the modules visited during
  32. // GenerateSingletonBuildActions, the GenerateAndroidBuildActions is unlikely to produce any
  33. // rules directly. Instead, it will probably set some providers to paths that will later have rules
  34. // generated to produce them in GenerateSingletonBuildActions.
  35. //
  36. // The expected use case for a SingletonModule is a module that produces files that depend on all
  37. // modules in the tree and will be used by other modules. For example it could produce a text
  38. // file that lists all modules that meet a certain criteria, and that text file could be an input
  39. // to another module. Care must be taken that the ninja rules produced by the SingletonModule
  40. // don't produce a cycle by referencing output files of rules of modules that depend on the
  41. // SingletonModule.
  42. //
  43. // A SingletonModule must embed a SingletonModuleBase struct, and its factory method must be
  44. // registered with RegisterSingletonModuleType from an init() function.
  45. //
  46. // A SingletonModule can also implement SingletonMakeVarsProvider to export values to Make.
  47. type SingletonModule interface {
  48. Module
  49. GenerateSingletonBuildActions(SingletonContext)
  50. singletonModuleBase() *SingletonModuleBase
  51. }
  52. // SingletonModuleBase must be embedded into implementers of the SingletonModule interface.
  53. type SingletonModuleBase struct {
  54. ModuleBase
  55. lock sync.Mutex
  56. bp string
  57. variant string
  58. }
  59. // GenerateBuildActions wraps the ModuleBase GenerateBuildActions method, verifying it was only
  60. // called once to prevent multiple variants of a SingletonModule.
  61. func (smb *SingletonModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
  62. smb.lock.Lock()
  63. if smb.variant != "" {
  64. ctx.ModuleErrorf("GenerateAndroidBuildActions already called for variant %q, SingletonModules can only have one variant", smb.variant)
  65. }
  66. smb.variant = ctx.ModuleSubDir()
  67. smb.lock.Unlock()
  68. smb.ModuleBase.GenerateBuildActions(ctx)
  69. }
  70. // InitAndroidSingletonModule must be called from the SingletonModule's factory function to
  71. // initialize SingletonModuleBase.
  72. func InitAndroidSingletonModule(sm SingletonModule) {
  73. InitAndroidModule(sm)
  74. }
  75. // singletonModuleBase retrieves the embedded SingletonModuleBase from a SingletonModule.
  76. func (smb *SingletonModuleBase) singletonModuleBase() *SingletonModuleBase { return smb }
  77. // SingletonModuleFactory is a factory method that returns a SingletonModule.
  78. type SingletonModuleFactory func() SingletonModule
  79. // SingletonModuleFactoryAdaptor converts a SingletonModuleFactory into a SingletonFactory and a
  80. // ModuleFactory.
  81. func SingletonModuleFactoryAdaptor(name string, factory SingletonModuleFactory) (SingletonFactory, ModuleFactory) {
  82. // The sm variable acts as a static holder of the only SingletonModule instance. Calls to the
  83. // returned SingletonFactory and ModuleFactory lambdas will always return the same sm value.
  84. // The SingletonFactory is only expected to be called once, but the ModuleFactory may be
  85. // called multiple times if the module is replaced with a clone of itself at the end of
  86. // blueprint.ResolveDependencies.
  87. var sm SingletonModule
  88. s := func() Singleton {
  89. sm = factory()
  90. return &singletonModuleSingletonAdaptor{sm}
  91. }
  92. m := func() Module {
  93. if sm == nil {
  94. panic(fmt.Errorf("Singleton %q for SingletonModule was not instantiated", name))
  95. }
  96. // Check for multiple uses of a SingletonModule in a LoadHook. Checking directly in the
  97. // factory would incorrectly flag when the factory was called again when the module is
  98. // replaced with a clone of itself at the end of blueprint.ResolveDependencies.
  99. AddLoadHook(sm, func(ctx LoadHookContext) {
  100. smb := sm.singletonModuleBase()
  101. smb.lock.Lock()
  102. defer smb.lock.Unlock()
  103. if smb.bp != "" {
  104. ctx.ModuleErrorf("Duplicate SingletonModule %q, previously used in %s", name, smb.bp)
  105. }
  106. smb.bp = ctx.BlueprintsFile()
  107. })
  108. return sm
  109. }
  110. return s, m
  111. }
  112. // singletonModuleSingletonAdaptor makes a SingletonModule into a Singleton by translating the
  113. // GenerateSingletonBuildActions method to Singleton.GenerateBuildActions.
  114. type singletonModuleSingletonAdaptor struct {
  115. sm SingletonModule
  116. }
  117. // GenerateBuildActions calls the SingletonModule's GenerateSingletonBuildActions method, but only
  118. // if the module was defined in an Android.bp file.
  119. func (smsa *singletonModuleSingletonAdaptor) GenerateBuildActions(ctx SingletonContext) {
  120. if smsa.sm.singletonModuleBase().bp != "" {
  121. smsa.sm.GenerateSingletonBuildActions(ctx)
  122. }
  123. }
  124. func (smsa *singletonModuleSingletonAdaptor) MakeVars(ctx MakeVarsContext) {
  125. if smsa.sm.singletonModuleBase().bp != "" {
  126. if makeVars, ok := smsa.sm.(SingletonMakeVarsProvider); ok {
  127. makeVars.MakeVars(ctx)
  128. }
  129. }
  130. }