blob: 64b0207e71cfc19db00c6387db1179a315e5cf41 [file] [log] [blame]
Colin Cross463a90e2015-06-17 14:20:06 -07001// Copyright 2015 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
Colin Cross798bfce2016-10-12 14:28:16 -070015package android
Colin Cross463a90e2015-06-17 14:20:06 -070016
Colin Cross4498afc2016-10-13 14:18:27 -070017import (
Paul Duffin0a286832019-12-19 12:23:01 +000018 "fmt"
Colin Cross9aed5bc2020-12-28 15:15:34 -080019 "reflect"
Paul Duffin0a286832019-12-19 12:23:01 +000020
Colin Cross4498afc2016-10-13 14:18:27 -070021 "github.com/google/blueprint"
22)
Colin Cross463a90e2015-06-17 14:20:06 -070023
Paul Duffin1d2d42f2021-03-06 20:08:12 +000024// A sortable component is one whose registration order affects the order in which it is executed
25// and so affects the behavior of the build system. As a result it is important for the order in
26// which they are registered during tests to match the order used at runtime and so the test
27// infrastructure will sort them to match.
28//
29// The sortable components are mutators, singletons and pre-singletons. Module types are not
30// sortable because their order of registration does not affect the runtime behavior.
31type sortableComponent interface {
32 // componentName returns the name of the component.
33 //
Usta Shresthac725f472022-01-11 02:44:21 -050034 // Uniquely identifies the components within the set of components used at runtime and during
Paul Duffin1d2d42f2021-03-06 20:08:12 +000035 // tests.
36 componentName() string
37
Sasha Smundak1845f422022-12-13 14:18:58 -080038 // registers this component in the supplied context.
Paul Duffin1d2d42f2021-03-06 20:08:12 +000039 register(ctx *Context)
40}
41
42type sortableComponents []sortableComponent
43
44// registerAll registers all components in this slice with the supplied context.
45func (r sortableComponents) registerAll(ctx *Context) {
46 for _, c := range r {
47 c.register(ctx)
48 }
49}
50
Colin Cross463a90e2015-06-17 14:20:06 -070051type moduleType struct {
52 name string
Colin Cross7089c272019-01-25 22:43:35 -080053 factory ModuleFactory
Colin Cross463a90e2015-06-17 14:20:06 -070054}
55
Paul Duffin1d2d42f2021-03-06 20:08:12 +000056func (t moduleType) register(ctx *Context) {
57 ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory))
58}
59
Colin Cross463a90e2015-06-17 14:20:06 -070060var moduleTypes []moduleType
Colin Cross9aed5bc2020-12-28 15:15:34 -080061var moduleTypesForDocs = map[string]reflect.Value{}
Sam Delmerico286bf262022-03-09 20:46:37 +000062var moduleTypeByFactory = map[reflect.Value]string{}
Colin Cross463a90e2015-06-17 14:20:06 -070063
64type singleton struct {
Paul Duffin1d2d42f2021-03-06 20:08:12 +000065 // True if this should be registered as a pre-singleton, false otherwise.
66 pre bool
67
LaMont Jonese59c0db2023-05-15 21:50:29 +000068 // True if this should be registered as a parallel singleton.
69 parallel bool
70
Colin Cross463a90e2015-06-17 14:20:06 -070071 name string
Colin Cross06fa5882020-10-29 18:21:38 -070072 factory SingletonFactory
Colin Cross463a90e2015-06-17 14:20:06 -070073}
74
LaMont Jonese59c0db2023-05-15 21:50:29 +000075func newSingleton(name string, factory SingletonFactory, parallel bool) singleton {
76 return singleton{pre: false, parallel: parallel, name: name, factory: factory}
Paul Duffin1d2d42f2021-03-06 20:08:12 +000077}
78
79func newPreSingleton(name string, factory SingletonFactory) singleton {
LaMont Jonese59c0db2023-05-15 21:50:29 +000080 return singleton{pre: true, parallel: false, name: name, factory: factory}
Paul Duffin1d2d42f2021-03-06 20:08:12 +000081}
82
83func (s singleton) componentName() string {
84 return s.name
85}
86
87func (s singleton) register(ctx *Context) {
88 adaptor := SingletonFactoryAdaptor(ctx, s.factory)
89 if s.pre {
90 ctx.RegisterPreSingletonType(s.name, adaptor)
91 } else {
LaMont Jonese59c0db2023-05-15 21:50:29 +000092 ctx.RegisterSingletonType(s.name, adaptor, s.parallel)
Paul Duffin1d2d42f2021-03-06 20:08:12 +000093 }
94}
95
96var _ sortableComponent = singleton{}
97
98var singletons sortableComponents
99var preSingletons sortableComponents
Colin Cross463a90e2015-06-17 14:20:06 -0700100
Colin Cross6362e272015-10-29 15:25:03 -0700101type mutator struct {
Lukacs T. Berki6c716762022-06-13 20:50:39 +0200102 name string
103 bottomUpMutator blueprint.BottomUpMutator
104 topDownMutator blueprint.TopDownMutator
105 transitionMutator blueprint.TransitionMutator
106 parallel bool
Colin Cross463a90e2015-06-17 14:20:06 -0700107}
108
Paul Duffin1d2d42f2021-03-06 20:08:12 +0000109var _ sortableComponent = &mutator{}
110
Colin Cross36242852017-06-23 15:06:31 -0700111type ModuleFactory func() Module
112
Colin Cross0875c522017-11-28 17:34:01 -0800113// ModuleFactoryAdaptor wraps a ModuleFactory into a blueprint.ModuleFactory by converting a Module
Colin Cross36242852017-06-23 15:06:31 -0700114// into a blueprint.Module and a list of property structs
115func ModuleFactoryAdaptor(factory ModuleFactory) blueprint.ModuleFactory {
116 return func() (blueprint.Module, []interface{}) {
117 module := factory()
118 return module, module.GetProperties()
119 }
120}
121
Colin Cross0875c522017-11-28 17:34:01 -0800122type SingletonFactory func() Singleton
123
124// SingletonFactoryAdaptor wraps a SingletonFactory into a blueprint.SingletonFactory by converting
125// a Singleton into a blueprint.Singleton
Colin Cross06fa5882020-10-29 18:21:38 -0700126func SingletonFactoryAdaptor(ctx *Context, factory SingletonFactory) blueprint.SingletonFactory {
Colin Cross0875c522017-11-28 17:34:01 -0800127 return func() blueprint.Singleton {
128 singleton := factory()
Colin Crossed023ec2019-02-19 12:38:45 -0800129 if makevars, ok := singleton.(SingletonMakeVarsProvider); ok {
Sasha Smundak1845f422022-12-13 14:18:58 -0800130 ctx.registerSingletonMakeVarsProvider(makevars)
Colin Crossed023ec2019-02-19 12:38:45 -0800131 }
Colin Cross4c83e5c2019-02-25 14:54:28 -0800132 return &singletonAdaptor{Singleton: singleton}
Colin Cross0875c522017-11-28 17:34:01 -0800133 }
134}
135
Colin Cross36242852017-06-23 15:06:31 -0700136func RegisterModuleType(name string, factory ModuleFactory) {
Colin Cross7089c272019-01-25 22:43:35 -0800137 moduleTypes = append(moduleTypes, moduleType{name, factory})
Colin Cross9aed5bc2020-12-28 15:15:34 -0800138 RegisterModuleTypeForDocs(name, reflect.ValueOf(factory))
139}
140
141// RegisterModuleTypeForDocs associates a module type name with a reflect.Value of the factory
142// function that has documentation for the module type. It is normally called automatically
143// by RegisterModuleType, but can be called manually after RegisterModuleType in order to
144// override the factory method used for documentation, for example if the method passed to
145// RegisterModuleType was a lambda.
146func RegisterModuleTypeForDocs(name string, factory reflect.Value) {
147 moduleTypesForDocs[name] = factory
Sam Delmerico286bf262022-03-09 20:46:37 +0000148 moduleTypeByFactory[factory] = name
Colin Cross463a90e2015-06-17 14:20:06 -0700149}
150
LaMont Jonese59c0db2023-05-15 21:50:29 +0000151func registerSingletonType(name string, factory SingletonFactory, parallel bool) {
152 singletons = append(singletons, newSingleton(name, factory, parallel))
153}
154
Colin Cross0875c522017-11-28 17:34:01 -0800155func RegisterSingletonType(name string, factory SingletonFactory) {
LaMont Jonese59c0db2023-05-15 21:50:29 +0000156 registerSingletonType(name, factory, false)
157}
158
159func RegisterParallelSingletonType(name string, factory SingletonFactory) {
160 registerSingletonType(name, factory, true)
Colin Cross463a90e2015-06-17 14:20:06 -0700161}
162
Colin Cross0875c522017-11-28 17:34:01 -0800163func RegisterPreSingletonType(name string, factory SingletonFactory) {
Paul Duffin1d2d42f2021-03-06 20:08:12 +0000164 preSingletons = append(preSingletons, newPreSingleton(name, factory))
Colin Cross5a79c832017-11-07 13:35:38 -0800165}
166
Colin Crosscec81712017-07-13 14:43:27 -0700167type Context struct {
168 *blueprint.Context
Colin Crossae8600b2020-10-29 17:09:13 -0700169 config Config
Colin Crosscec81712017-07-13 14:43:27 -0700170}
Colin Cross463a90e2015-06-17 14:20:06 -0700171
Colin Crossae8600b2020-10-29 17:09:13 -0700172func NewContext(config Config) *Context {
173 ctx := &Context{blueprint.NewContext(), config}
Colin Cross988414c2020-01-11 01:11:46 +0000174 ctx.SetSrcDir(absSrcDir)
Spandan Dasc5763832022-11-08 18:42:16 +0000175 ctx.AddIncludeTags(config.IncludeTags()...)
Sam Delmerico98a73292023-02-21 11:50:29 -0500176 ctx.AddSourceRootDirs(config.SourceRootDirs()...)
Colin Cross988414c2020-01-11 01:11:46 +0000177 return ctx
Colin Crosscec81712017-07-13 14:43:27 -0700178}
179
Spandan Das75e139b2022-11-28 20:12:03 +0000180// Helper function to register the module types used in bp2build and
181// api_bp2build.
182func registerModuleTypes(ctx *Context) {
Jingwen Chen4133ce62020-12-02 04:34:15 -0500183 for _, t := range moduleTypes {
Paul Duffin1d2d42f2021-03-06 20:08:12 +0000184 t.register(ctx)
Jingwen Chen4133ce62020-12-02 04:34:15 -0500185 }
Jingwen Chendaa54bc2020-12-14 02:58:54 -0500186 // Required for SingletonModule types, even though we are not using them.
187 for _, t := range singletons {
Paul Duffin1d2d42f2021-03-06 20:08:12 +0000188 t.register(ctx)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800189 }
Spandan Das75e139b2022-11-28 20:12:03 +0000190}
Jingwen Chen4133ce62020-12-02 04:34:15 -0500191
Spandan Das75e139b2022-11-28 20:12:03 +0000192// RegisterForBazelConversion registers an alternate shadow pipeline of
193// singletons, module types and mutators to register for converting Blueprint
194// files to semantically equivalent BUILD files.
195func (ctx *Context) RegisterForBazelConversion() {
196 registerModuleTypes(ctx)
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400197 RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators)
Jingwen Chen4133ce62020-12-02 04:34:15 -0500198}
199
Spandan Das5af0bd32022-09-28 20:43:08 +0000200// RegisterForApiBazelConversion is similar to RegisterForBazelConversion except that
201// it only generates API targets in the generated workspace
202func (ctx *Context) RegisterForApiBazelConversion() {
Spandan Das75e139b2022-11-28 20:12:03 +0000203 registerModuleTypes(ctx)
Spandan Das5af0bd32022-09-28 20:43:08 +0000204 RegisterMutatorsForApiBazelConversion(ctx, bp2buildPreArchMutators)
205}
206
Jingwen Chendaa54bc2020-12-14 02:58:54 -0500207// Register the pipeline of singletons, module types, and mutators for
208// generating build.ninja and other files for Kati, from Android.bp files.
Colin Crosscec81712017-07-13 14:43:27 -0700209func (ctx *Context) Register() {
Paul Duffin1d2d42f2021-03-06 20:08:12 +0000210 preSingletons.registerAll(ctx)
Colin Cross5a79c832017-11-07 13:35:38 -0800211
Colin Cross463a90e2015-06-17 14:20:06 -0700212 for _, t := range moduleTypes {
Paul Duffin1d2d42f2021-03-06 20:08:12 +0000213 t.register(ctx)
Colin Cross463a90e2015-06-17 14:20:06 -0700214 }
215
Paul Duffinc05b0342021-03-06 13:28:13 +0000216 mutators := collateGloballyRegisteredMutators()
217 mutators.registerAll(ctx)
Colin Cross1e676be2016-10-12 14:38:15 -0700218
Paul Duffin42d0b932021-03-06 20:24:50 +0000219 singletons := collateGloballyRegisteredSingletons()
220 singletons.registerAll(ctx)
221}
Chris Parsonsa798d962020-10-12 23:44:08 -0400222
Sasha Smundak1845f422022-12-13 14:18:58 -0800223func (ctx *Context) Config() Config {
224 return ctx.config
225}
226
227func (ctx *Context) registerSingletonMakeVarsProvider(makevars SingletonMakeVarsProvider) {
228 registerSingletonMakeVarsProvider(ctx.config, makevars)
229}
230
Paul Duffin42d0b932021-03-06 20:24:50 +0000231func collateGloballyRegisteredSingletons() sortableComponents {
232 allSingletons := append(sortableComponents(nil), singletons...)
233 allSingletons = append(allSingletons,
LaMont Jones0c10e4d2023-05-16 00:58:37 +0000234 singleton{pre: false, parallel: true, name: "bazeldeps", factory: BazelSingleton},
Colin Crossc3d87d32020-06-04 13:25:17 -0700235
Paul Duffin42d0b932021-03-06 20:24:50 +0000236 // Register phony just before makevars so it can write out its phony rules as Make rules
LaMont Jonese59c0db2023-05-15 21:50:29 +0000237 singleton{pre: false, parallel: false, name: "phony", factory: phonySingletonFactory},
Colin Cross580d2ce2019-02-09 22:59:32 -0800238
Paul Duffin42d0b932021-03-06 20:24:50 +0000239 // Register makevars after other singletons so they can export values through makevars
LaMont Jonese59c0db2023-05-15 21:50:29 +0000240 singleton{pre: false, parallel: false, name: "makevars", factory: makeVarsSingletonFunc},
Paul Duffin42d0b932021-03-06 20:24:50 +0000241
242 // Register env and ninjadeps last so that they can track all used environment variables and
243 // Ninja file dependencies stored in the config.
LaMont Jonese59c0db2023-05-15 21:50:29 +0000244 singleton{pre: false, parallel: false, name: "ninjadeps", factory: ninjaDepsSingletonFactory},
Paul Duffin42d0b932021-03-06 20:24:50 +0000245 )
246
247 return allSingletons
Colin Cross463a90e2015-06-17 14:20:06 -0700248}
Colin Cross7089c272019-01-25 22:43:35 -0800249
250func ModuleTypeFactories() map[string]ModuleFactory {
251 ret := make(map[string]ModuleFactory)
252 for _, t := range moduleTypes {
253 ret[t.name] = t.factory
254 }
255 return ret
256}
Paul Duffinf9b1da02019-12-18 19:51:55 +0000257
Colin Cross9aed5bc2020-12-28 15:15:34 -0800258func ModuleTypeFactoriesForDocs() map[string]reflect.Value {
259 return moduleTypesForDocs
260}
261
Sam Delmerico286bf262022-03-09 20:46:37 +0000262func ModuleTypeByFactory() map[reflect.Value]string {
263 return moduleTypeByFactory
264}
265
Paul Duffinf9b1da02019-12-18 19:51:55 +0000266// Interface for registering build components.
267//
268// Provided to allow registration of build components to be shared between the runtime
269// and test environments.
270type RegistrationContext interface {
271 RegisterModuleType(name string, factory ModuleFactory)
Colin Cross9aed5bc2020-12-28 15:15:34 -0800272 RegisterSingletonModuleType(name string, factory SingletonModuleFactory)
LaMont Jonese59c0db2023-05-15 21:50:29 +0000273 RegisterParallelSingletonModuleType(name string, factory SingletonModuleFactory)
Paul Duffineafc16b2021-02-24 01:43:18 +0000274 RegisterPreSingletonType(name string, factory SingletonFactory)
LaMont Jonese59c0db2023-05-15 21:50:29 +0000275 RegisterParallelSingletonType(name string, factory SingletonFactory)
Paul Duffinf9b1da02019-12-18 19:51:55 +0000276 RegisterSingletonType(name string, factory SingletonFactory)
Paul Duffina48f7582019-12-19 11:25:19 +0000277 PreArchMutators(f RegisterMutatorFunc)
Paul Duffina80ef842020-01-14 12:09:36 +0000278
279 // Register pre arch mutators that are hard coded into mutator.go.
280 //
281 // Only registers mutators for testing, is a noop on the InitRegistrationContext.
282 HardCodedPreArchMutators(f RegisterMutatorFunc)
283
Paul Duffin2ccaffd2019-12-19 15:12:58 +0000284 PreDepsMutators(f RegisterMutatorFunc)
285 PostDepsMutators(f RegisterMutatorFunc)
Martin Stjernholm710ec3a2020-01-16 15:12:04 +0000286 FinalDepsMutators(f RegisterMutatorFunc)
Paul Duffinf9b1da02019-12-18 19:51:55 +0000287}
288
289// Used to register build components from an init() method, e.g.
290//
Colin Crossd079e0b2022-08-16 10:27:33 -0700291// init() {
292// RegisterBuildComponents(android.InitRegistrationContext)
293// }
Paul Duffinf9b1da02019-12-18 19:51:55 +0000294//
Colin Crossd079e0b2022-08-16 10:27:33 -0700295// func RegisterBuildComponents(ctx android.RegistrationContext) {
296// ctx.RegisterModuleType(...)
297// ...
298// }
Paul Duffinf9b1da02019-12-18 19:51:55 +0000299//
300// Extracting the actual registration into a separate RegisterBuildComponents(ctx) function
301// allows it to be used to initialize test context, e.g.
302//
Colin Crossd079e0b2022-08-16 10:27:33 -0700303// ctx := android.NewTestContext(config)
304// RegisterBuildComponents(ctx)
Paul Duffin0a286832019-12-19 12:23:01 +0000305var InitRegistrationContext RegistrationContext = &initRegistrationContext{
Paul Duffin42da69d2021-03-22 13:41:36 +0000306 moduleTypes: make(map[string]ModuleFactory),
307 singletonTypes: make(map[string]SingletonFactory),
308 preSingletonTypes: make(map[string]SingletonFactory),
Paul Duffin0a286832019-12-19 12:23:01 +0000309}
Paul Duffinf9b1da02019-12-18 19:51:55 +0000310
311// Make sure the TestContext implements RegistrationContext.
312var _ RegistrationContext = (*TestContext)(nil)
313
Paul Duffin0a286832019-12-19 12:23:01 +0000314type initRegistrationContext struct {
Colin Cross9aed5bc2020-12-28 15:15:34 -0800315 moduleTypes map[string]ModuleFactory
316 singletonTypes map[string]SingletonFactory
Paul Duffineafc16b2021-02-24 01:43:18 +0000317 preSingletonTypes map[string]SingletonFactory
Colin Cross9aed5bc2020-12-28 15:15:34 -0800318 moduleTypesForDocs map[string]reflect.Value
Paul Duffin0a286832019-12-19 12:23:01 +0000319}
Paul Duffinf9b1da02019-12-18 19:51:55 +0000320
Paul Duffin0a286832019-12-19 12:23:01 +0000321func (ctx *initRegistrationContext) RegisterModuleType(name string, factory ModuleFactory) {
322 if _, present := ctx.moduleTypes[name]; present {
323 panic(fmt.Sprintf("module type %q is already registered", name))
324 }
325 ctx.moduleTypes[name] = factory
Paul Duffinf9b1da02019-12-18 19:51:55 +0000326 RegisterModuleType(name, factory)
Colin Cross9aed5bc2020-12-28 15:15:34 -0800327 RegisterModuleTypeForDocs(name, reflect.ValueOf(factory))
328}
329
330func (ctx *initRegistrationContext) RegisterSingletonModuleType(name string, factory SingletonModuleFactory) {
LaMont Jonese59c0db2023-05-15 21:50:29 +0000331 ctx.registerSingletonModuleType(name, factory, false)
332}
333func (ctx *initRegistrationContext) RegisterParallelSingletonModuleType(name string, factory SingletonModuleFactory) {
334 ctx.registerSingletonModuleType(name, factory, true)
335}
336
337func (ctx *initRegistrationContext) registerSingletonModuleType(name string, factory SingletonModuleFactory, parallel bool) {
Colin Cross9aed5bc2020-12-28 15:15:34 -0800338 s, m := SingletonModuleFactoryAdaptor(name, factory)
LaMont Jonese59c0db2023-05-15 21:50:29 +0000339 ctx.registerSingletonType(name, s, parallel)
Colin Cross9aed5bc2020-12-28 15:15:34 -0800340 ctx.RegisterModuleType(name, m)
341 // Overwrite moduleTypesForDocs with the original factory instead of the lambda returned by
342 // SingletonModuleFactoryAdaptor so that docs can find the module type documentation on the
343 // factory method.
344 RegisterModuleTypeForDocs(name, reflect.ValueOf(factory))
Paul Duffinf9b1da02019-12-18 19:51:55 +0000345}
346
LaMont Jonese59c0db2023-05-15 21:50:29 +0000347func (ctx *initRegistrationContext) registerSingletonType(name string, factory SingletonFactory, parallel bool) {
Paul Duffin0a286832019-12-19 12:23:01 +0000348 if _, present := ctx.singletonTypes[name]; present {
349 panic(fmt.Sprintf("singleton type %q is already registered", name))
350 }
351 ctx.singletonTypes[name] = factory
LaMont Jonese59c0db2023-05-15 21:50:29 +0000352 registerSingletonType(name, factory, parallel)
353}
354
355func (ctx *initRegistrationContext) RegisterSingletonType(name string, factory SingletonFactory) {
356 ctx.registerSingletonType(name, factory, false)
357}
358
359func (ctx *initRegistrationContext) RegisterParallelSingletonType(name string, factory SingletonFactory) {
360 ctx.registerSingletonType(name, factory, true)
Paul Duffinf9b1da02019-12-18 19:51:55 +0000361}
Paul Duffina48f7582019-12-19 11:25:19 +0000362
Paul Duffineafc16b2021-02-24 01:43:18 +0000363func (ctx *initRegistrationContext) RegisterPreSingletonType(name string, factory SingletonFactory) {
364 if _, present := ctx.preSingletonTypes[name]; present {
365 panic(fmt.Sprintf("pre singleton type %q is already registered", name))
366 }
367 ctx.preSingletonTypes[name] = factory
368 RegisterPreSingletonType(name, factory)
369}
370
Paul Duffin0a286832019-12-19 12:23:01 +0000371func (ctx *initRegistrationContext) PreArchMutators(f RegisterMutatorFunc) {
Paul Duffina48f7582019-12-19 11:25:19 +0000372 PreArchMutators(f)
373}
Paul Duffin2ccaffd2019-12-19 15:12:58 +0000374
Sasha Smundak1845f422022-12-13 14:18:58 -0800375func (ctx *initRegistrationContext) HardCodedPreArchMutators(_ RegisterMutatorFunc) {
Paul Duffina80ef842020-01-14 12:09:36 +0000376 // Nothing to do as the mutators are hard code in preArch in mutator.go
377}
378
Paul Duffin2ccaffd2019-12-19 15:12:58 +0000379func (ctx *initRegistrationContext) PreDepsMutators(f RegisterMutatorFunc) {
380 PreDepsMutators(f)
381}
382
383func (ctx *initRegistrationContext) PostDepsMutators(f RegisterMutatorFunc) {
384 PostDepsMutators(f)
385}
Martin Stjernholm710ec3a2020-01-16 15:12:04 +0000386
387func (ctx *initRegistrationContext) FinalDepsMutators(f RegisterMutatorFunc) {
388 FinalDepsMutators(f)
389}