diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go index 8a9a5f8..64fa8e5 100644 --- a/bootstrap/bootstrap.go +++ b/bootstrap/bootstrap.go @@ -180,8 +180,10 @@ func toolDir(config interface{}) string { func pluginDeps(ctx blueprint.BottomUpMutatorContext) { if pkg, ok := ctx.Module().(*goPackage); ok { - for _, plugin := range pkg.properties.PluginFor { - ctx.AddReverseDependency(ctx.Module(), nil, plugin) + if ctx.PrimaryModule() == ctx.Module() { + for _, plugin := range pkg.properties.PluginFor { + ctx.AddReverseDependency(ctx.Module(), nil, plugin) + } } } } @@ -211,7 +213,7 @@ func isGoPluginFor(name string) func(blueprint.Module) bool { } } -func isBootstrapModule(module blueprint.Module) bool { +func IsBootstrapModule(module blueprint.Module) bool { _, isPackage := module.(*goPackage) _, isBinary := module.(*goBinary) return isPackage || isBinary @@ -268,6 +270,9 @@ func newGoPackageModuleFactory(config *Config) func() (blueprint.Module, []inter } func (g *goPackage) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string { + if ctx.Module() != ctx.PrimaryModule() { + return nil + } return g.properties.Deps } @@ -297,6 +302,16 @@ func (g *goPackage) IsPluginFor(name string) bool { } func (g *goPackage) GenerateBuildActions(ctx blueprint.ModuleContext) { + // Allow the primary builder to create multiple variants. Any variants after the first + // will copy outputs from the first. + if ctx.Module() != ctx.PrimaryModule() { + primary := ctx.PrimaryModule().(*goPackage) + g.pkgRoot = primary.pkgRoot + g.archiveFile = primary.archiveFile + g.testResultFile = primary.testResultFile + return + } + var ( name = ctx.ModuleName() hasPlugins = false @@ -386,6 +401,9 @@ func newGoBinaryModuleFactory(config *Config, tooldir bool) func() (blueprint.Mo } func (g *goBinary) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string { + if ctx.Module() != ctx.PrimaryModule() { + return nil + } return g.properties.Deps } @@ -395,6 +413,14 @@ func (g *goBinary) InstallPath() string { } func (g *goBinary) GenerateBuildActions(ctx blueprint.ModuleContext) { + // Allow the primary builder to create multiple variants. Any variants after the first + // will copy outputs from the first. + if ctx.Module() != ctx.PrimaryModule() { + primary := ctx.PrimaryModule().(*goBinary) + g.installPath = primary.installPath + return + } + var ( name = ctx.ModuleName() objDir = moduleObjDir(ctx, g.config) @@ -653,13 +679,15 @@ func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) { var blueprintTools []string ctx.VisitAllModulesIf(isBootstrapBinaryModule, func(module blueprint.Module) { - binaryModule := module.(*goBinary) + if ctx.PrimaryModule(module) == module { + binaryModule := module.(*goBinary) - if binaryModule.properties.Tool_dir { - blueprintTools = append(blueprintTools, binaryModule.InstallPath()) - } - if binaryModule.properties.PrimaryBuilder { - primaryBuilders = append(primaryBuilders, binaryModule) + if binaryModule.properties.Tool_dir { + blueprintTools = append(blueprintTools, binaryModule.InstallPath()) + } + if binaryModule.properties.PrimaryBuilder { + primaryBuilders = append(primaryBuilders, binaryModule) + } } }) diff --git a/module_ctx.go b/module_ctx.go index 28578e0..c992c0a 100644 --- a/module_ctx.go +++ b/module_ctx.go @@ -246,6 +246,24 @@ type BaseModuleContext interface { // invalidated by future mutators. WalkDeps(visit func(Module, Module) bool) + // PrimaryModule returns the first variant of the current module. Variants of a module are always visited in + // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the + // Module returned by PrimaryModule without data races. This can be used to perform singleton actions that are + // only done once for all variants of a module. + PrimaryModule() Module + + // FinalModule returns the last variant of the current module. Variants of a module are always visited in + // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all + // variants using VisitAllModuleVariants if the current module == FinalModule(). This can be used to perform + // singleton actions that are only done once for all variants of a module. + FinalModule() Module + + // VisitAllModuleVariants calls visit for each variant of the current module. Variants of a module are always + // visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read + // from all variants if the current module == FinalModule(). Otherwise, care must be taken to not access any + // data modified by the current mutator. + VisitAllModuleVariants(visit func(Module)) + // OtherModuleName returns the name of another Module. See BaseModuleContext.ModuleName for more information. // It is intended for use inside the visit functions of Visit* and WalkDeps. OtherModuleName(m Module) string @@ -309,24 +327,6 @@ type ModuleContext interface { // Build creates a new ninja build statement. Build(pctx PackageContext, params BuildParams) - // PrimaryModule returns the first variant of the current module. Variants of a module are always visited in - // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the - // Module returned by PrimaryModule without data races. This can be used to perform singleton actions that are - // only done once for all variants of a module. - PrimaryModule() Module - - // FinalModule returns the last variant of the current module. Variants of a module are always visited in - // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all - // variants using VisitAllModuleVariants if the current module == FinalModule(). This can be used to perform - // singleton actions that are only done once for all variants of a module. - FinalModule() Module - - // VisitAllModuleVariants calls visit for each variant of the current module. Variants of a module are always - // visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read - // from all variants if the current module == FinalModule(). Otherwise, care must be taken to not access any - // data modified by the current mutator. - VisitAllModuleVariants(visit func(Module)) - // GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods, // but do not exist. It can be used with Context.SetAllowMissingDependencies to allow the primary builder to // handle missing dependencies on its own instead of having Blueprint treat them as an error. @@ -642,6 +642,18 @@ func (m *baseModuleContext) WalkDeps(visit func(child, parent Module) bool) { m.visitingDep = depInfo{} } +func (m *baseModuleContext) PrimaryModule() Module { + return m.module.group.modules[0].logicModule +} + +func (m *baseModuleContext) FinalModule() Module { + return m.module.group.modules[len(m.module.group.modules)-1].logicModule +} + +func (m *baseModuleContext) VisitAllModuleVariants(visit func(Module)) { + m.context.visitAllModuleVariants(m.module, visit) +} + func (m *baseModuleContext) AddNinjaFileDeps(deps ...string) { m.ninjaFileDeps = append(m.ninjaFileDeps, deps...) } @@ -695,18 +707,6 @@ func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def) } -func (m *moduleContext) PrimaryModule() Module { - return m.module.group.modules[0].logicModule -} - -func (m *moduleContext) FinalModule() Module { - return m.module.group.modules[len(m.module.group.modules)-1].logicModule -} - -func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) { - m.context.visitAllModuleVariants(m.module, visit) -} - func (m *moduleContext) GetMissingDependencies() []string { m.handledMissingDeps = true return m.module.missingDeps