summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Colin Cross <ccross@android.com> 2016-11-04 15:32:58 -0700
committer Colin Cross <ccross@android.com> 2016-11-07 10:53:49 -0800
commit6f080dff818c7a4e41d61520660c4a1298e48cb8 (patch)
tree5f25e82601d559e5e94e805e4948981b86b8d152
parent6bde0948d2b0d1826098a0046da5a8a2ce017fb6 (diff)
Support genrules with multiple tools
To allow genrules with more than one tool, rename the tool property to tools and make it an array, replace $tool with $(location <label>), and use $() for other variables for consistency. Also remove the host bin directory from the genrule path, and the $srcDir variable, using either of them would have caused dependency issues. Bug: 31948427 Test: compare build.ninja Change-Id: Icf6d3bce2bea00fec1363fd65c0bdf96d09281bf (cherry picked from commit de6bd86d240b98b7ea7ff6a0454a13edc639a163)
-rw-r--r--android/expand.go4
-rw-r--r--genrule/genrule.go128
2 files changed, 75 insertions, 57 deletions
diff --git a/android/expand.go b/android/expand.go
index dafb2b6e8..101318108 100644
--- a/android/expand.go
+++ b/android/expand.go
@@ -59,9 +59,7 @@ func getMapping(s string, mapping func(string) (string, error)) (string, int, er
case '$':
return s[0:1], 1, nil
default:
- i := strings.IndexFunc(s, func(c rune) bool {
- return !(unicode.IsLetter(c) || unicode.IsNumber(c) || c == '_' || c == '.' || c == '-')
- })
+ i := strings.IndexFunc(s, unicode.IsSpace)
if i == 0 {
return "", 0, fmt.Errorf("unexpected character '%c' after '$'", s[0])
} else if i == -1 {
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 5ee8b0bc2..498858d28 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -15,7 +15,8 @@
package genrule
import (
- "os"
+ "fmt"
+ "strings"
"github.com/google/blueprint"
@@ -31,11 +32,6 @@ var (
pctx = android.NewPackageContext("android/soong/genrule")
)
-func init() {
- pctx.SourcePathVariable("srcDir", "")
- pctx.HostBinToolVariable("hostBin", "")
-}
-
type SourceFileGenerator interface {
GeneratedSourceFiles() android.Paths
GeneratedHeaderDir() android.Path
@@ -47,20 +43,24 @@ type HostToolProvider interface {
type generatorProperties struct {
// command to run on one or more input files. Available variables for substitution:
- // $tool: the path to the `tool` or `tool_file`
- // $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
+ // $(location): the path to the first entry in tools or tool_files
+ // $(location <label>): the path to the tool or tool_file with name <label>
+ // $(in): one or more input files
+ // $(out): a single output file
+ // $(genDir): the sandbox directory for this tool; contains $(out)
+ // $$: a literal $
+ //
+ // DO NOT directly reference paths to files in the source tree, or the
+ // command will be missing proper dependencies to re-run if the files
+ // change.
Cmd string
- // name of the module (if any) that produces the host executable. Leave empty for
+ // name of the modules (if any) that produces the host executable. Leave empty for
// prebuilts or scripts that do not need a module to build them.
- Tool string
+ Tools []string
// Local file that is used as the tool
- Tool_file string
+ Tool_files []string
}
type generator struct {
@@ -95,58 +95,36 @@ func (g *generator) GeneratedHeaderDir() android.Path {
func (g *generator) DepsMutator(ctx android.BottomUpMutatorContext) {
if g, ok := ctx.Module().(*generator); ok {
- if g.properties.Tool != "" {
+ if len(g.properties.Tools) > 0 {
ctx.AddFarVariationDependencies([]blueprint.Variation{
{"arch", ctx.AConfig().BuildOsVariant},
- }, nil, g.properties.Tool)
+ }, nil, g.properties.Tools...)
}
}
}
func (g *generator) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if g.properties.Tool != "" && g.properties.Tool_file != "" {
- ctx.ModuleErrorf("`tool` and `tool_file` may not be specified at the same time")
+ if len(g.properties.Tools) == 0 && len(g.properties.Tool_files) == 0 {
+ ctx.ModuleErrorf("at least one `tools` or `tool_files` is required")
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 ""
- })
+ tools := map[string]android.Path{}
- g.rule = ctx.Rule(pctx, "generator", blueprint.RuleParams{
- Command: "PATH=$$PATH:$hostBin " + cmd,
- }, "tool")
-
- var tool string
- if g.properties.Tool_file != "" {
- toolpath := android.PathForModuleSrc(ctx, g.properties.Tool_file)
- g.deps = append(g.deps, toolpath)
- tool = toolpath.String()
- } else if g.properties.Tool != "" {
+ if len(g.properties.Tools) > 0 {
ctx.VisitDirectDeps(func(module blueprint.Module) {
if t, ok := module.(HostToolProvider); ok {
p := t.HostToolPath()
if p.Valid() {
g.deps = append(g.deps, p.Path())
- tool = p.String()
+ tool := ctx.OtherModuleName(module)
+ if _, exists := tools[tool]; !exists {
+ tools[tool] = p.Path()
+ } else {
+ ctx.ModuleErrorf("multiple tools for %q, %q and %q", tool, tools[tool], p.Path().String())
+ }
} else {
ctx.ModuleErrorf("host tool %q missing output file", ctx.OtherModuleName(module))
}
@@ -156,20 +134,62 @@ func (g *generator) GenerateAndroidBuildActions(ctx android.ModuleContext) {
})
}
+ for _, tool := range g.properties.Tool_files {
+ toolPath := android.PathForModuleSrc(ctx, tool)
+ g.deps = append(g.deps, toolPath)
+ if _, exists := tools[tool]; !exists {
+ tools[tool] = toolPath
+ } else {
+ ctx.ModuleErrorf("multiple tools for %q, %q and %q", tool, tools[tool], toolPath.String())
+ }
+ }
+
+ cmd, err := android.Expand(g.properties.Cmd, func(name string) (string, error) {
+ switch name {
+ case "location":
+ if len(g.properties.Tools) > 0 {
+ return tools[g.properties.Tools[0]].String(), nil
+ } else {
+ return tools[g.properties.Tool_files[0]].String(), nil
+ }
+ case "in":
+ return "${in}", nil
+ case "out":
+ return "${out}", nil
+ case "genDir":
+ return g.genPath.String(), nil
+ default:
+ if strings.HasPrefix(name, "location ") {
+ label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
+ if tool, ok := tools[label]; ok {
+ return tool.String(), nil
+ } else {
+ return "", fmt.Errorf("unknown location label %q", label)
+ }
+ }
+ return "", fmt.Errorf("unknown variable '$(%s)'", name)
+ }
+ })
+
+ if err != nil {
+ ctx.PropertyErrorf("cmd", "%s", err.Error())
+ }
+
+ g.rule = ctx.Rule(pctx, "generator", blueprint.RuleParams{
+ Command: cmd,
+ })
+
for _, task := range g.tasks(ctx) {
- g.generateSourceFile(ctx, task, tool)
+ g.generateSourceFile(ctx, task)
}
}
-func (g *generator) generateSourceFile(ctx android.ModuleContext, task generateTask, tool string) {
+func (g *generator) generateSourceFile(ctx android.ModuleContext, task generateTask) {
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: g.rule,
Outputs: task.out,
Inputs: task.in,
Implicits: g.deps,
- Args: map[string]string{
- "tool": tool,
- },
})
for _, outputFile := range task.out {