xref: /aosp_15_r20/build/soong/android/singleton_module.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2020 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage android
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"fmt"
19*333d2b36SAndroid Build Coastguard Worker	"sync"
20*333d2b36SAndroid Build Coastguard Worker
21*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint"
22*333d2b36SAndroid Build Coastguard Worker)
23*333d2b36SAndroid Build Coastguard Worker
24*333d2b36SAndroid Build Coastguard Worker// A SingletonModule is halfway between a Singleton and a Module.  It has access to visiting
25*333d2b36SAndroid Build Coastguard Worker// other modules via its GenerateSingletonBuildActions method, but must be defined in an Android.bp
26*333d2b36SAndroid Build Coastguard Worker// file and can also be depended on like a module.  It must be used zero or one times in an
27*333d2b36SAndroid Build Coastguard Worker// Android.bp file, and it can only have a single variant.
28*333d2b36SAndroid Build Coastguard Worker//
29*333d2b36SAndroid Build Coastguard Worker// The SingletonModule's GenerateAndroidBuildActions method will be called before any normal or
30*333d2b36SAndroid Build Coastguard Worker// singleton module that depends on it, but its GenerateSingletonBuildActions method will be called
31*333d2b36SAndroid Build Coastguard Worker// after all modules, in registration order with other singletons and singleton modules.
32*333d2b36SAndroid Build Coastguard Worker// GenerateAndroidBuildActions and GenerateSingletonBuildActions will not be called if the
33*333d2b36SAndroid Build Coastguard Worker// SingletonModule was not instantiated in an Android.bp file.
34*333d2b36SAndroid Build Coastguard Worker//
35*333d2b36SAndroid Build Coastguard Worker// Since the SingletonModule rules likely depend on the modules visited during
36*333d2b36SAndroid Build Coastguard Worker// GenerateSingletonBuildActions, the GenerateAndroidBuildActions is unlikely to produce any
37*333d2b36SAndroid Build Coastguard Worker// rules directly.  Instead, it will probably set some providers to paths that will later have rules
38*333d2b36SAndroid Build Coastguard Worker// generated to produce them in GenerateSingletonBuildActions.
39*333d2b36SAndroid Build Coastguard Worker//
40*333d2b36SAndroid Build Coastguard Worker// The expected use case for a SingletonModule is a module that produces files that depend on all
41*333d2b36SAndroid Build Coastguard Worker// modules in the tree and will be used by other modules.  For example it could produce a text
42*333d2b36SAndroid Build Coastguard Worker// file that lists all modules that meet a certain criteria, and that text file could be an input
43*333d2b36SAndroid Build Coastguard Worker// to another module.  Care must be taken that the ninja rules produced by the SingletonModule
44*333d2b36SAndroid Build Coastguard Worker// don't produce a cycle by referencing output files of rules of modules that depend on the
45*333d2b36SAndroid Build Coastguard Worker// SingletonModule.
46*333d2b36SAndroid Build Coastguard Worker//
47*333d2b36SAndroid Build Coastguard Worker// A SingletonModule must embed a SingletonModuleBase struct, and its factory method must be
48*333d2b36SAndroid Build Coastguard Worker// registered with RegisterSingletonModuleType from an init() function.
49*333d2b36SAndroid Build Coastguard Worker//
50*333d2b36SAndroid Build Coastguard Worker// A SingletonModule can also implement SingletonMakeVarsProvider to export values to Make.
51*333d2b36SAndroid Build Coastguard Workertype SingletonModule interface {
52*333d2b36SAndroid Build Coastguard Worker	Module
53*333d2b36SAndroid Build Coastguard Worker	GenerateSingletonBuildActions(SingletonContext)
54*333d2b36SAndroid Build Coastguard Worker	singletonModuleBase() *SingletonModuleBase
55*333d2b36SAndroid Build Coastguard Worker}
56*333d2b36SAndroid Build Coastguard Worker
57*333d2b36SAndroid Build Coastguard Worker// SingletonModuleBase must be embedded into implementers of the SingletonModule interface.
58*333d2b36SAndroid Build Coastguard Workertype SingletonModuleBase struct {
59*333d2b36SAndroid Build Coastguard Worker	ModuleBase
60*333d2b36SAndroid Build Coastguard Worker
61*333d2b36SAndroid Build Coastguard Worker	lock    sync.Mutex
62*333d2b36SAndroid Build Coastguard Worker	bp      string
63*333d2b36SAndroid Build Coastguard Worker	variant string
64*333d2b36SAndroid Build Coastguard Worker}
65*333d2b36SAndroid Build Coastguard Worker
66*333d2b36SAndroid Build Coastguard Worker// GenerateBuildActions wraps the ModuleBase GenerateBuildActions method, verifying it was only
67*333d2b36SAndroid Build Coastguard Worker// called once to prevent multiple variants of a SingletonModule.
68*333d2b36SAndroid Build Coastguard Workerfunc (smb *SingletonModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
69*333d2b36SAndroid Build Coastguard Worker	smb.lock.Lock()
70*333d2b36SAndroid Build Coastguard Worker	if smb.variant != "" {
71*333d2b36SAndroid Build Coastguard Worker		ctx.ModuleErrorf("GenerateAndroidBuildActions already called for variant %q, SingletonModules can only have one variant", smb.variant)
72*333d2b36SAndroid Build Coastguard Worker	}
73*333d2b36SAndroid Build Coastguard Worker	smb.variant = ctx.ModuleSubDir()
74*333d2b36SAndroid Build Coastguard Worker	smb.lock.Unlock()
75*333d2b36SAndroid Build Coastguard Worker
76*333d2b36SAndroid Build Coastguard Worker	smb.ModuleBase.GenerateBuildActions(ctx)
77*333d2b36SAndroid Build Coastguard Worker}
78*333d2b36SAndroid Build Coastguard Worker
79*333d2b36SAndroid Build Coastguard Worker// InitAndroidSingletonModule must be called from the SingletonModule's factory function to
80*333d2b36SAndroid Build Coastguard Worker// initialize SingletonModuleBase.
81*333d2b36SAndroid Build Coastguard Workerfunc InitAndroidSingletonModule(sm SingletonModule) {
82*333d2b36SAndroid Build Coastguard Worker	InitAndroidModule(sm)
83*333d2b36SAndroid Build Coastguard Worker}
84*333d2b36SAndroid Build Coastguard Worker
85*333d2b36SAndroid Build Coastguard Worker// singletonModuleBase retrieves the embedded SingletonModuleBase from a SingletonModule.
86*333d2b36SAndroid Build Coastguard Workerfunc (smb *SingletonModuleBase) singletonModuleBase() *SingletonModuleBase { return smb }
87*333d2b36SAndroid Build Coastguard Worker
88*333d2b36SAndroid Build Coastguard Worker// SingletonModuleFactory is a factory method that returns a SingletonModule.
89*333d2b36SAndroid Build Coastguard Workertype SingletonModuleFactory func() SingletonModule
90*333d2b36SAndroid Build Coastguard Worker
91*333d2b36SAndroid Build Coastguard Worker// SingletonModuleFactoryAdaptor converts a SingletonModuleFactory into a SingletonFactory and a
92*333d2b36SAndroid Build Coastguard Worker// ModuleFactory.
93*333d2b36SAndroid Build Coastguard Workerfunc SingletonModuleFactoryAdaptor(name string, factory SingletonModuleFactory) (SingletonFactory, ModuleFactory) {
94*333d2b36SAndroid Build Coastguard Worker	// The sm variable acts as a static holder of the only SingletonModule instance.  Calls to the
95*333d2b36SAndroid Build Coastguard Worker	// returned SingletonFactory and ModuleFactory lambdas will always return the same sm value.
96*333d2b36SAndroid Build Coastguard Worker	// The SingletonFactory is only expected to be called once, but the ModuleFactory may be
97*333d2b36SAndroid Build Coastguard Worker	// called multiple times if the module is replaced with a clone of itself at the end of
98*333d2b36SAndroid Build Coastguard Worker	// blueprint.ResolveDependencies.
99*333d2b36SAndroid Build Coastguard Worker	var sm SingletonModule
100*333d2b36SAndroid Build Coastguard Worker	s := func() Singleton {
101*333d2b36SAndroid Build Coastguard Worker		sm = factory()
102*333d2b36SAndroid Build Coastguard Worker		return &singletonModuleSingletonAdaptor{sm}
103*333d2b36SAndroid Build Coastguard Worker	}
104*333d2b36SAndroid Build Coastguard Worker	m := func() Module {
105*333d2b36SAndroid Build Coastguard Worker		if sm == nil {
106*333d2b36SAndroid Build Coastguard Worker			panic(fmt.Errorf("Singleton %q for SingletonModule was not instantiated", name))
107*333d2b36SAndroid Build Coastguard Worker		}
108*333d2b36SAndroid Build Coastguard Worker
109*333d2b36SAndroid Build Coastguard Worker		// Check for multiple uses of a SingletonModule in a LoadHook.  Checking directly in the
110*333d2b36SAndroid Build Coastguard Worker		// factory would incorrectly flag when the factory was called again when the module is
111*333d2b36SAndroid Build Coastguard Worker		// replaced with a clone of itself at the end of blueprint.ResolveDependencies.
112*333d2b36SAndroid Build Coastguard Worker		AddLoadHook(sm, func(ctx LoadHookContext) {
113*333d2b36SAndroid Build Coastguard Worker			smb := sm.singletonModuleBase()
114*333d2b36SAndroid Build Coastguard Worker			smb.lock.Lock()
115*333d2b36SAndroid Build Coastguard Worker			defer smb.lock.Unlock()
116*333d2b36SAndroid Build Coastguard Worker			if smb.bp != "" {
117*333d2b36SAndroid Build Coastguard Worker				ctx.ModuleErrorf("Duplicate SingletonModule %q, previously used in %s", name, smb.bp)
118*333d2b36SAndroid Build Coastguard Worker			}
119*333d2b36SAndroid Build Coastguard Worker			smb.bp = ctx.BlueprintsFile()
120*333d2b36SAndroid Build Coastguard Worker		})
121*333d2b36SAndroid Build Coastguard Worker		return sm
122*333d2b36SAndroid Build Coastguard Worker	}
123*333d2b36SAndroid Build Coastguard Worker	return s, m
124*333d2b36SAndroid Build Coastguard Worker}
125*333d2b36SAndroid Build Coastguard Worker
126*333d2b36SAndroid Build Coastguard Worker// singletonModuleSingletonAdaptor makes a SingletonModule into a Singleton by translating the
127*333d2b36SAndroid Build Coastguard Worker// GenerateSingletonBuildActions method to Singleton.GenerateBuildActions.
128*333d2b36SAndroid Build Coastguard Workertype singletonModuleSingletonAdaptor struct {
129*333d2b36SAndroid Build Coastguard Worker	sm SingletonModule
130*333d2b36SAndroid Build Coastguard Worker}
131*333d2b36SAndroid Build Coastguard Worker
132*333d2b36SAndroid Build Coastguard Worker// GenerateBuildActions calls the SingletonModule's GenerateSingletonBuildActions method, but only
133*333d2b36SAndroid Build Coastguard Worker// if the module was defined in an Android.bp file.
134*333d2b36SAndroid Build Coastguard Workerfunc (smsa *singletonModuleSingletonAdaptor) GenerateBuildActions(ctx SingletonContext) {
135*333d2b36SAndroid Build Coastguard Worker	if smsa.sm.singletonModuleBase().bp != "" {
136*333d2b36SAndroid Build Coastguard Worker		smsa.sm.GenerateSingletonBuildActions(ctx)
137*333d2b36SAndroid Build Coastguard Worker	}
138*333d2b36SAndroid Build Coastguard Worker}
139*333d2b36SAndroid Build Coastguard Worker
140*333d2b36SAndroid Build Coastguard Workerfunc (smsa *singletonModuleSingletonAdaptor) MakeVars(ctx MakeVarsContext) {
141*333d2b36SAndroid Build Coastguard Worker	if smsa.sm.singletonModuleBase().bp != "" {
142*333d2b36SAndroid Build Coastguard Worker		if makeVars, ok := smsa.sm.(SingletonMakeVarsProvider); ok {
143*333d2b36SAndroid Build Coastguard Worker			makeVars.MakeVars(ctx)
144*333d2b36SAndroid Build Coastguard Worker		}
145*333d2b36SAndroid Build Coastguard Worker	}
146*333d2b36SAndroid Build Coastguard Worker}
147