diff --git a/android/module.go b/android/module.go index f5cfe6601..e431adaf4 100644 --- a/android/module.go +++ b/android/module.go @@ -19,6 +19,7 @@ import ( "os" "path" "path/filepath" + "regexp" "strings" "text/scanner" @@ -135,6 +136,13 @@ type BaseModuleContext interface { // GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1] GetTagPath() []blueprint.DependencyTag + // GetPathString is supposed to be called in visit function passed in WalkDeps() + // and returns a multi-line string showing the modules and dependency tags + // among them along the top-down dependency path from a start module to current child module. + // skipFirst when set to true, the output doesn't include the start module, + // which is already printed when this function is used along with ModuleErrorf(). + GetPathString(skipFirst bool) string + AddMissingDependencies(missingDeps []string) Target() Target @@ -1734,6 +1742,41 @@ func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag { return b.tagPath } +// A regexp for removing boilerplate from BaseDependencyTag from the string representation of +// a dependency tag. +var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`) + +// PrettyPrintTag returns string representation of the tag, but prefers +// custom String() method if available. +func PrettyPrintTag(tag blueprint.DependencyTag) string { + // Use tag's custom String() method if available. + if stringer, ok := tag.(fmt.Stringer); ok { + return stringer.String() + } + + // Otherwise, get a default string representation of the tag's struct. + tagString := fmt.Sprintf("%#v", tag) + + // Remove the boilerplate from BaseDependencyTag as it adds no value. + tagString = tagCleaner.ReplaceAllString(tagString, "") + return tagString +} + +func (b *baseModuleContext) GetPathString(skipFirst bool) string { + sb := strings.Builder{} + tagPath := b.GetTagPath() + walkPath := b.GetWalkPath() + if !skipFirst { + sb.WriteString(walkPath[0].String()) + } + for i, m := range walkPath[1:] { + sb.WriteString("\n") + sb.WriteString(fmt.Sprintf(" via tag %s\n", PrettyPrintTag(tagPath[i]))) + sb.WriteString(fmt.Sprintf(" -> %s", m.String())) + } + return sb.String() +} + func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) { m.bp.VisitAllModuleVariants(func(module blueprint.Module) { visit(module.(Module)) diff --git a/apex/apex.go b/apex/apex.go index d196e95e9..93ceb8387 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -18,7 +18,6 @@ import ( "fmt" "path" "path/filepath" - "regexp" "sort" "strings" "sync" @@ -1809,24 +1808,6 @@ func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int { return intVer } -// A regexp for removing boilerplate from BaseDependencyTag from the string representation of -// a dependency tag. -var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`) - -func PrettyPrintTag(tag blueprint.DependencyTag) string { - // Use tag's custom String() method if available. - if stringer, ok := tag.(fmt.Stringer); ok { - return stringer.String() - } - - // Otherwise, get a default string representation of the tag's struct. - tagString := fmt.Sprintf("%#v", tag) - - // Remove the boilerplate from BaseDependencyTag as it adds no value. - tagString = tagCleaner.ReplaceAllString(tagString, "") - return tagString -} - // Ensures that the dependencies are marked as available for this APEX func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { // Let's be practical. Availability for test, host, and the VNDK apex isn't important @@ -1861,14 +1842,7 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) { return true } - message := "" - tagPath := ctx.GetTagPath() - // Skip the first module as that will be added at the start of the error message by ctx.ModuleErrorf(). - walkPath := ctx.GetWalkPath()[1:] - for i, m := range walkPath { - message = fmt.Sprintf("%s\n via tag %s\n -> %s", message, PrettyPrintTag(tagPath[i]), m.String()) - } - ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, message) + ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, ctx.GetPathString(true)) // Visit this module's dependencies to check and report any issues with their availability. return true }) @@ -2132,7 +2106,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName)) } } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { - ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", PrettyPrintTag(depTag), depName) + ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName) } } }