xref: /aosp_15_r20/build/soong/android/hooks.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2016 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	"path"
20*333d2b36SAndroid Build Coastguard Worker	"reflect"
21*333d2b36SAndroid Build Coastguard Worker	"runtime"
22*333d2b36SAndroid Build Coastguard Worker
23*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint"
24*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint/proptools"
25*333d2b36SAndroid Build Coastguard Worker)
26*333d2b36SAndroid Build Coastguard Worker
27*333d2b36SAndroid Build Coastguard Worker// This file implements hooks that external module types can use to inject logic into existing
28*333d2b36SAndroid Build Coastguard Worker// module types.  Each hook takes an interface as a parameter so that new methods can be added
29*333d2b36SAndroid Build Coastguard Worker// to the interface without breaking existing module types.
30*333d2b36SAndroid Build Coastguard Worker
31*333d2b36SAndroid Build Coastguard Worker// Load hooks are run after the module's properties have been filled from the blueprint file, but
32*333d2b36SAndroid Build Coastguard Worker// before the module has been split into architecture variants, and before defaults modules have
33*333d2b36SAndroid Build Coastguard Worker// been applied.
34*333d2b36SAndroid Build Coastguard Workertype LoadHookContext interface {
35*333d2b36SAndroid Build Coastguard Worker	EarlyModuleContext
36*333d2b36SAndroid Build Coastguard Worker
37*333d2b36SAndroid Build Coastguard Worker	AppendProperties(...interface{})
38*333d2b36SAndroid Build Coastguard Worker	PrependProperties(...interface{})
39*333d2b36SAndroid Build Coastguard Worker	CreateModule(ModuleFactory, ...interface{}) Module
40*333d2b36SAndroid Build Coastguard Worker	CreateModuleInDirectory(ModuleFactory, string, ...interface{}) Module
41*333d2b36SAndroid Build Coastguard Worker
42*333d2b36SAndroid Build Coastguard Worker	registerScopedModuleType(name string, factory blueprint.ModuleFactory)
43*333d2b36SAndroid Build Coastguard Worker	moduleFactories() map[string]blueprint.ModuleFactory
44*333d2b36SAndroid Build Coastguard Worker}
45*333d2b36SAndroid Build Coastguard Worker
46*333d2b36SAndroid Build Coastguard Worker// Add a hook that will be called once the module has been loaded, i.e. its
47*333d2b36SAndroid Build Coastguard Worker// properties have been initialized from the Android.bp file.
48*333d2b36SAndroid Build Coastguard Worker//
49*333d2b36SAndroid Build Coastguard Worker// Consider using SetDefaultableHook to register a hook for any module that implements
50*333d2b36SAndroid Build Coastguard Worker// DefaultableModule as the hook is called after any defaults have been applied to the
51*333d2b36SAndroid Build Coastguard Worker// module which could reduce duplication and make it easier to use.
52*333d2b36SAndroid Build Coastguard Workerfunc AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) {
53*333d2b36SAndroid Build Coastguard Worker	blueprint.AddLoadHook(m, func(ctx blueprint.LoadHookContext) {
54*333d2b36SAndroid Build Coastguard Worker		actx := &loadHookContext{
55*333d2b36SAndroid Build Coastguard Worker			earlyModuleContext: m.(Module).base().earlyModuleContextFactory(ctx),
56*333d2b36SAndroid Build Coastguard Worker			bp:                 ctx,
57*333d2b36SAndroid Build Coastguard Worker		}
58*333d2b36SAndroid Build Coastguard Worker		hook(actx)
59*333d2b36SAndroid Build Coastguard Worker	})
60*333d2b36SAndroid Build Coastguard Worker}
61*333d2b36SAndroid Build Coastguard Worker
62*333d2b36SAndroid Build Coastguard Workerfunc AddLoadHookWithPriority(m blueprint.Module, hook func(LoadHookContext), priority int) {
63*333d2b36SAndroid Build Coastguard Worker	blueprint.AddLoadHookWithPriority(m, func(ctx blueprint.LoadHookContext) {
64*333d2b36SAndroid Build Coastguard Worker		actx := &loadHookContext{
65*333d2b36SAndroid Build Coastguard Worker			earlyModuleContext: m.(Module).base().earlyModuleContextFactory(ctx),
66*333d2b36SAndroid Build Coastguard Worker			bp:                 ctx,
67*333d2b36SAndroid Build Coastguard Worker		}
68*333d2b36SAndroid Build Coastguard Worker		hook(actx)
69*333d2b36SAndroid Build Coastguard Worker	}, priority)
70*333d2b36SAndroid Build Coastguard Worker}
71*333d2b36SAndroid Build Coastguard Worker
72*333d2b36SAndroid Build Coastguard Workertype loadHookContext struct {
73*333d2b36SAndroid Build Coastguard Worker	earlyModuleContext
74*333d2b36SAndroid Build Coastguard Worker	bp     blueprint.LoadHookContext
75*333d2b36SAndroid Build Coastguard Worker	module Module
76*333d2b36SAndroid Build Coastguard Worker}
77*333d2b36SAndroid Build Coastguard Worker
78*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) moduleFactories() map[string]blueprint.ModuleFactory {
79*333d2b36SAndroid Build Coastguard Worker	return l.bp.ModuleFactories()
80*333d2b36SAndroid Build Coastguard Worker}
81*333d2b36SAndroid Build Coastguard Worker
82*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) appendPrependHelper(props []interface{},
83*333d2b36SAndroid Build Coastguard Worker	extendFn func([]interface{}, interface{}, proptools.ExtendPropertyFilterFunc) error) {
84*333d2b36SAndroid Build Coastguard Worker	for _, p := range props {
85*333d2b36SAndroid Build Coastguard Worker		err := extendFn(l.Module().base().GetProperties(), p, nil)
86*333d2b36SAndroid Build Coastguard Worker		if err != nil {
87*333d2b36SAndroid Build Coastguard Worker			if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
88*333d2b36SAndroid Build Coastguard Worker				l.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
89*333d2b36SAndroid Build Coastguard Worker			} else {
90*333d2b36SAndroid Build Coastguard Worker				panic(err)
91*333d2b36SAndroid Build Coastguard Worker			}
92*333d2b36SAndroid Build Coastguard Worker		}
93*333d2b36SAndroid Build Coastguard Worker	}
94*333d2b36SAndroid Build Coastguard Worker}
95*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) AppendProperties(props ...interface{}) {
96*333d2b36SAndroid Build Coastguard Worker	l.appendPrependHelper(props, proptools.AppendMatchingProperties)
97*333d2b36SAndroid Build Coastguard Worker}
98*333d2b36SAndroid Build Coastguard Worker
99*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) PrependProperties(props ...interface{}) {
100*333d2b36SAndroid Build Coastguard Worker	l.appendPrependHelper(props, proptools.PrependMatchingProperties)
101*333d2b36SAndroid Build Coastguard Worker}
102*333d2b36SAndroid Build Coastguard Worker
103*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) blueprint.Module {
104*333d2b36SAndroid Build Coastguard Worker	return l.bp.CreateModule(factory, name, props...)
105*333d2b36SAndroid Build Coastguard Worker}
106*333d2b36SAndroid Build Coastguard Worker
107*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) createModuleInDirectory(factory blueprint.ModuleFactory, name, moduleDir string, props ...interface{}) blueprint.Module {
108*333d2b36SAndroid Build Coastguard Worker	return l.bp.CreateModuleInDirectory(factory, name, moduleDir, props...)
109*333d2b36SAndroid Build Coastguard Worker}
110*333d2b36SAndroid Build Coastguard Worker
111*333d2b36SAndroid Build Coastguard Workertype specifyDirectory struct {
112*333d2b36SAndroid Build Coastguard Worker	specified bool
113*333d2b36SAndroid Build Coastguard Worker	directory string
114*333d2b36SAndroid Build Coastguard Worker}
115*333d2b36SAndroid Build Coastguard Worker
116*333d2b36SAndroid Build Coastguard Workerfunc doesNotSpecifyDirectory() specifyDirectory {
117*333d2b36SAndroid Build Coastguard Worker	return specifyDirectory{
118*333d2b36SAndroid Build Coastguard Worker		specified: false,
119*333d2b36SAndroid Build Coastguard Worker		directory: "",
120*333d2b36SAndroid Build Coastguard Worker	}
121*333d2b36SAndroid Build Coastguard Worker}
122*333d2b36SAndroid Build Coastguard Worker
123*333d2b36SAndroid Build Coastguard Workerfunc specifiesDirectory(directory string) specifyDirectory {
124*333d2b36SAndroid Build Coastguard Worker	return specifyDirectory{
125*333d2b36SAndroid Build Coastguard Worker		specified: true,
126*333d2b36SAndroid Build Coastguard Worker		directory: directory,
127*333d2b36SAndroid Build Coastguard Worker	}
128*333d2b36SAndroid Build Coastguard Worker}
129*333d2b36SAndroid Build Coastguard Worker
130*333d2b36SAndroid Build Coastguard Workertype createModuleContext interface {
131*333d2b36SAndroid Build Coastguard Worker	Module() Module
132*333d2b36SAndroid Build Coastguard Worker	HasMutatorFinished(mutatorName string) bool
133*333d2b36SAndroid Build Coastguard Worker	createModule(blueprint.ModuleFactory, string, ...interface{}) blueprint.Module
134*333d2b36SAndroid Build Coastguard Worker	createModuleInDirectory(blueprint.ModuleFactory, string, string, ...interface{}) blueprint.Module
135*333d2b36SAndroid Build Coastguard Worker}
136*333d2b36SAndroid Build Coastguard Worker
137*333d2b36SAndroid Build Coastguard Workerfunc createModule(ctx createModuleContext, factory ModuleFactory, ext string, specifyDirectory specifyDirectory, props ...interface{}) Module {
138*333d2b36SAndroid Build Coastguard Worker	if ctx.HasMutatorFinished("defaults") {
139*333d2b36SAndroid Build Coastguard Worker		// Creating modules late is oftentimes problematic, because they don't have earlier
140*333d2b36SAndroid Build Coastguard Worker		// mutators run on them. Prevent making modules after the defaults mutator has run.
141*333d2b36SAndroid Build Coastguard Worker		panic("Cannot create a module after the defaults mutator has finished")
142*333d2b36SAndroid Build Coastguard Worker	}
143*333d2b36SAndroid Build Coastguard Worker
144*333d2b36SAndroid Build Coastguard Worker	inherited := []interface{}{&ctx.Module().base().commonProperties}
145*333d2b36SAndroid Build Coastguard Worker
146*333d2b36SAndroid Build Coastguard Worker	var typeName string
147*333d2b36SAndroid Build Coastguard Worker	if typeNameLookup, ok := ModuleTypeByFactory()[reflect.ValueOf(factory)]; ok {
148*333d2b36SAndroid Build Coastguard Worker		typeName = typeNameLookup
149*333d2b36SAndroid Build Coastguard Worker	} else {
150*333d2b36SAndroid Build Coastguard Worker		factoryPtr := reflect.ValueOf(factory).Pointer()
151*333d2b36SAndroid Build Coastguard Worker		factoryFunc := runtime.FuncForPC(factoryPtr)
152*333d2b36SAndroid Build Coastguard Worker		filePath, _ := factoryFunc.FileLine(factoryPtr)
153*333d2b36SAndroid Build Coastguard Worker		typeName = fmt.Sprintf("%s_%s", path.Base(filePath), factoryFunc.Name())
154*333d2b36SAndroid Build Coastguard Worker	}
155*333d2b36SAndroid Build Coastguard Worker	typeName = typeName + "_" + ext
156*333d2b36SAndroid Build Coastguard Worker
157*333d2b36SAndroid Build Coastguard Worker	var module Module
158*333d2b36SAndroid Build Coastguard Worker	if specifyDirectory.specified {
159*333d2b36SAndroid Build Coastguard Worker		module = ctx.createModuleInDirectory(ModuleFactoryAdaptor(factory), typeName, specifyDirectory.directory, append(inherited, props...)...).(Module)
160*333d2b36SAndroid Build Coastguard Worker	} else {
161*333d2b36SAndroid Build Coastguard Worker		module = ctx.createModule(ModuleFactoryAdaptor(factory), typeName, append(inherited, props...)...).(Module)
162*333d2b36SAndroid Build Coastguard Worker	}
163*333d2b36SAndroid Build Coastguard Worker
164*333d2b36SAndroid Build Coastguard Worker	if ctx.Module().base().variableProperties != nil && module.base().variableProperties != nil {
165*333d2b36SAndroid Build Coastguard Worker		src := ctx.Module().base().variableProperties
166*333d2b36SAndroid Build Coastguard Worker		dst := []interface{}{
167*333d2b36SAndroid Build Coastguard Worker			module.base().variableProperties,
168*333d2b36SAndroid Build Coastguard Worker			// Put an empty copy of the src properties into dst so that properties in src that are not in dst
169*333d2b36SAndroid Build Coastguard Worker			// don't cause a "failed to find property to extend" error.
170*333d2b36SAndroid Build Coastguard Worker			proptools.CloneEmptyProperties(reflect.ValueOf(src)).Interface(),
171*333d2b36SAndroid Build Coastguard Worker		}
172*333d2b36SAndroid Build Coastguard Worker		err := proptools.AppendMatchingProperties(dst, src, nil)
173*333d2b36SAndroid Build Coastguard Worker		if err != nil {
174*333d2b36SAndroid Build Coastguard Worker			panic(err)
175*333d2b36SAndroid Build Coastguard Worker		}
176*333d2b36SAndroid Build Coastguard Worker	}
177*333d2b36SAndroid Build Coastguard Worker
178*333d2b36SAndroid Build Coastguard Worker	return module
179*333d2b36SAndroid Build Coastguard Worker}
180*333d2b36SAndroid Build Coastguard Worker
181*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
182*333d2b36SAndroid Build Coastguard Worker	return createModule(l, factory, "_loadHookModule", doesNotSpecifyDirectory(), props...)
183*333d2b36SAndroid Build Coastguard Worker}
184*333d2b36SAndroid Build Coastguard Worker
185*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) CreateModuleInDirectory(factory ModuleFactory, directory string, props ...interface{}) Module {
186*333d2b36SAndroid Build Coastguard Worker	return createModule(l, factory, "_loadHookModule", specifiesDirectory(directory), props...)
187*333d2b36SAndroid Build Coastguard Worker}
188*333d2b36SAndroid Build Coastguard Worker
189*333d2b36SAndroid Build Coastguard Workerfunc (l *loadHookContext) registerScopedModuleType(name string, factory blueprint.ModuleFactory) {
190*333d2b36SAndroid Build Coastguard Worker	l.bp.RegisterScopedModuleType(name, factory)
191*333d2b36SAndroid Build Coastguard Worker}
192*333d2b36SAndroid Build Coastguard Worker
193*333d2b36SAndroid Build Coastguard Workertype InstallHookContext interface {
194*333d2b36SAndroid Build Coastguard Worker	ModuleContext
195*333d2b36SAndroid Build Coastguard Worker	SrcPath() Path
196*333d2b36SAndroid Build Coastguard Worker	Path() InstallPath
197*333d2b36SAndroid Build Coastguard Worker	Symlink() bool
198*333d2b36SAndroid Build Coastguard Worker}
199*333d2b36SAndroid Build Coastguard Worker
200*333d2b36SAndroid Build Coastguard Worker// Install hooks are run after a module creates a rule to install a file or symlink.
201*333d2b36SAndroid Build Coastguard Worker// The installed path is available from InstallHookContext.Path(), and
202*333d2b36SAndroid Build Coastguard Worker// InstallHookContext.Symlink() will be true if it was a symlink.
203*333d2b36SAndroid Build Coastguard Workerfunc AddInstallHook(m blueprint.Module, hook func(InstallHookContext)) {
204*333d2b36SAndroid Build Coastguard Worker	h := &m.(Module).base().hooks
205*333d2b36SAndroid Build Coastguard Worker	h.install = append(h.install, hook)
206*333d2b36SAndroid Build Coastguard Worker}
207*333d2b36SAndroid Build Coastguard Worker
208*333d2b36SAndroid Build Coastguard Workertype installHookContext struct {
209*333d2b36SAndroid Build Coastguard Worker	ModuleContext
210*333d2b36SAndroid Build Coastguard Worker	srcPath Path
211*333d2b36SAndroid Build Coastguard Worker	path    InstallPath
212*333d2b36SAndroid Build Coastguard Worker	symlink bool
213*333d2b36SAndroid Build Coastguard Worker}
214*333d2b36SAndroid Build Coastguard Worker
215*333d2b36SAndroid Build Coastguard Workervar _ InstallHookContext = &installHookContext{}
216*333d2b36SAndroid Build Coastguard Worker
217*333d2b36SAndroid Build Coastguard Workerfunc (x *installHookContext) SrcPath() Path {
218*333d2b36SAndroid Build Coastguard Worker	return x.srcPath
219*333d2b36SAndroid Build Coastguard Worker}
220*333d2b36SAndroid Build Coastguard Worker
221*333d2b36SAndroid Build Coastguard Workerfunc (x *installHookContext) Path() InstallPath {
222*333d2b36SAndroid Build Coastguard Worker	return x.path
223*333d2b36SAndroid Build Coastguard Worker}
224*333d2b36SAndroid Build Coastguard Worker
225*333d2b36SAndroid Build Coastguard Workerfunc (x *installHookContext) Symlink() bool {
226*333d2b36SAndroid Build Coastguard Worker	return x.symlink
227*333d2b36SAndroid Build Coastguard Worker}
228*333d2b36SAndroid Build Coastguard Worker
229*333d2b36SAndroid Build Coastguard Workerfunc (x *hooks) runInstallHooks(ctx ModuleContext, srcPath Path, path InstallPath, symlink bool) {
230*333d2b36SAndroid Build Coastguard Worker	if len(x.install) > 0 {
231*333d2b36SAndroid Build Coastguard Worker		mctx := &installHookContext{
232*333d2b36SAndroid Build Coastguard Worker			ModuleContext: ctx,
233*333d2b36SAndroid Build Coastguard Worker			srcPath:       srcPath,
234*333d2b36SAndroid Build Coastguard Worker			path:          path,
235*333d2b36SAndroid Build Coastguard Worker			symlink:       symlink,
236*333d2b36SAndroid Build Coastguard Worker		}
237*333d2b36SAndroid Build Coastguard Worker		for _, x := range x.install {
238*333d2b36SAndroid Build Coastguard Worker			x(mctx)
239*333d2b36SAndroid Build Coastguard Worker			if mctx.Failed() {
240*333d2b36SAndroid Build Coastguard Worker				return
241*333d2b36SAndroid Build Coastguard Worker			}
242*333d2b36SAndroid Build Coastguard Worker		}
243*333d2b36SAndroid Build Coastguard Worker	}
244*333d2b36SAndroid Build Coastguard Worker}
245*333d2b36SAndroid Build Coastguard Worker
246*333d2b36SAndroid Build Coastguard Workertype hooks struct {
247*333d2b36SAndroid Build Coastguard Worker	install []func(InstallHookContext)
248*333d2b36SAndroid Build Coastguard Worker}
249