Prettify soong ninja build descriptions

Descriptions currently look like:
[  0% 4/29328] cc out-soong/.intermediates/external/clang/lib/Sema/libclangSema/android_arm_armv7-a-neon_denver_static_core/obj/external/clang/lib/Sema/SemaCodeComplete.o

This is not very helpful - most of the characters are used to show the
output path, which contains useful information like target architecture,
but also contains most of the path to the source files twice, and less
useful information like the exact variant name used by soong.
Make the descriptions look like:
[  0% 3/29329] //external/clang/lib/Sema:libclangSema clang++ SemaTemplateInstantiate.cpp

This is //path/to/module:modulename tool relative/path/to/source/file

Test: builds, looks pretty
Change-Id: I3087aa7d4eb1860ef6239d77407b8b35445616d7
diff --git a/android/api_levels.go b/android/api_levels.go
index c77ced1..70b251b 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -16,6 +16,7 @@
 
 import (
 	"encoding/json"
+	"path/filepath"
 
 	"github.com/google/blueprint"
 )
@@ -39,8 +40,9 @@
 	}
 
 	ctx.Build(pctx, blueprint.BuildParams{
-		Rule:    WriteFile,
-		Outputs: []string{file},
+		Rule:        WriteFile,
+		Description: "generate " + filepath.Base(file),
+		Outputs:     []string{file},
 		Args: map[string]string{
 			"content": string(jsonStr[:]),
 		},
diff --git a/android/arch.go b/android/arch.go
index 39477ad..51fc444 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -224,6 +224,21 @@
 	HostCross
 )
 
+func (class OsClass) String() string {
+	switch class {
+	case Generic:
+		return "generic"
+	case Device:
+		return "device"
+	case Host:
+		return "host"
+	case HostCross:
+		return "host cross"
+	default:
+		panic(fmt.Errorf("unknown class %d", class))
+	}
+}
+
 func (os OsType) String() string {
 	return os.Name
 }
diff --git a/android/module.go b/android/module.go
index 90d61e2..8f8f34b 100644
--- a/android/module.go
+++ b/android/module.go
@@ -36,6 +36,7 @@
 	Rule            blueprint.Rule
 	Deps            blueprint.Deps
 	Depfile         WritablePath
+	Description     string
 	Output          WritablePath
 	Outputs         WritablePaths
 	ImplicitOutput  WritablePath
@@ -480,6 +481,23 @@
 		missingDeps:            ctx.GetMissingDependencies(),
 	}
 
+	desc := "//" + ctx.ModuleDir() + ":" + ctx.ModuleName() + " "
+	var suffix []string
+	if androidCtx.Os().Class != Device && androidCtx.Os().Class != Generic {
+		suffix = append(suffix, androidCtx.Os().String())
+	}
+	if !androidCtx.PrimaryArch() {
+		suffix = append(suffix, androidCtx.Arch().ArchType.String())
+	}
+
+	ctx.Variable(pctx, "moduleDesc", desc)
+
+	s := ""
+	if len(suffix) > 0 {
+		s = " [" + strings.Join(suffix, " ") + "]"
+	}
+	ctx.Variable(pctx, "moduleDescSuffix", s)
+
 	if a.Enabled() {
 		a.module.GenerateAndroidBuildActions(androidCtx)
 		if ctx.Failed() {
@@ -516,11 +534,12 @@
 	module          Module
 }
 
-func (a *androidModuleContext) ninjaError(outputs []string, err error) {
+func (a *androidModuleContext) ninjaError(desc string, outputs []string, err error) {
 	a.ModuleContext.Build(pctx, blueprint.BuildParams{
-		Rule:     ErrorRule,
-		Outputs:  outputs,
-		Optional: true,
+		Rule:        ErrorRule,
+		Description: desc,
+		Outputs:     outputs,
+		Optional:    true,
 		Args: map[string]string{
 			"error": err.Error(),
 		},
@@ -530,8 +549,9 @@
 
 func (a *androidModuleContext) Build(pctx blueprint.PackageContext, params blueprint.BuildParams) {
 	if a.missingDeps != nil {
-		a.ninjaError(params.Outputs, fmt.Errorf("module %s missing dependencies: %s\n",
-			a.ModuleName(), strings.Join(a.missingDeps, ", ")))
+		a.ninjaError(params.Description, params.Outputs,
+			fmt.Errorf("module %s missing dependencies: %s\n",
+				a.ModuleName(), strings.Join(a.missingDeps, ", ")))
 		return
 	}
 
@@ -552,6 +572,10 @@
 		Optional:        !params.Default,
 	}
 
+	if params.Description != "" {
+		bparams.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
+	}
+
 	if params.Depfile != nil {
 		bparams.Depfile = params.Depfile.String()
 	}
@@ -569,8 +593,9 @@
 	}
 
 	if a.missingDeps != nil {
-		a.ninjaError(bparams.Outputs, fmt.Errorf("module %s missing dependencies: %s\n",
-			a.ModuleName(), strings.Join(a.missingDeps, ", ")))
+		a.ninjaError(bparams.Description, bparams.Outputs,
+			fmt.Errorf("module %s missing dependencies: %s\n",
+				a.ModuleName(), strings.Join(a.missingDeps, ", ")))
 		return
 	}
 
@@ -624,6 +649,9 @@
 }
 
 func (a *androidBaseContextImpl) PrimaryArch() bool {
+	if len(a.config.Targets[a.target.Os.Class]) <= 1 {
+		return true
+	}
 	return a.target.Arch.ArchType == a.config.Targets[a.target.Os.Class][0].Arch.ArchType
 }
 
@@ -686,12 +714,13 @@
 		}
 
 		a.ModuleBuild(pctx, ModuleBuildParams{
-			Rule:      Cp,
-			Output:    fullInstallPath,
-			Input:     srcPath,
-			Implicits: implicitDeps,
-			OrderOnly: orderOnlyDeps,
-			Default:   !a.AConfig().EmbeddedInMake(),
+			Rule:        Cp,
+			Description: "install " + fullInstallPath.Base(),
+			Output:      fullInstallPath,
+			Input:       srcPath,
+			Implicits:   implicitDeps,
+			OrderOnly:   orderOnlyDeps,
+			Default:     !a.AConfig().EmbeddedInMake(),
 		})
 
 		a.installFiles = append(a.installFiles, fullInstallPath)
@@ -711,10 +740,11 @@
 	if !a.skipInstall(fullInstallPath) {
 
 		a.ModuleBuild(pctx, ModuleBuildParams{
-			Rule:      Symlink,
-			Output:    fullInstallPath,
-			OrderOnly: Paths{srcPath},
-			Default:   !a.AConfig().EmbeddedInMake(),
+			Rule:        Symlink,
+			Description: "install symlink " + fullInstallPath.Base(),
+			Output:      fullInstallPath,
+			OrderOnly:   Paths{srcPath},
+			Default:     !a.AConfig().EmbeddedInMake(),
 			Args: map[string]string{
 				"fromPath": srcPath.String(),
 			},
diff --git a/cc/builder.go b/cc/builder.go
index 8a0c7f4..a4fda5b 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -45,7 +45,6 @@
 			Deps:        blueprint.DepsGCC,
 			Command:     "$relPwd ${config.CcWrapper}$ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in",
 			CommandDeps: []string{"$ccCmd"},
-			Description: "cc $out",
 		},
 		"ccCmd", "cFlags")
 
@@ -54,7 +53,6 @@
 			Command: "$ldCmd ${crtBegin} @${out}.rsp " +
 				"${libFlags} ${crtEnd} -o ${out} ${ldFlags}",
 			CommandDeps:    []string{"$ldCmd"},
-			Description:    "ld $out",
 			Rspfile:        "${out}.rsp",
 			RspfileContent: "${in}",
 		},
@@ -64,7 +62,6 @@
 		blueprint.RuleParams{
 			Command:     "$ldCmd -nostdlib -Wl,-r ${in} -o ${out} ${ldFlags}",
 			CommandDeps: []string{"$ldCmd"},
-			Description: "partialLd $out",
 		},
 		"ldCmd", "ldFlags")
 
@@ -72,7 +69,6 @@
 		blueprint.RuleParams{
 			Command:        "rm -f ${out} && $arCmd $arFlags $out @${out}.rsp",
 			CommandDeps:    []string{"$arCmd"},
-			Description:    "ar $out",
 			Rspfile:        "${out}.rsp",
 			RspfileContent: "${in}",
 		},
@@ -82,7 +78,6 @@
 		blueprint.RuleParams{
 			Command:     "rm -f ${out} && ${config.MacArPath} $arFlags $out $in",
 			CommandDeps: []string{"${config.MacArPath}"},
-			Description: "ar $out",
 		},
 		"arFlags")
 
@@ -90,7 +85,6 @@
 		blueprint.RuleParams{
 			Command:     "cp -f ${inAr} ${out}.tmp && ${config.MacArPath} $arFlags ${out}.tmp $in && mv ${out}.tmp ${out}",
 			CommandDeps: []string{"${config.MacArPath}", "${inAr}"},
-			Description: "ar $out",
 		},
 		"arFlags", "inAr")
 
@@ -98,14 +92,12 @@
 		blueprint.RuleParams{
 			Command:     "${config.MacStripPath} -u -r -o $out $in",
 			CommandDeps: []string{"${config.MacStripPath}"},
-			Description: "strip $out",
 		})
 
 	prefixSymbols = pctx.AndroidStaticRule("prefixSymbols",
 		blueprint.RuleParams{
 			Command:     "$objcopyCmd --prefix-symbols=${prefix} ${in} ${out}",
 			CommandDeps: []string{"$objcopyCmd"},
-			Description: "prefixSymbols $out",
 		},
 		"objcopyCmd", "prefix")
 
@@ -117,14 +109,12 @@
 			Deps:        blueprint.DepsGCC,
 			Command:     "CROSS_COMPILE=$crossCompile $stripPath ${args} -i ${in} -o ${out} -d ${out}.d",
 			CommandDeps: []string{"$stripPath"},
-			Description: "strip $out",
 		},
 		"args", "crossCompile")
 
 	emptyFile = pctx.AndroidStaticRule("emptyFile",
 		blueprint.RuleParams{
-			Command:     "rm -f $out && touch $out",
-			Description: "empty file $out",
+			Command: "rm -f $out && touch $out",
 		})
 
 	_ = pctx.SourcePathVariable("copyGccLibPath", "build/soong/scripts/copygcclib.sh")
@@ -135,7 +125,6 @@
 			Deps:        blueprint.DepsGCC,
 			Command:     "$copyGccLibPath $out $ccCmd $cFlags -print-file-name=${libName}",
 			CommandDeps: []string{"$copyGccLibPath", "$ccCmd"},
-			Description: "copy gcc $out",
 		},
 		"ccCmd", "cFlags", "libName")
 
@@ -155,7 +144,6 @@
 		blueprint.RuleParams{
 			Command:     "rm -f $out && ${config.ClangBin}/clang-tidy $tidyFlags $in -- $cFlags && touch $out",
 			CommandDeps: []string{"${config.ClangBin}/clang-tidy"},
-			Description: "tidy $out",
 		},
 		"cFlags", "tidyFlags")
 
@@ -165,7 +153,6 @@
 		blueprint.RuleParams{
 			Command:     "$yasmCmd $asFlags -o $out $in",
 			CommandDeps: []string{"$yasmCmd"},
-			Description: "yasm $out",
 		},
 		"asFlags")
 
@@ -175,7 +162,6 @@
 		blueprint.RuleParams{
 			Command:     "rm -f $out && $sAbiDumper -o ${out} $in $exportDirs -- $cFlags -Wno-packed -Qunused-arguments -isystem ${config.RSIncludePath}",
 			CommandDeps: []string{"$sAbiDumper"},
-			Description: "header-abi-dumper $in -o $out $exportDirs",
 		},
 		"cFlags", "exportDirs")
 
@@ -185,7 +171,6 @@
 		blueprint.RuleParams{
 			Command:        "$sAbiLinker -o ${out} $symbolFile -arch $arch -api $api $exportedHeaderFlags @${out}.rsp ",
 			CommandDeps:    []string{"$sAbiLinker"},
-			Description:    "header-abi-linker $in -o $out",
 			Rspfile:        "${out}.rsp",
 			RspfileContent: "${in}",
 		},
@@ -197,7 +182,6 @@
 		blueprint.RuleParams{
 			Command:     "$sAbiDiffer -advice-only -o ${out} -new $in -old $referenceDump",
 			CommandDeps: []string{"$sAbiDiffer"},
-			Description: "header-abi-diff -o ${out} -new $in -old $referenceDump",
 		},
 		"referenceDump")
 )
@@ -323,10 +307,11 @@
 
 		if srcFile.Ext() == ".asm" {
 			ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-				Rule:      yasm,
-				Output:    objFile,
-				Input:     srcFile,
-				OrderOnly: deps,
+				Rule:        yasm,
+				Description: "yasm " + srcFile.Rel(),
+				Output:      objFile,
+				Input:       srcFile,
+				OrderOnly:   deps,
 				Args: map[string]string{
 					"asFlags": flags.yasmFlags,
 				},
@@ -367,7 +352,11 @@
 			default:
 				panic("unrecoginzied ccCmd")
 			}
+		}
 
+		ccDesc := ccCmd
+
+		if flags.clang {
 			ccCmd = "${config.ClangBin}/" + ccCmd
 		} else {
 			ccCmd = gccCmd(flags.toolchain, ccCmd)
@@ -382,6 +371,7 @@
 
 		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 			Rule:            cc,
+			Description:     ccDesc + " " + srcFile.Rel(),
 			Output:          objFile,
 			ImplicitOutputs: implicitOutputs,
 			Input:           srcFile,
@@ -397,9 +387,10 @@
 			tidyFiles = append(tidyFiles, tidyFile)
 
 			ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-				Rule:   clangTidy,
-				Output: tidyFile,
-				Input:  srcFile,
+				Rule:        clangTidy,
+				Description: "clang-tidy " + srcFile.Rel(),
+				Output:      tidyFile,
+				Input:       srcFile,
 				// We must depend on objFile, since clang-tidy doesn't
 				// support exporting dependencies.
 				Implicit: objFile,
@@ -415,10 +406,11 @@
 			sAbiDumpFiles = append(sAbiDumpFiles, sAbiDumpFile)
 
 			ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-				Rule:     sAbiDump,
-				Output:   sAbiDumpFile,
-				Input:    srcFile,
-				Implicit: objFile,
+				Rule:        sAbiDump,
+				Description: "header-abi-dumper " + srcFile.Rel(),
+				Output:      sAbiDumpFile,
+				Input:       srcFile,
+				Implicit:    objFile,
 				Args: map[string]string{
 					"cFlags":     moduleCflags,
 					"exportDirs": flags.sAbiFlags,
@@ -452,10 +444,11 @@
 	}
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:      ar,
-		Output:    outputFile,
-		Inputs:    objFiles,
-		Implicits: deps,
+		Rule:        ar,
+		Description: "static link " + outputFile.Base(),
+		Output:      outputFile,
+		Inputs:      objFiles,
+		Implicits:   deps,
 		Args: map[string]string{
 			"arFlags": arFlags,
 			"arCmd":   arCmd,
@@ -477,24 +470,27 @@
 		dummyAr := android.PathForModuleOut(ctx, "dummy"+staticLibraryExtension)
 
 		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-			Rule:      emptyFile,
-			Output:    dummy,
-			Implicits: deps,
+			Rule:        emptyFile,
+			Description: "empty object file",
+			Output:      dummy,
+			Implicits:   deps,
 		})
 
 		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-			Rule:   darwinAr,
-			Output: dummyAr,
-			Input:  dummy,
+			Rule:        darwinAr,
+			Description: "empty static archive",
+			Output:      dummyAr,
+			Input:       dummy,
 			Args: map[string]string{
 				"arFlags": arFlags,
 			},
 		})
 
 		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-			Rule:   darwinAppendAr,
-			Output: outputFile,
-			Input:  dummy,
+			Rule:        darwinAppendAr,
+			Description: "static link " + outputFile.Base(),
+			Output:      outputFile,
+			Input:       dummy,
 			Args: map[string]string{
 				"arFlags": "d",
 				"inAr":    dummyAr.String(),
@@ -519,10 +515,11 @@
 		}
 
 		build := android.ModuleBuildParams{
-			Rule:      darwinAr,
-			Output:    out,
-			Inputs:    l,
-			Implicits: deps,
+			Rule:        darwinAr,
+			Description: "static link " + out.Base(),
+			Output:      out,
+			Inputs:      l,
+			Implicits:   deps,
 			Args: map[string]string{
 				"arFlags": arFlags,
 			},
@@ -592,10 +589,11 @@
 	}
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:      ld,
-		Output:    outputFile,
-		Inputs:    objFiles,
-		Implicits: deps,
+		Rule:        ld,
+		Description: "link " + outputFile.Base(),
+		Output:      outputFile,
+		Inputs:      objFiles,
+		Implicits:   deps,
 		Args: map[string]string{
 			"ldCmd":    ldCmd,
 			"crtBegin": crtBegin.String(),
@@ -618,10 +616,11 @@
 		linkedDumpDep = symbolFile.Path()
 	}
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:     sAbiLink,
-		Output:   outputFile,
-		Inputs:   sAbiDumps,
-		Implicit: linkedDumpDep,
+		Rule:        sAbiLink,
+		Description: "header-abi-linker " + outputFile.Base(),
+		Output:      outputFile,
+		Inputs:      sAbiDumps,
+		Implicit:    linkedDumpDep,
 		Args: map[string]string{
 			"symbolFile": symbolFileStr,
 			"arch":       ctx.Arch().ArchType.Name,
@@ -636,10 +635,11 @@
 	baseName string) android.OptionalPath {
 	outputFile := android.PathForModuleOut(ctx, baseName+".abidiff")
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:     sAbiDiff,
-		Output:   outputFile,
-		Input:    inputDump,
-		Implicit: referenceDump,
+		Rule:        sAbiDiff,
+		Description: "header-abi-diff " + outputFile.Base(),
+		Output:      outputFile,
+		Input:       inputDump,
+		Implicit:    referenceDump,
 		Args: map[string]string{
 			"referenceDump": referenceDump.String(),
 		},
@@ -654,9 +654,10 @@
 	crossCompile := gccCmd(flags.toolchain, "")
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   toc,
-		Output: outputFile,
-		Input:  inputFile,
+		Rule:        toc,
+		Description: "generate toc " + inputFile.Base(),
+		Output:      outputFile,
+		Input:       inputFile,
 		Args: map[string]string{
 			"crossCompile": crossCompile,
 		},
@@ -675,9 +676,10 @@
 	}
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   partialLd,
-		Output: outputFile,
-		Inputs: objFiles,
+		Rule:        partialLd,
+		Description: "link " + outputFile.Base(),
+		Output:      outputFile,
+		Inputs:      objFiles,
 		Args: map[string]string{
 			"ldCmd":   ldCmd,
 			"ldFlags": flags.ldFlags,
@@ -692,9 +694,10 @@
 	objcopyCmd := gccCmd(flags.toolchain, "objcopy")
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   prefixSymbols,
-		Output: outputFile,
-		Input:  inputFile,
+		Rule:        prefixSymbols,
+		Description: "prefix symbols " + outputFile.Base(),
+		Output:      outputFile,
+		Input:       inputFile,
 		Args: map[string]string{
 			"objcopyCmd": objcopyCmd,
 			"prefix":     prefix,
@@ -718,9 +721,10 @@
 	}
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   strip,
-		Output: outputFile,
-		Input:  inputFile,
+		Rule:        strip,
+		Description: "strip " + outputFile.Base(),
+		Output:      outputFile,
+		Input:       inputFile,
 		Args: map[string]string{
 			"crossCompile": crossCompile,
 			"args":         args,
@@ -732,9 +736,10 @@
 	outputFile android.WritablePath) {
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   darwinStrip,
-		Output: outputFile,
-		Input:  inputFile,
+		Rule:        darwinStrip,
+		Description: "strip " + outputFile.Base(),
+		Output:      outputFile,
+		Input:       inputFile,
 	})
 }
 
@@ -756,8 +761,9 @@
 	flags builderFlags, outputFile android.WritablePath) {
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   copyGccLib,
-		Output: outputFile,
+		Rule:        copyGccLib,
+		Description: "copy gcc library " + libName,
+		Output:      outputFile,
 		Args: map[string]string{
 			"ccCmd":   gccCmd(flags.toolchain, "gcc"),
 			"cFlags":  flags.globalFlags,
diff --git a/cc/gen.go b/cc/gen.go
index 353c43d..7a22abd 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -37,7 +37,6 @@
 		blueprint.RuleParams{
 			Command:     "BISON_PKGDATADIR=$yaccDataDir $yaccCmd -d $yaccFlags --defines=$hFile -o $out $in",
 			CommandDeps: []string{"$yaccCmd"},
-			Description: "yacc $out",
 		},
 		"yaccFlags", "hFile")
 
@@ -45,7 +44,6 @@
 		blueprint.RuleParams{
 			Command:     "$lexCmd -o$out $in",
 			CommandDeps: []string{"$lexCmd"},
-			Description: "lex $out",
 		})
 
 	aidl = pctx.AndroidStaticRule("aidl",
@@ -54,7 +52,6 @@
 			CommandDeps: []string{"$aidlCmd"},
 			Depfile:     "${out}.d",
 			Deps:        blueprint.DepsGCC,
-			Description: "aidl $out",
 		},
 		"aidlFlags", "outDir")
 )
@@ -64,6 +61,7 @@
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 		Rule:           yacc,
+		Description:    "yacc " + yaccFile.Rel(),
 		Output:         outFile,
 		ImplicitOutput: headerFile,
 		Input:          yaccFile,
@@ -79,9 +77,10 @@
 func genAidl(ctx android.ModuleContext, aidlFile android.Path, outFile android.ModuleGenPath, aidlFlags string) android.Paths {
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   aidl,
-		Output: outFile,
-		Input:  aidlFile,
+		Rule:        aidl,
+		Description: "aidl " + aidlFile.Rel(),
+		Output:      outFile,
+		Input:       aidlFile,
 		Args: map[string]string{
 			"aidlFlags": aidlFlags,
 			"outDir":    android.PathForModuleGen(ctx, "aidl").String(),
@@ -94,9 +93,10 @@
 
 func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath) {
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   lex,
-		Output: outFile,
-		Input:  lexFile,
+		Rule:        lex,
+		Description: "lex " + lexFile.Rel(),
+		Output:      outFile,
+		Input:       lexFile,
 	})
 }
 
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index deb735a..516f6e2 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -31,7 +31,6 @@
 			// let us have only implicit outputs.
 			Command:     "$versionerCmd -o $outDir $srcDir $depsPath && touch $out",
 			CommandDeps: []string{"$versionerCmd"},
-			Description: "versioner preprocess $in",
 		},
 		"depsPath", "srcDir", "outDir")
 )
@@ -238,6 +237,7 @@
 	timestampFile := android.PathForModuleOut(ctx, "versioner.timestamp")
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 		Rule:            preprocessBionicHeaders,
+		Description:     "versioner preprocess " + srcDir.Rel(),
 		Output:          timestampFile,
 		Implicits:       append(srcFiles, depsGlob...),
 		ImplicitOutputs: installPaths,
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 1bd63a9..ba3ec7d 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -32,7 +32,6 @@
 		blueprint.RuleParams{
 			Command: "$toolPath --arch $arch --api $apiLevel --api-map " +
 				"$apiMap $vndk $in $out",
-			Description: "genStubSrc $out",
 			CommandDeps: []string{"$toolPath"},
 		}, "arch", "apiLevel", "apiMap", "vndk")
 
@@ -251,10 +250,11 @@
 	symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
 	apiLevelsJson := android.GetApiLevelsJson(ctx)
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:      genStubSrc,
-		Outputs:   []android.WritablePath{stubSrcPath, versionScriptPath},
-		Input:     symbolFilePath,
-		Implicits: []android.Path{apiLevelsJson},
+		Rule:        genStubSrc,
+		Description: "generate stubs " + symbolFilePath.Rel(),
+		Outputs:     []android.WritablePath{stubSrcPath, versionScriptPath},
+		Input:       symbolFilePath,
+		Implicits:   []android.Path{apiLevelsJson},
 		Args: map[string]string{
 			"arch":     arch,
 			"apiLevel": apiLevel,
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 2e4e395..5b4cfbe 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -113,10 +113,11 @@
 
 	combinedLicense := getNdkInstallBase(ctx).Join(ctx, "NOTICE")
 	ctx.Build(pctx, blueprint.BuildParams{
-		Rule:     android.Cat,
-		Outputs:  []string{combinedLicense.String()},
-		Inputs:   licensePaths,
-		Optional: true,
+		Rule:        android.Cat,
+		Description: "combine licenses",
+		Outputs:     []string{combinedLicense.String()},
+		Inputs:      licensePaths,
+		Optional:    true,
 	})
 
 	depPaths := append(installPaths, combinedLicense.String())
diff --git a/cc/proto.go b/cc/proto.go
index 10d3c62..6c1789a 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -30,7 +30,6 @@
 		blueprint.RuleParams{
 			Command:     "$protocCmd --cpp_out=$outDir $protoFlags $in",
 			CommandDeps: []string{"$protocCmd"},
-			Description: "protoc $out",
 		}, "protoFlags", "outDir")
 )
 
@@ -48,9 +47,10 @@
 	outFile := android.GenPathWithExt(ctx, "proto", protoFile, "pb.cc")
 	headerFile := android.GenPathWithExt(ctx, "proto", protoFile, "pb.h")
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:    proto,
-		Outputs: android.WritablePaths{outFile, headerFile},
-		Input:   protoFile,
+		Rule:        proto,
+		Description: "protoc " + protoFile.Rel(),
+		Outputs:     android.WritablePaths{outFile, headerFile},
+		Input:       protoFile,
 		Args: map[string]string{
 			"outDir":     protoDir(ctx).String(),
 			"protoFlags": protoFlags,
diff --git a/cc/relocation_packer.go b/cc/relocation_packer.go
index c509f31..c9f82ba 100644
--- a/cc/relocation_packer.go
+++ b/cc/relocation_packer.go
@@ -30,7 +30,6 @@
 	blueprint.RuleParams{
 		Command:     "rm -f $out && cp $in $out && $relocationPackerCmd $out",
 		CommandDeps: []string{"$relocationPackerCmd"},
-		Description: "pack relocations $out",
 	})
 
 type RelocationPackerProperties struct {
@@ -77,8 +76,9 @@
 
 func (p *relocationPacker) pack(ctx ModuleContext, in, out android.ModuleOutPath, flags builderFlags) {
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   relocationPackerRule,
-		Output: out,
-		Input:  in,
+		Rule:        relocationPackerRule,
+		Description: "pack relocations",
+		Output:      out,
+		Input:       in,
 	})
 }
diff --git a/cc/rs.go b/cc/rs.go
index a001f89..976107e 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -39,7 +39,6 @@
 			CommandDeps: []string{"$rsCmd"},
 			Depfile:     "${out}.d",
 			Deps:        blueprint.DepsGCC,
-			Description: "rsCpp $out",
 		},
 		"depFiles", "outDir", "rsFlags", "stampFile")
 )
@@ -67,6 +66,7 @@
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 		Rule:            rsCpp,
+		Description:     "llvm-rs-cc",
 		Output:          stampFile,
 		ImplicitOutputs: cppFiles,
 		Inputs:          rsFiles,
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 6807761..2ff018f 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -218,11 +218,17 @@
 }
 
 func (g *generator) generateSourceFile(ctx android.ModuleContext, task generateTask) {
+	desc := "generate"
+	if len(task.out) == 1 {
+		desc += " " + task.out[0].Base()
+	}
+
 	params := android.ModuleBuildParams{
-		Rule:      g.rule,
-		Outputs:   task.out,
-		Inputs:    task.in,
-		Implicits: g.deps,
+		Rule:        g.rule,
+		Description: "generate",
+		Outputs:     task.out,
+		Inputs:      task.in,
+		Implicits:   g.deps,
 	}
 	if g.properties.Depfile {
 		depfile := android.GenPathWithExt(ctx, "", task.out[0], task.out[0].Ext()+".d")
diff --git a/java/app_builder.go b/java/app_builder.go
index bbd3dac..55fded5 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -34,7 +34,6 @@
 				`-J $javaDir || ( rm -rf "$javaDir/*"; exit 41 ) && ` +
 				`find $javaDir -name "*.java" > $javaFileList`,
 			CommandDeps: []string{"$aaptCmd"},
-			Description: "aapt create R.java $out",
 		},
 		"aaptFlags", "publicResourcesFile", "proguardOptionsFile", "javaDir", "javaFileList")
 
@@ -42,7 +41,6 @@
 		blueprint.RuleParams{
 			Command:     `rm -f $out && $aaptCmd package $aaptFlags -F $out`,
 			CommandDeps: []string{"$aaptCmd"},
-			Description: "aapt export package $out",
 		},
 		"aaptFlags", "publicResourcesFile", "proguardOptionsFile", "javaDir", "javaFileList")
 
@@ -51,7 +49,6 @@
 			// TODO: add-jni-shared-libs-to-package
 			Command:     `cp -f $in $out.tmp && $aaptCmd package -u $aaptFlags -F $out.tmp && mv $out.tmp $out`,
 			CommandDeps: []string{"$aaptCmd"},
-			Description: "aapt package $out",
 		},
 		"aaptFlags")
 
@@ -59,7 +56,6 @@
 		blueprint.RuleParams{
 			Command:     `java -jar $signapkCmd $certificates $in $out`,
 			CommandDeps: []string{"$signapkCmd"},
-			Description: "signapk $out",
 		},
 		"certificates")
 
@@ -68,7 +64,7 @@
 			Command: "java -classpath $androidManifestMergerCmd com.android.manifmerger.Main merge " +
 				"--main $in --libs $libsManifests --out $out",
 			CommandDeps: []string{"$androidManifestMergerCmd"},
-			Description: "merge manifest files $out",
+			Description: "merge manifest files",
 		},
 		"libsManifests")
 )
@@ -87,9 +83,10 @@
 	proguardOptionsFile := android.PathForModuleOut(ctx, "proguard.options")
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:      aaptCreateResourceJavaFile,
-		Outputs:   android.WritablePaths{publicResourcesFile, proguardOptionsFile, javaFileList},
-		Implicits: deps,
+		Rule:        aaptCreateResourceJavaFile,
+		Description: "aapt create R.java",
+		Outputs:     android.WritablePaths{publicResourcesFile, proguardOptionsFile, javaFileList},
+		Implicits:   deps,
 		Args: map[string]string{
 			"aaptFlags":           strings.Join(flags, " "),
 			"publicResourcesFile": publicResourcesFile.String(),
@@ -106,9 +103,10 @@
 	outputFile := android.PathForModuleOut(ctx, "package-export.apk")
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:      aaptCreateAssetsPackage,
-		Output:    outputFile,
-		Implicits: deps,
+		Rule:        aaptCreateAssetsPackage,
+		Description: "aapt export package",
+		Output:      outputFile,
+		Implicits:   deps,
 		Args: map[string]string{
 			"aaptFlags": strings.Join(flags, " "),
 		},
@@ -123,9 +121,10 @@
 	resourceApk := android.PathForModuleOut(ctx, "resources.apk")
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   aaptAddResources,
-		Output: resourceApk,
-		Input:  jarFile,
+		Rule:        aaptAddResources,
+		Description: "aapt package",
+		Output:      resourceApk,
+		Input:       jarFile,
 		Args: map[string]string{
 			"aaptFlags": strings.Join(flags, " "),
 		},
@@ -139,9 +138,10 @@
 	}
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   signapk,
-		Output: outputFile,
-		Input:  resourceApk,
+		Rule:        signapk,
+		Description: "signapk",
+		Output:      outputFile,
+		Input:       resourceApk,
 		Args: map[string]string{
 			"certificates": strings.Join(certificateArgs, " "),
 		},
diff --git a/java/builder.go b/java/builder.go
index a9da0fc..895a999 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -45,7 +45,6 @@
 				`find $outDir -name "*.class" > $out`,
 			Rspfile:        "$out.rsp",
 			RspfileContent: "$in",
-			Description:    "javac $outDir",
 		},
 		"javacCmd", "javacFlags", "bootClasspath", "classpath", "outDir")
 
@@ -53,7 +52,6 @@
 		blueprint.RuleParams{
 			Command:     `$jarCmd -o $out $jarArgs`,
 			CommandDeps: []string{"$jarCmd"},
-			Description: "jar $out",
 		},
 		"jarCmd", "jarArgs")
 
@@ -63,7 +61,6 @@
 				`$dxCmd --dex --output=$outDir $dxFlags $in || ( rm -rf "$outDir"; exit 41 ) && ` +
 				`find "$outDir" -name "classes*.dex" > $out`,
 			CommandDeps: []string{"$dxCmd"},
-			Description: "dex $out",
 		},
 		"outDir", "dxFlags")
 
@@ -71,7 +68,6 @@
 		blueprint.RuleParams{
 			Command:     "java -jar $jarjarCmd process $rulesFile $in $out",
 			CommandDeps: []string{"$jarjarCmd", "$rulesFile"},
-			Description: "jarjar $out",
 		},
 		"rulesFile")
 
@@ -81,7 +77,6 @@
 				`find $outDir -name "*.class" > $classFile && ` +
 				`find $outDir -type f -a \! -name "*.class" -a \! -name "MANIFEST.MF" > $resourceFile || ` +
 				`(rm -rf $outDir; exit 42)`,
-			Description: "extract java prebuilt $outDir",
 		},
 		"outDir", "classFile", "resourceFile")
 )
@@ -122,10 +117,11 @@
 	deps = append(deps, srcFileLists...)
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:      javac,
-		Output:    classFileList,
-		Inputs:    srcFiles,
-		Implicits: deps,
+		Rule:        javac,
+		Description: "javac",
+		Output:      classFileList,
+		Inputs:      srcFiles,
+		Implicits:   deps,
 		Args: map[string]string{
 			"javacFlags":    javacFlags,
 			"bootClasspath": flags.bootClasspath,
@@ -156,9 +152,10 @@
 	}
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:      jar,
-		Output:    outputFile,
-		Implicits: deps,
+		Rule:        jar,
+		Description: "jar",
+		Output:      outputFile,
+		Implicits:   deps,
 		Args: map[string]string{
 			"jarArgs": strings.Join(jarArgs, " "),
 		},
@@ -174,9 +171,10 @@
 	outputFile := android.PathForModuleOut(ctx, "dex.filelist")
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   dx,
-		Output: outputFile,
-		Input:  classesJar,
+		Rule:        dx,
+		Description: "dx",
+		Output:      outputFile,
+		Input:       classesJar,
 		Args: map[string]string{
 			"dxFlags": flags.dxFlags,
 			"outDir":  outDir.String(),
@@ -202,9 +200,10 @@
 	jarArgs = append(jarArgs, dexJarSpec.soongJarArgs())
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:      jar,
-		Output:    outputFile,
-		Implicits: deps,
+		Rule:        jar,
+		Description: "jar",
+		Output:      outputFile,
+		Implicits:   deps,
 		Args: map[string]string{
 			"jarArgs": strings.Join(jarArgs, " "),
 		},
@@ -216,10 +215,11 @@
 func TransformJarJar(ctx android.ModuleContext, classesJar android.Path, rulesFile android.Path) android.Path {
 	outputFile := android.PathForModuleOut(ctx, "classes-jarjar.jar")
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:     jarjar,
-		Output:   outputFile,
-		Input:    classesJar,
-		Implicit: rulesFile,
+		Rule:        jarjar,
+		Description: "jarjar",
+		Output:      outputFile,
+		Input:       classesJar,
+		Implicit:    rulesFile,
 		Args: map[string]string{
 			"rulesFile": rulesFile.String(),
 		},
@@ -236,9 +236,10 @@
 	resourceFileList := android.PathForModuleOut(ctx, "extracted/resources.list")
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:    extractPrebuilt,
-		Outputs: android.WritablePaths{classFileList, resourceFileList},
-		Input:   prebuilt,
+		Rule:        extractPrebuilt,
+		Description: "extract classes",
+		Outputs:     android.WritablePaths{classFileList, resourceFileList},
+		Input:       prebuilt,
 		Args: map[string]string{
 			"outDir":       classDir.String(),
 			"classFile":    classFileList.String(),
diff --git a/java/gen.go b/java/gen.go
index 0624708..e3973bf 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -37,7 +37,6 @@
 		blueprint.RuleParams{
 			Command:     "$aidlCmd -d$depFile $aidlFlags $in $out",
 			CommandDeps: []string{"$aidlCmd"},
-			Description: "aidl $out",
 		},
 		"depFile", "aidlFlags")
 
@@ -45,14 +44,12 @@
 		blueprint.RuleParams{
 			Command:     "$logtagsCmd -o $out $in $allLogtagsFile",
 			CommandDeps: []string{"$logtagsCmd"},
-			Description: "logtags $out",
 		})
 
 	mergeLogtags = pctx.AndroidStaticRule("mergeLogtags",
 		blueprint.RuleParams{
 			Command:     "$mergeLogtagsCmd -o $out $in",
 			CommandDeps: []string{"$mergeLogtagsCmd"},
-			Description: "merge logtags $out",
 		})
 )
 
@@ -61,9 +58,10 @@
 	depFile := javaFile.String() + ".d"
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   aidl,
-		Output: javaFile,
-		Input:  aidlFile,
+		Rule:        aidl,
+		Description: "aidl " + aidlFile.Rel(),
+		Output:      javaFile,
+		Input:       aidlFile,
 		Args: map[string]string{
 			"depFile":   depFile,
 			"aidlFlags": aidlFlags,
@@ -77,9 +75,10 @@
 	javaFile := android.GenPathWithExt(ctx, "logtags", logtagsFile, "java")
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:   logtags,
-		Output: javaFile,
-		Input:  logtagsFile,
+		Rule:        logtags,
+		Description: "logtags " + logtagsFile.Rel(),
+		Output:      javaFile,
+		Input:       logtagsFile,
 	})
 
 	return javaFile
@@ -122,8 +121,9 @@
 	})
 
 	ctx.Build(pctx, blueprint.BuildParams{
-		Rule:    mergeLogtags,
-		Outputs: []string{"$allLogtagsFile"},
-		Inputs:  allLogtags.Strings(),
+		Rule:        mergeLogtags,
+		Description: "merge logtags",
+		Outputs:     []string{"$allLogtagsFile"},
+		Inputs:      allLogtags.Strings(),
 	})
 }
diff --git a/python/builder.go b/python/builder.go
index 6223448..541d2bf 100644
--- a/python/builder.go
+++ b/python/builder.go
@@ -35,7 +35,6 @@
 				`$parCmd -o $parFile $parArgs && echo '#!/usr/bin/env python' | cat - $parFile > $out && ` +
 				`chmod +x $out && (rm -f $initFile; rm -f $stub; rm -f $parFile)`,
 			CommandDeps: []string{"$parCmd", "$template"},
-			Description: "build par $out",
 		},
 		"initFile", "interp", "main", "template", "stub", "parCmd", "parFile", "parArgs")
 )
@@ -78,9 +77,10 @@
 	}
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:      android.WriteFile,
-		Output:    fileList,
-		Implicits: files,
+		Rule:        android.WriteFile,
+		Description: "generate " + fileList.Rel(),
+		Output:      fileList,
+		Implicits:   files,
 		Args: map[string]string{
 			"content": strings.Join(content, "\n"),
 		},
@@ -126,9 +126,10 @@
 	}
 
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:      par,
-		Output:    binFile,
-		Implicits: implicits,
+		Rule:        par,
+		Description: "python archive",
+		Output:      binFile,
+		Implicits:   implicits,
 		Args: map[string]string{
 			"initFile": initFile,
 			// the "\" isn't being interpreted by regex parser, it's being