diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 1f6002ee2..41c7d46ce 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -75,8 +75,7 @@ func main() { bootstrap.Main(ctx.Context, configuration, configuration.ConfigFileName, configuration.ProductVariablesFileName) if docFile != "" { - err := writeDocs(ctx, docFile) - if err != nil { + if err := writeDocs(ctx, docFile); err != nil { fmt.Fprintf(os.Stderr, "%s", err) os.Exit(1) } diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go index 8f86b3321..74c854a39 100644 --- a/cmd/soong_build/writedocs.go +++ b/cmd/soong_build/writedocs.go @@ -26,7 +26,25 @@ import ( "github.com/google/blueprint/bootstrap/bpdoc" ) -func writeDocs(ctx *android.Context, filename string) error { +type moduleTypeTemplateData struct { + Name string + Synopsis string + Properties []bpdoc.Property +} + +// The properties in this map are displayed first, according to their rank. +// TODO(jungjw): consider providing module type-dependent ranking +var propertyRank = map[string]int{ + "name": 0, + "src": 1, + "srcs": 2, + "defautls": 3, + "host_supported": 4, + "device_supported": 5, +} + +// For each module type, extract its documentation and convert it to the template data. +func moduleTypeDocsToTemplates(ctx *android.Context) ([]moduleTypeTemplateData, error) { moduleTypeFactories := android.ModuleTypeFactories() bpModuleTypeFactories := make(map[string]reflect.Value) for moduleType, factory := range moduleTypeFactories { @@ -35,39 +53,83 @@ func writeDocs(ctx *android.Context, filename string) error { packages, err := bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories) if err != nil { - return err + return []moduleTypeTemplateData{}, err } - - buf := &bytes.Buffer{} - var moduleTypeList []*bpdoc.ModuleType for _, pkg := range packages { moduleTypeList = append(moduleTypeList, pkg.ModuleTypes...) } - sort.Slice(moduleTypeList, func(i, j int) bool { return moduleTypeList[i].Name < moduleTypeList[j].Name }) - unique := 0 + result := make([]moduleTypeTemplateData, 0) + // Combine properties from all PropertyStruct's and reorder them -- first the ones + // with rank, then the rest of the properties in alphabetic order. + for _, m := range moduleTypeList { + item := moduleTypeTemplateData{ + Name: m.Name, + Synopsis: m.Text, + Properties: make([]bpdoc.Property, 0), + } + props := make([]bpdoc.Property, 0) + for _, propStruct := range m.PropertyStructs { + props = append(props, propStruct.Properties...) + } + sort.Slice(props, func(i, j int) bool { + if rankI, ok := propertyRank[props[i].Name]; ok { + if rankJ, ok := propertyRank[props[j].Name]; ok { + return rankI < rankJ + } else { + return true + } + } + if _, ok := propertyRank[props[j].Name]; ok { + return false + } + return props[i].Name < props[j].Name + }) + // Eliminate top-level duplicates. TODO(jungjw): improve bpdoc to handle this. + previousPropertyName := "" + for _, prop := range props { + if prop.Name == previousPropertyName { + oldProp := &item.Properties[len(item.Properties)-1].Properties + bpdoc.CollapseDuplicateProperties(oldProp, &prop.Properties) + } else { + item.Properties = append(item.Properties, prop) + } + previousPropertyName = prop.Name + } + result = append(result, item) + } + sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name }) + return result, err +} + +func writeDocs(ctx *android.Context, filename string) error { + buf := &bytes.Buffer{} + + // We need a module name getter/setter function because I couldn't + // find a way to keep it in a variable defined within the template. + currentModuleName := "" + data, err := moduleTypeDocsToTemplates(ctx) + if err != nil { + return err + } tmpl, err := template.New("file").Funcs(map[string]interface{}{ - "unique": func() int { - unique++ - return unique - }}).Parse(fileTemplate) - if err != nil { - return err + "setModule": func(moduleName string) string { + currentModuleName = moduleName + return "" + }, + "getModule": func() string { + return currentModuleName + }, + }).Parse(fileTemplate) + if err == nil { + err = tmpl.Execute(buf, data) } - - err = tmpl.Execute(buf, moduleTypeList) - if err != nil { - return err + if err == nil { + err = ioutil.WriteFile(filename, buf.Bytes(), 0666) } - - err = ioutil.WriteFile(filename, buf.Bytes(), 0666) - if err != nil { - return err - } - - return nil + return err } const ( @@ -75,70 +137,112 @@ const ( Build Docs - - - + + -

Build Docs

-
- {{range .}} - {{ $collapseIndex := unique }} -
- -
-
-
-

{{.Text}}

- {{range .PropertyStructs}} -

{{.Text}}

- {{template "properties" .Properties}} - {{end}} -
-
- {{end}} -
- - +{{- /* Fixed sidebar with module types */ -}} + +{{/* Main panel with H1 section per module type */}} +
+

Soong Modules Reference

+The latest versions of Android use the Soong build system, which greatly simplifies build +configuration over the previous Make-based system. This site contains the generated reference +files for the Soong build system. +

+See the Android Build System +description for an overview of Soong and examples for its use. -{{define "properties"}} -

- {{range .}} - {{$collapseIndex := unique}} - {{if .Properties}} - -
-
-

{{.Text}}

- {{range .OtherTexts}}

{{.}}

{{end}} - {{template "properties" .Properties}} -
-
- {{else}} -
-

{{.Name}}{{range .OtherNames}}, {{.}}{{end}}

-

{{.Text}}

- {{range .OtherTexts}}

{{.}}

{{end}} -

Type: {{.Type}}

- {{if .Default}}

Default: {{.Default}}

{{end}} -
- {{end}} - {{end}} +{{range $imodule, $moduleType := .}} + {{setModule $moduleType.Name}} +

+

{{$moduleType.Name}}

+ {{if $moduleType.Synopsis }}{{$moduleType.Synopsis}}{{else}}Missing synopsis{{end}} + {{- /* Comma-separated list of module attributes' links module attributes */ -}} + -{{end}} + {{- /* Property description */ -}} + {{- template "properties" $moduleType.Properties -}} +{{- end -}} + +{{define "properties" -}} + {{range .}} + {{if .Properties -}} +
+ {{.Name}} + {{- range .OtherNames -}}, {{.}}{{- end -}} +
+
+ {{- .Text}} {{range .OtherTexts}}{{.}}{{end}} + {{template "properties" .Properties -}} +
+ {{- else -}} +
+  {{.Name}} {{range .OtherNames}}, {{.}}{{end -}} + {{- if .Text -}}{{.Text}}{{- end -}} + {{- with .OtherTexts -}}{{.}}{{- end -}}{{.Type}} + {{- if .Default -}}Default: {{.Default}}{{- end -}} +
+ {{- end}} + {{- end -}} +{{- end -}} + +
+ + ` )