diff options
author | Joe Onorato <joeo@google.com> | 2024-02-04 00:51:59 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2024-02-04 00:51:59 +0000 |
commit | 2f019ce883501cb9cec361f9871150acc123cf55 (patch) | |
tree | b90b0d91c13b37a5c4c792a94e4629a388337f5a | |
parent | 689b3e5ce422aa6f5fe9ee6f2375ed0db0c3da85 (diff) | |
parent | 8ad2b88c8db3d7606d08563b6cc240a9cf0c3c77 (diff) | |
download | blueprint-2f019ce883501cb9cec361f9871150acc123cf55.tar.gz |
Add new soong module debug info json. am: 8ad2b88c8d
Original change: https://android-review.googlesource.com/c/platform/build/blueprint/+/2949327
Change-Id: Id900142900cc5c6b302e69e4d88770cdb5654db5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | bootstrap/command.go | 7 | ||||
-rw-r--r-- | context.go | 139 |
2 files changed, 146 insertions, 0 deletions
diff --git a/bootstrap/command.go b/bootstrap/command.go index d7dcc27..580907c 100644 --- a/bootstrap/command.go +++ b/bootstrap/command.go @@ -40,6 +40,9 @@ type Args struct { Cpuprofile string Memprofile string TraceFile string + + // Debug data json file + ModuleDebugFile string } // RegisterGoModuleTypes adds module types to build tools written in golang @@ -131,6 +134,10 @@ func RunBlueprint(args Args, stopBefore StopBefore, ctx *blueprint.Context, conf ninjaDeps = append(ninjaDeps, buildActionsDeps...) } + if args.ModuleDebugFile != "" { + ctx.GenerateModuleDebugInfo(args.ModuleDebugFile) + } + if stopBefore == StopBeforeWriteNinja { return ninjaDeps, nil } @@ -3820,6 +3820,25 @@ func (c *Context) visitAllModuleVariants(module *moduleInfo, } } +func (c *Context) visitAllModuleInfos(visit func(*moduleInfo)) { + var module *moduleInfo + + defer func() { + if r := recover(); r != nil { + panic(newPanicErrorf(r, "VisitAllModules(%s) for %s", + funcName(visit), module)) + } + }() + + for _, moduleGroup := range c.sortedModuleGroups() { + for _, moduleOrAlias := range moduleGroup.modules { + if module = moduleOrAlias.module(); module != nil { + visit(module) + } + } + } +} + func (c *Context) requireNinjaVersion(major, minor, micro int) { if major != 1 { panic("ninja version with major version != 1 not supported") @@ -4920,6 +4939,126 @@ func funcName(f interface{}) string { return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() } +// json representation of a dependency +type depJson struct { + Name string `json:"name"` + Variant string `json:"variant"` + TagType string `json:"tag_type"` +} + +// json representation of a provider +type providerJson struct { + Type string `json:"type"` + Debug string `json:"debug"` // from GetDebugString on the provider data +} + +// interface for getting debug info from various data. +// TODO: Consider having this return a json object instead +type Debuggable interface { + GetDebugString() string +} + +// Get the debug json for a single module. Returns thae data as +// flattened json text for easy concatenation by GenerateModuleDebugInfo. +func getModuleDebugJson(module *moduleInfo) []byte { + info := struct { + Name string `json:"name"` + SourceFile string `json:"source_file"` + SourceLine int `json:"source_line"` + Type string `json:"type"` + Variant string `json:"variant"` + Deps []depJson `json:"deps"` + Providers []providerJson `json:"providers"` + Debug string `json:"debug"` // from GetDebugString on the module + }{ + Name: module.logicModule.Name(), + SourceFile: module.pos.Filename, + SourceLine: module.pos.Line, + Type: module.typeName, + Variant: module.variant.name, + Deps: func() []depJson { + result := make([]depJson, len(module.directDeps)) + for i, dep := range module.directDeps { + result[i] = depJson{ + Name: dep.module.logicModule.Name(), + Variant: dep.module.variant.name, + } + t := reflect.TypeOf(dep.tag) + if t != nil { + result[i].TagType = t.PkgPath() + "." + t.Name() + } + } + return result + }(), + Providers: func() []providerJson { + result := make([]providerJson, 0, len(module.providers)) + for _, p := range module.providers { + pj := providerJson{} + include := false + + t := reflect.TypeOf(p) + if t != nil { + pj.Type = t.PkgPath() + "." + t.Name() + include = true + } + + if dbg, ok := p.(Debuggable); ok { + pj.Debug = dbg.GetDebugString() + if pj.Debug != "" { + include = true + } + } + if include { + result = append(result, pj) + } + } + return result + }(), + Debug: func() string { + if dbg, ok := module.logicModule.(Debuggable); ok { + return dbg.GetDebugString() + } else { + return "" + } + }(), + } + buf, _ := json.Marshal(info) + return buf +} + +// Generate out/soong/soong-debug-info.json Called if GENERATE_SOONG_DEBUG=true. +func (this *Context) GenerateModuleDebugInfo(filename string) { + err := os.MkdirAll(filepath.Dir(filename), 0777) + if err != nil { + // We expect this to be writable + panic(fmt.Sprintf("couldn't create directory for soong module debug file %s: %s", filepath.Dir(filename), err)) + } + + f, err := os.Create(filename) + if err != nil { + // We expect this to be writable + panic(fmt.Sprintf("couldn't create soong module debug file %s: %s", filename, err)) + } + defer f.Close() + + needComma := false + f.WriteString("{\n\"modules\": [\n") + + // TODO: Optimize this (parallel execution, etc) if it gets slow. + this.visitAllModuleInfos(func(module *moduleInfo) { + if needComma { + f.WriteString(",\n") + } else { + needComma = true + } + + moduleData := getModuleDebugJson(module) + f.Write(moduleData) + }) + + f.WriteString("\n]\n}") +} + var fileHeaderTemplate = `****************************************************************************** *** This file is generated and should not be edited *** ****************************************************************************** |