aboutsummaryrefslogtreecommitdiffstats
path: root/genrule
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2018-10-04 23:29:14 -0700
committerColin Cross <ccross@android.com>2018-10-08 16:05:48 -0700
commit08f15ab46655d7b8a285df531d1dfd3cafb2eb73 (patch)
treecf1e3f672cd40e42d848112752c94b326428e2f6 /genrule
parent1c7e0a235b83739b07d9ca88ba90d558fdc4a69d (diff)
downloadbuild_soong-08f15ab46655d7b8a285df531d1dfd3cafb2eb73.tar.gz
build_soong-08f15ab46655d7b8a285df531d1dfd3cafb2eb73.tar.bz2
build_soong-08f15ab46655d7b8a285df531d1dfd3cafb2eb73.zip
genrule: add $(location) for inputs and outputs
There was no way to select a single source file from a genrule that has multiple source files. Make Soong's genrule closer to Bazel by supporting $(location) for input and outputs. Change the label used for tools referenced through filegroups to the name of the module instead of the name of the file, which means it matches the string used in the tools property. Also support :module format in the tools property in preparation for deprecating the tool_files property and putting both files and modules in the tools property. Bug: 117354232 Test: genrule_test.go Change-Id: Id31a4ac4ff7064076a576c1d8ffeb7c19fc6b9a4 Merged-In: Id31a4ac4ff7064076a576c1d8ffeb7c19fc6b9a4 (cherry picked from commit 098d22b5f6d965872b524ce798ce728580ce405c)
Diffstat (limited to 'genrule')
-rw-r--r--genrule/genrule.go101
-rw-r--r--genrule/genrule_test.go119
2 files changed, 187 insertions, 33 deletions
diff --git a/genrule/genrule.go b/genrule/genrule.go
index f19e2aa0..2824e490 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -52,10 +52,9 @@ type HostToolProvider interface {
type hostToolDependencyTag struct {
blueprint.BaseDependencyTag
+ label string
}
-var hostToolDepTag hostToolDependencyTag
-
type generatorProperties struct {
// The command to run on one or more input files. Cmd supports substitution of a few variables
// (the actual substitution is implemented in GenerateAndroidBuildActions below)
@@ -63,7 +62,7 @@ type generatorProperties struct {
// Available variables for substitution:
//
// $(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>
+ // $(location <label>): the path to the tool, tool_file, input or output with name <label>
// $(in): one or more input files
// $(out): a single output file
// $(depfile): a file to which dependencies will be written, if the depfile property is set to true
@@ -141,10 +140,14 @@ func (g *Module) DepsMutator(ctx android.BottomUpMutatorContext) {
android.ExtractSourcesDeps(ctx, g.properties.Srcs)
android.ExtractSourcesDeps(ctx, g.properties.Tool_files)
if g, ok := ctx.Module().(*Module); ok {
- if len(g.properties.Tools) > 0 {
+ for _, tool := range g.properties.Tools {
+ tag := hostToolDependencyTag{label: tool}
+ if m := android.SrcIsModule(tool); m != "" {
+ tool = m
+ }
ctx.AddFarVariationDependencies([]blueprint.Variation{
{Mutator: "arch", Variation: ctx.Config().BuildOsVariant},
- }, hostToolDepTag, g.properties.Tools...)
+ }, tag, tool)
}
}
}
@@ -159,12 +162,25 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
g.exportedIncludeDirs = append(g.exportedIncludeDirs, android.PathForModuleGen(ctx, ""))
}
- tools := map[string]android.Path{}
+ locationLabels := map[string][]string{}
+ firstLabel := ""
+
+ addLocationLabel := func(label string, paths []string) {
+ if firstLabel == "" {
+ firstLabel = label
+ }
+ if _, exists := locationLabels[label]; !exists {
+ locationLabels[label] = paths
+ } else {
+ ctx.ModuleErrorf("multiple labels for %q, %q and %q",
+ label, strings.Join(locationLabels[label], " "), strings.Join(paths, " "))
+ }
+ }
if len(g.properties.Tools) > 0 {
ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
- switch ctx.OtherModuleDependencyTag(module) {
- case hostToolDepTag:
+ switch tag := ctx.OtherModuleDependencyTag(module).(type) {
+ case hostToolDependencyTag:
tool := ctx.OtherModuleName(module)
var path android.OptionalPath
@@ -192,11 +208,7 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if path.Valid() {
g.deps = append(g.deps, path.Path())
- if _, exists := tools[tool]; !exists {
- tools[tool] = path.Path()
- } else {
- ctx.ModuleErrorf("multiple tools for %q, %q and %q", tool, tools[tool], path.Path().String())
- }
+ addLocationLabel(tag.label, []string{path.Path().String()})
} else {
ctx.ModuleErrorf("host tool %q missing output file", tool)
}
@@ -208,21 +220,27 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
return
}
- toolFiles := ctx.ExpandSources(g.properties.Tool_files, nil)
- for _, tool := range toolFiles {
- g.deps = append(g.deps, tool)
- if _, exists := tools[tool.Rel()]; !exists {
- tools[tool.Rel()] = tool
- } else {
- ctx.ModuleErrorf("multiple tools for %q, %q and %q", tool, tools[tool.Rel()], tool.Rel())
- }
+ for _, toolFile := range g.properties.Tool_files {
+ paths := ctx.ExpandSources([]string{toolFile}, nil)
+ g.deps = append(g.deps, paths...)
+ addLocationLabel(toolFile, paths.Strings())
}
- referencedDepfile := false
+ var srcFiles android.Paths
+ for _, in := range g.properties.Srcs {
+ paths := ctx.ExpandSources([]string{in}, nil)
+ srcFiles = append(srcFiles, paths...)
+ addLocationLabel(in, paths.Strings())
+ }
- srcFiles := ctx.ExpandSources(g.properties.Srcs, nil)
task := g.taskGenerator(ctx, String(g.properties.Cmd), srcFiles)
+ for _, out := range task.out {
+ addLocationLabel(out.Rel(), []string{filepath.Join("__SBOX_OUT_DIR__", out.Rel())})
+ }
+
+ referencedDepfile := false
+
rawCommand, err := android.Expand(task.cmd, func(name string) (string, error) {
// report the error directly without returning an error to android.Expand to catch multiple errors in a
// single run
@@ -233,13 +251,17 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
switch name {
case "location":
- if len(g.properties.Tools) == 0 && len(toolFiles) == 0 {
+ if len(g.properties.Tools) == 0 && len(g.properties.Tool_files) == 0 {
return reportError("at least one `tools` or `tool_files` is required if $(location) is used")
- } else if len(g.properties.Tools) > 0 {
- return tools[g.properties.Tools[0]].String(), nil
- } else {
- return tools[toolFiles[0].Rel()].String(), nil
}
+ paths := locationLabels[firstLabel]
+ if len(paths) == 0 {
+ return reportError("default label %q has no files", firstLabel)
+ } else if len(paths) > 1 {
+ return reportError("default label %q has multiple files, use $(locations %s) to reference it",
+ firstLabel, firstLabel)
+ }
+ return locationLabels[firstLabel][0], nil
case "in":
return "${in}", nil
case "out":
@@ -255,13 +277,30 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
default:
if strings.HasPrefix(name, "location ") {
label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
- if tool, ok := tools[label]; ok {
- return tool.String(), nil
+ if paths, ok := locationLabels[label]; ok {
+ if len(paths) == 0 {
+ return reportError("label %q has no files", label)
+ } else if len(paths) > 1 {
+ return reportError("label %q has multiple files, use $(locations %s) to reference it",
+ label, label)
+ }
+ return paths[0], nil
} else {
return reportError("unknown location label %q", label)
}
+ } else if strings.HasPrefix(name, "locations ") {
+ label := strings.TrimSpace(strings.TrimPrefix(name, "locations "))
+ if paths, ok := locationLabels[label]; ok {
+ if len(paths) == 0 {
+ return reportError("label %q has no files", label)
+ }
+ return strings.Join(paths, " "), nil
+ } else {
+ return reportError("unknown locations label %q", label)
+ }
+ } else {
+ return reportError("unknown variable '$(%s)'", name)
}
- return reportError("unknown variable '$(%s)'", name)
}
})
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 0d690d42..7e16ce1f 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -133,6 +133,15 @@ func TestGenruleCmd(t *testing.T) {
expect: "out/tool > __SBOX_OUT_FILES__",
},
{
+ name: "empty location tool2",
+ prop: `
+ tools: [":tool"],
+ out: ["out"],
+ cmd: "$(location) > $(out)",
+ `,
+ expect: "out/tool > __SBOX_OUT_FILES__",
+ },
+ {
name: "empty location tool file",
prop: `
tool_files: ["tool_file1"],
@@ -170,6 +179,15 @@ func TestGenruleCmd(t *testing.T) {
expect: "out/tool > __SBOX_OUT_FILES__",
},
{
+ name: "tool2",
+ prop: `
+ tools: [":tool"],
+ out: ["out"],
+ cmd: "$(location :tool) > $(out)",
+ `,
+ expect: "out/tool > __SBOX_OUT_FILES__",
+ },
+ {
name: "tool file",
prop: `
tool_files: ["tool_file1"],
@@ -183,7 +201,7 @@ func TestGenruleCmd(t *testing.T) {
prop: `
tool_files: [":1tool_file"],
out: ["out"],
- cmd: "$(location tool_file1) > $(out)",
+ cmd: "$(location :1tool_file) > $(out)",
`,
expect: "tool_file1 > __SBOX_OUT_FILES__",
},
@@ -192,7 +210,7 @@ func TestGenruleCmd(t *testing.T) {
prop: `
tool_files: [":tool_files"],
out: ["out"],
- cmd: "$(location tool_file1) $(location tool_file2) > $(out)",
+ cmd: "$(locations :tool_files) > $(out)",
`,
expect: "tool_file1 tool_file2 > __SBOX_OUT_FILES__",
},
@@ -233,6 +251,42 @@ func TestGenruleCmd(t *testing.T) {
expect: "cat ${in} > __SBOX_OUT_FILES__",
},
{
+ name: "location in1",
+ prop: `
+ srcs: ["in1"],
+ out: ["out"],
+ cmd: "cat $(location in1) > $(out)",
+ `,
+ expect: "cat in1 > __SBOX_OUT_FILES__",
+ },
+ {
+ name: "location in1 fg",
+ prop: `
+ srcs: [":1in"],
+ out: ["out"],
+ cmd: "cat $(location :1in) > $(out)",
+ `,
+ expect: "cat in1 > __SBOX_OUT_FILES__",
+ },
+ {
+ name: "location ins",
+ prop: `
+ srcs: ["in1", "in2"],
+ out: ["out"],
+ cmd: "cat $(location in1) > $(out)",
+ `,
+ expect: "cat in1 > __SBOX_OUT_FILES__",
+ },
+ {
+ name: "location ins fg",
+ prop: `
+ srcs: [":ins"],
+ out: ["out"],
+ cmd: "cat $(locations :ins) > $(out)",
+ `,
+ expect: "cat in1 in2 > __SBOX_OUT_FILES__",
+ },
+ {
name: "outs",
prop: `
out: ["out", "out2"],
@@ -241,6 +295,14 @@ func TestGenruleCmd(t *testing.T) {
expect: "echo foo > __SBOX_OUT_FILES__",
},
{
+ name: "location out",
+ prop: `
+ out: ["out", "out2"],
+ cmd: "echo foo > $(location out2)",
+ `,
+ expect: "echo foo > __SBOX_OUT_DIR__/out2",
+ },
+ {
name: "depfile",
prop: `
out: ["out"],
@@ -267,6 +329,24 @@ func TestGenruleCmd(t *testing.T) {
err: "at least one `tools` or `tool_files` is required if $(location) is used",
},
{
+ name: "error empty location no files",
+ prop: `
+ tool_files: [":empty"],
+ out: ["out"],
+ cmd: "$(location) > $(out)",
+ `,
+ err: `default label ":empty" has no files`,
+ },
+ {
+ name: "error empty location multiple files",
+ prop: `
+ tool_files: [":tool_files"],
+ out: ["out"],
+ cmd: "$(location) > $(out)",
+ `,
+ err: `default label ":tool_files" has multiple files`,
+ },
+ {
name: "error location",
prop: `
out: ["out"],
@@ -275,6 +355,41 @@ func TestGenruleCmd(t *testing.T) {
err: `unknown location label "missing"`,
},
{
+ name: "error locations",
+ prop: `
+ out: ["out"],
+ cmd: "echo foo > $(locations missing)",
+ `,
+ err: `unknown locations label "missing"`,
+ },
+ {
+ name: "error location no files",
+ prop: `
+ out: ["out"],
+ srcs: [":empty"],
+ cmd: "echo $(location :empty) > $(out)",
+ `,
+ err: `label ":empty" has no files`,
+ },
+ {
+ name: "error locations no files",
+ prop: `
+ out: ["out"],
+ srcs: [":empty"],
+ cmd: "echo $(locations :empty) > $(out)",
+ `,
+ err: `label ":empty" has no files`,
+ },
+ {
+ name: "error location multiple files",
+ prop: `
+ out: ["out"],
+ srcs: [":ins"],
+ cmd: "echo $(location :ins) > $(out)",
+ `,
+ err: `label ":ins" has multiple files`,
+ },
+ {
name: "error variable",
prop: `
out: ["out"],