Merge "genrule: add $(location) for inputs and outputs"
This commit is contained in:
commit
f4465da1dc
2 changed files with 188 additions and 34 deletions
|
@ -52,10 +52,9 @@ type HostToolProvider interface {
|
||||||
|
|
||||||
type hostToolDependencyTag struct {
|
type hostToolDependencyTag struct {
|
||||||
blueprint.BaseDependencyTag
|
blueprint.BaseDependencyTag
|
||||||
|
label string
|
||||||
}
|
}
|
||||||
|
|
||||||
var hostToolDepTag hostToolDependencyTag
|
|
||||||
|
|
||||||
type generatorProperties struct {
|
type generatorProperties struct {
|
||||||
// The command to run on one or more input files. Cmd supports substitution of a few variables
|
// 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)
|
// (the actual substitution is implemented in GenerateAndroidBuildActions below)
|
||||||
|
@ -63,7 +62,7 @@ type generatorProperties struct {
|
||||||
// Available variables for substitution:
|
// Available variables for substitution:
|
||||||
//
|
//
|
||||||
// $(location): the path to the first entry in tools or tool_files
|
// $(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
|
// $(in): one or more input files
|
||||||
// $(out): a single output file
|
// $(out): a single output file
|
||||||
// $(depfile): a file to which dependencies will be written, if the depfile property is set to true
|
// $(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.Srcs)
|
||||||
android.ExtractSourcesDeps(ctx, g.properties.Tool_files)
|
android.ExtractSourcesDeps(ctx, g.properties.Tool_files)
|
||||||
if g, ok := ctx.Module().(*Module); ok {
|
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{
|
ctx.AddFarVariationDependencies([]blueprint.Variation{
|
||||||
{Mutator: "arch", Variation: ctx.Config().BuildOsVariant},
|
{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, ""))
|
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 {
|
if len(g.properties.Tools) > 0 {
|
||||||
ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
|
ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
|
||||||
switch ctx.OtherModuleDependencyTag(module) {
|
switch tag := ctx.OtherModuleDependencyTag(module).(type) {
|
||||||
case hostToolDepTag:
|
case hostToolDependencyTag:
|
||||||
tool := ctx.OtherModuleName(module)
|
tool := ctx.OtherModuleName(module)
|
||||||
var path android.OptionalPath
|
var path android.OptionalPath
|
||||||
|
|
||||||
|
@ -192,11 +208,7 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
|
|
||||||
if path.Valid() {
|
if path.Valid() {
|
||||||
g.deps = append(g.deps, path.Path())
|
g.deps = append(g.deps, path.Path())
|
||||||
if _, exists := tools[tool]; !exists {
|
addLocationLabel(tag.label, []string{path.Path().String()})
|
||||||
tools[tool] = path.Path()
|
|
||||||
} else {
|
|
||||||
ctx.ModuleErrorf("multiple tools for %q, %q and %q", tool, tools[tool], path.Path().String())
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ctx.ModuleErrorf("host tool %q missing output file", tool)
|
ctx.ModuleErrorf("host tool %q missing output file", tool)
|
||||||
}
|
}
|
||||||
|
@ -208,21 +220,27 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
toolFiles := ctx.ExpandSources(g.properties.Tool_files, nil)
|
for _, toolFile := range g.properties.Tool_files {
|
||||||
for _, tool := range toolFiles {
|
paths := ctx.ExpandSources([]string{toolFile}, nil)
|
||||||
g.deps = append(g.deps, tool)
|
g.deps = append(g.deps, paths...)
|
||||||
if _, exists := tools[tool.Rel()]; !exists {
|
addLocationLabel(toolFile, paths.Strings())
|
||||||
tools[tool.Rel()] = tool
|
}
|
||||||
} else {
|
|
||||||
ctx.ModuleErrorf("multiple tools for %q, %q and %q", tool, tools[tool.Rel()], tool.Rel())
|
var srcFiles android.Paths
|
||||||
}
|
for _, in := range g.properties.Srcs {
|
||||||
|
paths := ctx.ExpandSources([]string{in}, nil)
|
||||||
|
srcFiles = append(srcFiles, paths...)
|
||||||
|
addLocationLabel(in, paths.Strings())
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
referencedDepfile := false
|
||||||
|
|
||||||
srcFiles := ctx.ExpandSources(g.properties.Srcs, nil)
|
|
||||||
task := g.taskGenerator(ctx, String(g.properties.Cmd), srcFiles)
|
|
||||||
|
|
||||||
rawCommand, err := android.Expand(task.cmd, func(name string) (string, error) {
|
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
|
// report the error directly without returning an error to android.Expand to catch multiple errors in a
|
||||||
// single run
|
// single run
|
||||||
|
@ -233,13 +251,17 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
|
|
||||||
switch name {
|
switch name {
|
||||||
case "location":
|
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")
|
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":
|
case "in":
|
||||||
return "${in}", nil
|
return "${in}", nil
|
||||||
case "out":
|
case "out":
|
||||||
|
@ -255,13 +277,30 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
default:
|
default:
|
||||||
if strings.HasPrefix(name, "location ") {
|
if strings.HasPrefix(name, "location ") {
|
||||||
label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
|
label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
|
||||||
if tool, ok := tools[label]; ok {
|
if paths, ok := locationLabels[label]; ok {
|
||||||
return tool.String(), nil
|
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 {
|
} else {
|
||||||
return reportError("unknown location label %q", label)
|
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)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,15 @@ func TestGenruleCmd(t *testing.T) {
|
||||||
`,
|
`,
|
||||||
expect: "out/tool > __SBOX_OUT_FILES__",
|
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",
|
name: "empty location tool file",
|
||||||
prop: `
|
prop: `
|
||||||
|
@ -169,6 +178,15 @@ func TestGenruleCmd(t *testing.T) {
|
||||||
`,
|
`,
|
||||||
expect: "out/tool > __SBOX_OUT_FILES__",
|
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",
|
name: "tool file",
|
||||||
prop: `
|
prop: `
|
||||||
|
@ -183,7 +201,7 @@ func TestGenruleCmd(t *testing.T) {
|
||||||
prop: `
|
prop: `
|
||||||
tool_files: [":1tool_file"],
|
tool_files: [":1tool_file"],
|
||||||
out: ["out"],
|
out: ["out"],
|
||||||
cmd: "$(location tool_file1) > $(out)",
|
cmd: "$(location :1tool_file) > $(out)",
|
||||||
`,
|
`,
|
||||||
expect: "tool_file1 > __SBOX_OUT_FILES__",
|
expect: "tool_file1 > __SBOX_OUT_FILES__",
|
||||||
},
|
},
|
||||||
|
@ -192,7 +210,7 @@ func TestGenruleCmd(t *testing.T) {
|
||||||
prop: `
|
prop: `
|
||||||
tool_files: [":tool_files"],
|
tool_files: [":tool_files"],
|
||||||
out: ["out"],
|
out: ["out"],
|
||||||
cmd: "$(location tool_file1) $(location tool_file2) > $(out)",
|
cmd: "$(locations :tool_files) > $(out)",
|
||||||
`,
|
`,
|
||||||
expect: "tool_file1 tool_file2 > __SBOX_OUT_FILES__",
|
expect: "tool_file1 tool_file2 > __SBOX_OUT_FILES__",
|
||||||
},
|
},
|
||||||
|
@ -232,6 +250,42 @@ func TestGenruleCmd(t *testing.T) {
|
||||||
`,
|
`,
|
||||||
expect: "cat ${in} > __SBOX_OUT_FILES__",
|
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",
|
name: "outs",
|
||||||
prop: `
|
prop: `
|
||||||
|
@ -240,6 +294,14 @@ func TestGenruleCmd(t *testing.T) {
|
||||||
`,
|
`,
|
||||||
expect: "echo foo > __SBOX_OUT_FILES__",
|
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",
|
name: "depfile",
|
||||||
prop: `
|
prop: `
|
||||||
|
@ -266,6 +328,24 @@ func TestGenruleCmd(t *testing.T) {
|
||||||
`,
|
`,
|
||||||
err: "at least one `tools` or `tool_files` is required if $(location) is used",
|
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",
|
name: "error location",
|
||||||
prop: `
|
prop: `
|
||||||
|
@ -274,6 +354,41 @@ func TestGenruleCmd(t *testing.T) {
|
||||||
`,
|
`,
|
||||||
err: `unknown location label "missing"`,
|
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",
|
name: "error variable",
|
||||||
prop: `
|
prop: `
|
||||||
|
|
Loading…
Reference in a new issue