1package bootstrap 2 3import ( 4 "fmt" 5 "maps" 6 "path/filepath" 7 "reflect" 8 9 "github.com/google/blueprint" 10 "github.com/google/blueprint/bootstrap/bpdoc" 11 "github.com/google/blueprint/pathtools" 12) 13 14// ModuleTypeDocs returns a list of bpdoc.ModuleType objects that contain information relevant 15// to generating documentation for module types supported by the primary builder. 16func ModuleTypeDocs(ctx *blueprint.Context, factories map[string]reflect.Value) ([]*bpdoc.Package, error) { 17 // Find the module that's marked as the "primary builder", which means it's 18 // creating the binary that we'll use to generate the non-bootstrap 19 // build.ninja file. 20 var primaryBuilders []blueprint.Module 21 ctx.VisitAllModules(func(module blueprint.Module) { 22 if ctx.PrimaryModule(module) == module { 23 if _, ok := blueprint.SingletonModuleProvider(ctx, module, PrimaryBuilderProvider); ok { 24 primaryBuilders = append(primaryBuilders, module) 25 } 26 } 27 }) 28 29 var primaryBuilder blueprint.Module 30 switch len(primaryBuilders) { 31 case 0: 32 return nil, fmt.Errorf("no primary builder module present") 33 34 case 1: 35 primaryBuilder = primaryBuilders[0] 36 37 default: 38 return nil, fmt.Errorf("multiple primary builder modules present") 39 } 40 41 pkgFiles := make(map[string][]string) 42 ctx.VisitDepsDepthFirst(primaryBuilder, func(module blueprint.Module) { 43 if info, ok := blueprint.SingletonModuleProvider(ctx, module, DocsPackageProvider); ok { 44 pkgFiles[info.PkgPath] = pathtools.PrefixPaths(info.Srcs, 45 filepath.Join(ctx.SrcDir(), ctx.ModuleDir(module))) 46 } 47 }) 48 49 mergedFactories := maps.Clone(factories) 50 51 for moduleType, factory := range ctx.ModuleTypeFactories() { 52 if _, exists := mergedFactories[moduleType]; !exists { 53 mergedFactories[moduleType] = reflect.ValueOf(factory) 54 } 55 } 56 57 return bpdoc.AllPackages(pkgFiles, mergedFactories, ctx.ModuleTypePropertyStructs()) 58} 59