aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Onorato <joeo@google.com>2024-02-04 00:51:59 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2024-02-04 00:51:59 +0000
commit2f019ce883501cb9cec361f9871150acc123cf55 (patch)
treeb90b0d91c13b37a5c4c792a94e4629a388337f5a
parent689b3e5ce422aa6f5fe9ee6f2375ed0db0c3da85 (diff)
parent8ad2b88c8db3d7606d08563b6cc240a9cf0c3c77 (diff)
downloadblueprint-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.go7
-rw-r--r--context.go139
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
}
diff --git a/context.go b/context.go
index 4130700..e850647 100644
--- a/context.go
+++ b/context.go
@@ -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 ***
******************************************************************************