Parse genrule's cmd property

Instead of just passing this to ninja, use os.Expand to parse the
variable substitutions. While we're here, define a new "genDir" variable
that is the root of this module's generated directory.

Bug: 31742855
Test: Ensure invalid variables cause error
Test: Inspect commands in build.ninja
Change-Id: Iff6d0499ab57367669e73df52ab7c647358da13b
diff --git a/genrule/genrule.go b/genrule/genrule.go
index ecc5ab8..a49a5dd 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -15,6 +15,8 @@
 package genrule
 
 import (
+	"os"
+
 	"github.com/google/blueprint"
 
 	"android/soong"
@@ -52,6 +54,7 @@
 	// $in: one or more input files
 	// $out: a single output file
 	// $srcDir: the root directory of the source tree
+	// $genDir: the sandbox directory for this tool; contains $out
 	// The host bin directory will be in the path
 	Cmd string
 
@@ -109,8 +112,30 @@
 		return
 	}
 
+	g.genPath = android.PathForModuleGen(ctx, "")
+
+	cmd := os.Expand(g.properties.Cmd, func(name string) string {
+		switch name {
+		case "$":
+			return "$$"
+		case "tool":
+			return "${tool}"
+		case "in":
+			return "${in}"
+		case "out":
+			return "${out}"
+		case "srcDir":
+			return "${srcDir}"
+		case "genDir":
+			return g.genPath.String()
+		default:
+			ctx.PropertyErrorf("cmd", "unknown variable '%s'", name)
+		}
+		return ""
+	})
+
 	g.rule = ctx.Rule(pctx, "generator", blueprint.RuleParams{
-		Command: "PATH=$$PATH:$hostBin " + g.properties.Cmd,
+		Command: "PATH=$$PATH:$hostBin " + cmd,
 	}, "tool")
 
 	var tool string
@@ -134,8 +159,6 @@
 		})
 	}
 
-	g.genPath = android.PathForModuleGen(ctx, "")
-
 	for _, task := range g.tasks(ctx) {
 		g.generateSourceFile(ctx, task, tool)
 	}