Merge "Use interface for $(location) values in genrules"
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 72c0d10..06e82c8 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -793,13 +793,6 @@
return path.String()
}
-// SboxPathForTool takes a path to a tool, which may be an output file or a source file, and returns
-// the corresponding path for the tool in the sbox sandbox. It assumes that sandboxing and tool
-// sandboxing are enabled.
-func SboxPathForTool(ctx BuilderContext, path Path) string {
- return filepath.Join(sboxSandboxBaseDir, sboxPathForToolRel(ctx, path))
-}
-
func sboxPathForToolRel(ctx BuilderContext, path Path) string {
// Errors will be handled in RuleBuilder.Build where we have a context to report them
relOut, isRelOut, _ := maybeRelErr(PathForOutput(ctx, "host", ctx.Config().PrebuiltOS()).String(), path.String())
@@ -842,17 +835,21 @@
return ret
}
-// SboxPathForPackagedTool takes a PackageSpec for a tool and returns the corresponding path for the
-// tool after copying it into the sandbox. This can be used on the RuleBuilder command line to
-// reference the tool.
-func SboxPathForPackagedTool(spec PackagingSpec) string {
- return filepath.Join(sboxSandboxBaseDir, sboxPathForPackagedToolRel(spec))
-}
-
func sboxPathForPackagedToolRel(spec PackagingSpec) string {
return filepath.Join(sboxToolsSubDir, "out", spec.relPathInPackage)
}
+// PathForPackagedTool takes a PackageSpec for a tool and returns the corresponding path for the
+// tool after copying it into the sandbox. This can be used on the RuleBuilder command line to
+// reference the tool.
+func (c *RuleBuilderCommand) PathForPackagedTool(spec PackagingSpec) string {
+ if !c.rule.sboxTools {
+ panic("PathForPackagedTool() requires SandboxTools()")
+ }
+
+ return filepath.Join(sboxSandboxBaseDir, sboxPathForPackagedToolRel(spec))
+}
+
// PathForTool takes a path to a tool, which may be an output file or a source file, and returns
// the corresponding path for the tool in the sbox sandbox if sbox is enabled, or the original path
// if it is not. This can be used on the RuleBuilder command line to reference the tool.
@@ -863,6 +860,20 @@
return path.String()
}
+// PathsForTools takes a list of paths to tools, which may be output files or source files, and
+// returns the corresponding paths for the tools in the sbox sandbox if sbox is enabled, or the
+// original paths if it is not. This can be used on the RuleBuilder command line to reference the tool.
+func (c *RuleBuilderCommand) PathsForTools(paths Paths) []string {
+ if c.rule.sbox && c.rule.sboxTools {
+ var ret []string
+ for _, path := range paths {
+ ret = append(ret, filepath.Join(sboxSandboxBaseDir, sboxPathForToolRel(c.rule.ctx, path)))
+ }
+ return ret
+ }
+ return paths.Strings()
+}
+
// PackagedTool adds the specified tool path to the command line. It can only be used with tool
// sandboxing enabled by SandboxTools(), and will copy the tool into the sandbox.
func (c *RuleBuilderCommand) PackagedTool(spec PackagingSpec) *RuleBuilderCommand {
diff --git a/genrule/Android.bp b/genrule/Android.bp
index 214940d..8fb5c40 100644
--- a/genrule/Android.bp
+++ b/genrule/Android.bp
@@ -16,6 +16,7 @@
],
srcs: [
"genrule.go",
+ "locations.go",
],
testSrcs: [
"genrule_test.go",
diff --git a/genrule/genrule.go b/genrule/genrule.go
index cb841ed..9019a83 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -91,7 +91,6 @@
func init() {
pctx.Import("android/soong/android")
- pctx.HostBinToolVariable("sboxCmd", "sbox")
pctx.HostBinToolVariable("soongZip", "soong_zip")
pctx.HostBinToolVariable("zipSync", "zipsync")
@@ -254,18 +253,18 @@
g.exportedIncludeDirs = append(g.exportedIncludeDirs, android.PathForModuleGen(ctx, g.subDir))
}
- locationLabels := map[string][]string{}
+ locationLabels := map[string]location{}
firstLabel := ""
- addLocationLabel := func(label string, paths []string) {
+ addLocationLabel := func(label string, loc location) {
if firstLabel == "" {
firstLabel = label
}
if _, exists := locationLabels[label]; !exists {
- locationLabels[label] = paths
+ locationLabels[label] = loc
} else {
ctx.ModuleErrorf("multiple labels for %q, %q and %q",
- label, strings.Join(locationLabels[label], " "), strings.Join(paths, " "))
+ label, locationLabels[label], loc)
}
}
@@ -303,17 +302,17 @@
// sandbox.
packagedTools = append(packagedTools, specs...)
// Assume that the first PackagingSpec of the module is the tool.
- addLocationLabel(tag.label, []string{android.SboxPathForPackagedTool(specs[0])})
+ addLocationLabel(tag.label, packagedToolLocation{specs[0]})
} else {
tools = append(tools, path.Path())
- addLocationLabel(tag.label, []string{android.SboxPathForTool(ctx, path.Path())})
+ addLocationLabel(tag.label, toolLocation{android.Paths{path.Path()}})
}
case bootstrap.GoBinaryTool:
// A GoBinaryTool provides the install path to a tool, which will be copied.
if s, err := filepath.Rel(android.PathForOutput(ctx).String(), t.InstallPath()); err == nil {
toolPath := android.PathForOutput(ctx, s)
tools = append(tools, toolPath)
- addLocationLabel(tag.label, []string{android.SboxPathForTool(ctx, toolPath)})
+ addLocationLabel(tag.label, toolLocation{android.Paths{toolPath}})
} else {
ctx.ModuleErrorf("cannot find path for %q: %v", tool, err)
return
@@ -335,7 +334,7 @@
if ctx.Config().AllowMissingDependencies() {
for _, tool := range g.properties.Tools {
if !seenTools[tool] {
- addLocationLabel(tool, []string{"***missing tool " + tool + "***"})
+ addLocationLabel(tool, errorLocation{"***missing tool " + tool + "***"})
}
}
}
@@ -348,11 +347,7 @@
for _, toolFile := range g.properties.Tool_files {
paths := android.PathsForModuleSrc(ctx, []string{toolFile})
tools = append(tools, paths...)
- var sandboxPaths []string
- for _, path := range paths {
- sandboxPaths = append(sandboxPaths, android.SboxPathForTool(ctx, path))
- }
- addLocationLabel(toolFile, sandboxPaths)
+ addLocationLabel(toolFile, toolLocation{paths})
}
var srcFiles android.Paths
@@ -370,10 +365,10 @@
// The command that uses this placeholder file will never be executed because the rule will be
// replaced with an android.Error rule reporting the missing dependencies.
ctx.AddMissingDependencies(missingDeps)
- addLocationLabel(in, []string{"***missing srcs " + in + "***"})
+ addLocationLabel(in, errorLocation{"***missing srcs " + in + "***"})
} else {
srcFiles = append(srcFiles, paths...)
- addLocationLabel(in, paths.Strings())
+ addLocationLabel(in, inputLocation{paths})
}
}
@@ -408,7 +403,7 @@
cmd := rule.Command()
for _, out := range task.out {
- addLocationLabel(out.Rel(), []string{cmd.PathForOutput(out)})
+ addLocationLabel(out.Rel(), outputLocation{out})
}
referencedDepfile := false
@@ -426,16 +421,17 @@
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")
}
- paths := locationLabels[firstLabel]
+ loc := locationLabels[firstLabel]
+ paths := loc.Paths(cmd)
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
+ return paths[0], nil
case "in":
- return strings.Join(srcFiles.Strings(), " "), nil
+ return strings.Join(cmd.PathsForInputs(srcFiles), " "), nil
case "out":
var sandboxOuts []string
for _, out := range task.out {
@@ -453,7 +449,8 @@
default:
if strings.HasPrefix(name, "location ") {
label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
- if paths, ok := locationLabels[label]; ok {
+ if loc, ok := locationLabels[label]; ok {
+ paths := loc.Paths(cmd)
if len(paths) == 0 {
return reportError("label %q has no files", label)
} else if len(paths) > 1 {
@@ -466,7 +463,8 @@
}
} else if strings.HasPrefix(name, "locations ") {
label := strings.TrimSpace(strings.TrimPrefix(name, "locations "))
- if paths, ok := locationLabels[label]; ok {
+ if loc, ok := locationLabels[label]; ok {
+ paths := loc.Paths(cmd)
if len(paths) == 0 {
return reportError("label %q has no files", label)
}
@@ -719,7 +717,7 @@
outputDepfile = android.PathForModuleGen(ctx, genSubDir, "gensrcs.d")
depFixerTool := ctx.Config().HostToolPath(ctx, "dep_fixer")
fullCommand += fmt.Sprintf(" && %s -o $(depfile) %s",
- android.SboxPathForTool(ctx, depFixerTool),
+ rule.Command().PathForTool(depFixerTool),
strings.Join(commandDepFiles, " "))
extraTools = append(extraTools, depFixerTool)
}
diff --git a/genrule/locations.go b/genrule/locations.go
new file mode 100644
index 0000000..2978b91
--- /dev/null
+++ b/genrule/locations.go
@@ -0,0 +1,104 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package genrule
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+// location is used to service $(location) and $(locations) entries in genrule commands.
+type location interface {
+ Paths(cmd *android.RuleBuilderCommand) []string
+ String() string
+}
+
+// inputLocation is a $(location) result for an entry in the srcs property.
+type inputLocation struct {
+ paths android.Paths
+}
+
+func (l inputLocation) String() string {
+ return strings.Join(l.paths.Strings(), " ")
+}
+
+func (l inputLocation) Paths(cmd *android.RuleBuilderCommand) []string {
+ return cmd.PathsForInputs(l.paths)
+}
+
+var _ location = inputLocation{}
+
+// outputLocation is a $(location) result for an entry in the out property.
+type outputLocation struct {
+ path android.WritablePath
+}
+
+func (l outputLocation) String() string {
+ return l.path.String()
+}
+
+func (l outputLocation) Paths(cmd *android.RuleBuilderCommand) []string {
+ return []string{cmd.PathForOutput(l.path)}
+}
+
+var _ location = outputLocation{}
+
+// toolLocation is a $(location) result for an entry in the tools or tool_files property.
+type toolLocation struct {
+ paths android.Paths
+}
+
+func (l toolLocation) String() string {
+ return strings.Join(l.paths.Strings(), " ")
+}
+
+func (l toolLocation) Paths(cmd *android.RuleBuilderCommand) []string {
+ return cmd.PathsForTools(l.paths)
+}
+
+var _ location = toolLocation{}
+
+// packagedToolLocation is a $(location) result for an entry in the tools or tool_files property
+// that has PackagingSpecs.
+type packagedToolLocation struct {
+ spec android.PackagingSpec
+}
+
+func (l packagedToolLocation) String() string {
+ return l.spec.FileName()
+}
+
+func (l packagedToolLocation) Paths(cmd *android.RuleBuilderCommand) []string {
+ return []string{cmd.PathForPackagedTool(l.spec)}
+}
+
+var _ location = packagedToolLocation{}
+
+// errorLocation is a placeholder for a $(location) result that returns garbage to break the command
+// when error reporting is delayed by ALLOW_MISSING_DEPENDENCIES=true.
+type errorLocation struct {
+ err string
+}
+
+func (l errorLocation) String() string {
+ return l.err
+}
+
+func (l errorLocation) Paths(cmd *android.RuleBuilderCommand) []string {
+ return []string{l.err}
+}
+
+var _ location = errorLocation{}