Make $(depfile) work with sbox
Most notably, the sandbox depfile path should be passed into the tool. Bug: 68336760 Test: m -j checkbuild Change-Id: I22f944a3f57d613fda26de0ea777a915cafcd020
This commit is contained in:
@@ -32,7 +32,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var usage = "Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> <outputFile> [<outputFile>...]\n" +
|
var usage = "Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> [--depfile-out depFile] <outputFile> [<outputFile>...]\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"Runs <commandToRun> and moves each <outputFile> out of <sandboxPath>\n" +
|
"Runs <commandToRun> and moves each <outputFile> out of <sandboxPath>\n" +
|
||||||
"If any file in <outputFiles> is specified by absolute path, then <outputRoot> must be specified as well,\n" +
|
"If any file in <outputFiles> is specified by absolute path, then <outputRoot> must be specified as well,\n" +
|
||||||
@@ -43,13 +43,18 @@ func usageError(violation string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func run() error {
|
func run() error {
|
||||||
var outFiles []string
|
// the contents of the __SBOX_OUT_FILES__ variable
|
||||||
|
var outputsVarEntries []string
|
||||||
|
// all outputs
|
||||||
|
var allOutputs []string
|
||||||
|
|
||||||
args := os.Args[1:]
|
args := os.Args[1:]
|
||||||
|
|
||||||
var rawCommand string
|
var rawCommand string
|
||||||
var sandboxesRoot string
|
var sandboxesRoot string
|
||||||
removeTempDir := true
|
removeTempDir := true
|
||||||
var outputRoot string
|
var outputRoot string
|
||||||
|
var depfile string
|
||||||
|
|
||||||
for i := 0; i < len(args); i++ {
|
for i := 0; i < len(args); i++ {
|
||||||
arg := args[i]
|
arg := args[i]
|
||||||
@@ -64,17 +69,20 @@ func run() error {
|
|||||||
i++
|
i++
|
||||||
} else if arg == "--keep-out-dir" {
|
} else if arg == "--keep-out-dir" {
|
||||||
removeTempDir = false
|
removeTempDir = false
|
||||||
|
} else if arg == "--depfile-out" {
|
||||||
|
depfile = args[i+1]
|
||||||
|
i++
|
||||||
} else {
|
} else {
|
||||||
outFiles = append(outFiles, arg)
|
outputsVarEntries = append(outputsVarEntries, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(rawCommand) == 0 {
|
if rawCommand == "" {
|
||||||
return usageError("-c <commandToRun> is required and must be non-empty")
|
return usageError("-c <commandToRun> is required and must be non-empty")
|
||||||
}
|
}
|
||||||
if outFiles == nil {
|
if len(outputsVarEntries) == 0 {
|
||||||
return usageError("at least one output file must be given")
|
return usageError("at least one output file must be given")
|
||||||
}
|
}
|
||||||
if len(sandboxesRoot) == 0 {
|
if sandboxesRoot == "" {
|
||||||
// In practice, the value of sandboxesRoot will mostly likely be at a fixed location relative to OUT_DIR,
|
// In practice, the value of sandboxesRoot will mostly likely be at a fixed location relative to OUT_DIR,
|
||||||
// and the sbox executable will most likely be at a fixed location relative to OUT_DIR too, so
|
// and the sbox executable will most likely be at a fixed location relative to OUT_DIR too, so
|
||||||
// the value of sandboxesRoot will most likely be at a fixed location relative to the sbox executable
|
// the value of sandboxesRoot will most likely be at a fixed location relative to the sbox executable
|
||||||
@@ -82,25 +90,39 @@ func run() error {
|
|||||||
// and by passing it as a parameter we don't need to duplicate its value
|
// and by passing it as a parameter we don't need to duplicate its value
|
||||||
return usageError("--sandbox-path <sandboxPath> is required and must be non-empty")
|
return usageError("--sandbox-path <sandboxPath> is required and must be non-empty")
|
||||||
}
|
}
|
||||||
|
if len(outputRoot) == 0 {
|
||||||
// Rewrite output file paths to be relative to output root
|
return usageError("--output-root <outputRoot> is required and must be non-empty")
|
||||||
// This facilitates matching them up against the corresponding paths in the temporary directory in case they're absolute
|
|
||||||
for i, filePath := range outFiles {
|
|
||||||
if path.IsAbs(filePath) {
|
|
||||||
if len(outputRoot) == 0 {
|
|
||||||
return fmt.Errorf("Absolute path %s requires nonempty value for --output-root", filePath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
relativePath, err := filepath.Rel(outputRoot, filePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
outFiles[i] = relativePath
|
|
||||||
}
|
}
|
||||||
|
|
||||||
os.MkdirAll(sandboxesRoot, 0777)
|
os.MkdirAll(sandboxesRoot, 0777)
|
||||||
|
|
||||||
tempDir, err := ioutil.TempDir(sandboxesRoot, "sbox")
|
tempDir, err := ioutil.TempDir(sandboxesRoot, "sbox")
|
||||||
|
|
||||||
|
// Rewrite output file paths to be relative to output root
|
||||||
|
// This facilitates matching them up against the corresponding paths in the temporary directory in case they're absolute
|
||||||
|
for i, filePath := range outputsVarEntries {
|
||||||
|
relativePath, err := filepath.Rel(outputRoot, filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
outputsVarEntries[i] = relativePath
|
||||||
|
}
|
||||||
|
|
||||||
|
allOutputs = append([]string(nil), outputsVarEntries...)
|
||||||
|
|
||||||
|
if depfile != "" {
|
||||||
|
sandboxedDepfile, err := filepath.Rel(outputRoot, depfile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
allOutputs = append(allOutputs, sandboxedDepfile)
|
||||||
|
if !strings.Contains(rawCommand, "__SBOX_DEPFILE__") {
|
||||||
|
return fmt.Errorf("the --depfile-out argument only makes sense if the command contains the text __SBOX_DEPFILE__")
|
||||||
|
}
|
||||||
|
rawCommand = strings.Replace(rawCommand, "__SBOX_DEPFILE__", filepath.Join(tempDir, sandboxedDepfile), -1)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to create temp dir: %s", err)
|
return fmt.Errorf("Failed to create temp dir: %s", err)
|
||||||
}
|
}
|
||||||
@@ -122,7 +144,7 @@ func run() error {
|
|||||||
if strings.Contains(rawCommand, "__SBOX_OUT_FILES__") {
|
if strings.Contains(rawCommand, "__SBOX_OUT_FILES__") {
|
||||||
// expands into a space-separated list of output files to be generated into the sandbox directory
|
// expands into a space-separated list of output files to be generated into the sandbox directory
|
||||||
tempOutPaths := []string{}
|
tempOutPaths := []string{}
|
||||||
for _, outputPath := range outFiles {
|
for _, outputPath := range outputsVarEntries {
|
||||||
tempOutPath := path.Join(tempDir, outputPath)
|
tempOutPath := path.Join(tempDir, outputPath)
|
||||||
tempOutPaths = append(tempOutPaths, tempOutPath)
|
tempOutPaths = append(tempOutPaths, tempOutPath)
|
||||||
}
|
}
|
||||||
@@ -130,8 +152,12 @@ func run() error {
|
|||||||
rawCommand = strings.Replace(rawCommand, "__SBOX_OUT_FILES__", pathsText, -1)
|
rawCommand = strings.Replace(rawCommand, "__SBOX_OUT_FILES__", pathsText, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, filePath := range outFiles {
|
for _, filePath := range allOutputs {
|
||||||
os.MkdirAll(path.Join(tempDir, filepath.Dir(filePath)), 0777)
|
dir := path.Join(tempDir, filepath.Dir(filePath))
|
||||||
|
err = os.MkdirAll(dir, 0777)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commandDescription := rawCommand
|
commandDescription := rawCommand
|
||||||
@@ -150,7 +176,7 @@ func run() error {
|
|||||||
|
|
||||||
// validate that all files are created properly
|
// validate that all files are created properly
|
||||||
var outputErrors []error
|
var outputErrors []error
|
||||||
for _, filePath := range outFiles {
|
for _, filePath := range allOutputs {
|
||||||
tempPath := filepath.Join(tempDir, filePath)
|
tempPath := filepath.Join(tempDir, filePath)
|
||||||
fileInfo, err := os.Stat(tempPath)
|
fileInfo, err := os.Stat(tempPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -168,7 +194,7 @@ func run() error {
|
|||||||
return fmt.Errorf("mismatch between declared and actual outputs in sbox command (%s):\n%v", commandDescription, outputErrors)
|
return fmt.Errorf("mismatch between declared and actual outputs in sbox command (%s):\n%v", commandDescription, outputErrors)
|
||||||
}
|
}
|
||||||
// the created files match the declared files; now move them
|
// the created files match the declared files; now move them
|
||||||
for _, filePath := range outFiles {
|
for _, filePath := range allOutputs {
|
||||||
tempPath := filepath.Join(tempDir, filePath)
|
tempPath := filepath.Join(tempDir, filePath)
|
||||||
destPath := filePath
|
destPath := filePath
|
||||||
if len(outputRoot) != 0 {
|
if len(outputRoot) != 0 {
|
||||||
|
@@ -16,7 +16,6 @@ package genrule
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/blueprint"
|
"github.com/google/blueprint"
|
||||||
@@ -139,6 +138,17 @@ func (g *Module) DepsMutator(ctx android.BottomUpMutatorContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Given an output file, returns an expression for the corresponding file path within the sandbox
|
||||||
|
func sandboxPathForOutput(ctx android.ModuleContext, outputFile string) (relative string, err error) {
|
||||||
|
var relativePath string
|
||||||
|
basedir := ctx.AConfig().BuildDir()
|
||||||
|
relativePath, err = filepath.Rel(basedir, outputFile)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return filepath.Join("__SBOX_OUT_DIR__", relativePath), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
if len(g.properties.Tools) == 0 && len(g.properties.Tool_files) == 0 {
|
if len(g.properties.Tools) == 0 && len(g.properties.Tool_files) == 0 {
|
||||||
ctx.ModuleErrorf("at least one `tools` or `tool_files` is required")
|
ctx.ModuleErrorf("at least one `tools` or `tool_files` is required")
|
||||||
@@ -209,6 +219,8 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
referencedDepfile := false
|
||||||
|
|
||||||
rawCommand, err := android.Expand(g.properties.Cmd, func(name string) (string, error) {
|
rawCommand, err := android.Expand(g.properties.Cmd, func(name string) (string, error) {
|
||||||
switch name {
|
switch name {
|
||||||
case "location":
|
case "location":
|
||||||
@@ -222,20 +234,17 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
case "out":
|
case "out":
|
||||||
return "__SBOX_OUT_FILES__", nil
|
return "__SBOX_OUT_FILES__", nil
|
||||||
case "depfile":
|
case "depfile":
|
||||||
|
referencedDepfile = true
|
||||||
if !g.properties.Depfile {
|
if !g.properties.Depfile {
|
||||||
return "", fmt.Errorf("$(depfile) used without depfile property")
|
return "", fmt.Errorf("$(depfile) used without depfile property")
|
||||||
}
|
}
|
||||||
return "${depfile}", nil
|
return "__SBOX_DEPFILE__", nil
|
||||||
case "genDir":
|
case "genDir":
|
||||||
genPath := android.PathForModuleGen(ctx, "").String()
|
path, err := sandboxPathForOutput(ctx, android.PathForModuleGen(ctx, "").String())
|
||||||
var relativePath string
|
|
||||||
var err error
|
|
||||||
outputPath := android.PathForOutput(ctx).String()
|
|
||||||
relativePath, err = filepath.Rel(outputPath, genPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return "", err
|
||||||
}
|
}
|
||||||
return path.Join("__SBOX_OUT_DIR__", relativePath), nil
|
return path, nil
|
||||||
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 "))
|
||||||
@@ -249,6 +258,10 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if g.properties.Depfile && !referencedDepfile {
|
||||||
|
ctx.PropertyErrorf("cmd", "specified depfile=true but did not include a reference to '${depfile}' in cmd")
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.PropertyErrorf("cmd", "%s", err.Error())
|
ctx.PropertyErrorf("cmd", "%s", err.Error())
|
||||||
return
|
return
|
||||||
@@ -260,7 +273,11 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
|
|
||||||
// recall that Sprintf replaces percent sign expressions, whereas dollar signs expressions remain as written,
|
// recall that Sprintf replaces percent sign expressions, whereas dollar signs expressions remain as written,
|
||||||
// to be replaced later by ninja_strings.go
|
// to be replaced later by ninja_strings.go
|
||||||
sandboxCommand := fmt.Sprintf("$sboxCmd --sandbox-path %s --output-root %s -c %q $allouts", sandboxPath, buildDir, rawCommand)
|
depfilePlaceholder := ""
|
||||||
|
if g.properties.Depfile {
|
||||||
|
depfilePlaceholder = "$depfileArgs"
|
||||||
|
}
|
||||||
|
sandboxCommand := fmt.Sprintf("$sboxCmd --sandbox-path %s --output-root %s -c %q %s $allouts", sandboxPath, buildDir, rawCommand, depfilePlaceholder)
|
||||||
|
|
||||||
ruleParams := blueprint.RuleParams{
|
ruleParams := blueprint.RuleParams{
|
||||||
Command: sandboxCommand,
|
Command: sandboxCommand,
|
||||||
@@ -269,7 +286,7 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
args := []string{"allouts"}
|
args := []string{"allouts"}
|
||||||
if g.properties.Depfile {
|
if g.properties.Depfile {
|
||||||
ruleParams.Deps = blueprint.DepsGCC
|
ruleParams.Deps = blueprint.DepsGCC
|
||||||
args = append(args, "depfile")
|
args = append(args, "depfileArgs")
|
||||||
}
|
}
|
||||||
g.rule = ctx.Rule(pctx, "generator", ruleParams, args...)
|
g.rule = ctx.Rule(pctx, "generator", ruleParams, args...)
|
||||||
|
|
||||||
@@ -289,6 +306,11 @@ func (g *Module) generateSourceFile(ctx android.ModuleContext, task generateTask
|
|||||||
desc += " " + task.out[0].Base()
|
desc += " " + task.out[0].Base()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var depFile android.ModuleGenPath
|
||||||
|
if g.properties.Depfile {
|
||||||
|
depFile = android.PathForModuleGen(ctx, task.out[0].Rel()+".d")
|
||||||
|
}
|
||||||
|
|
||||||
params := android.BuildParams{
|
params := android.BuildParams{
|
||||||
Rule: g.rule,
|
Rule: g.rule,
|
||||||
Description: "generate",
|
Description: "generate",
|
||||||
@@ -301,9 +323,10 @@ func (g *Module) generateSourceFile(ctx android.ModuleContext, task generateTask
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
if g.properties.Depfile {
|
if g.properties.Depfile {
|
||||||
depfile := android.GenPathWithExt(ctx, "", task.out[0], task.out[0].Ext()+".d")
|
params.Depfile = android.PathForModuleGen(ctx, task.out[0].Rel()+".d")
|
||||||
params.Depfile = depfile
|
params.Args["depfileArgs"] = "--depfile-out " + depFile.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Build(pctx, params)
|
ctx.Build(pctx, params)
|
||||||
|
|
||||||
for _, outputFile := range task.out {
|
for _, outputFile := range task.out {
|
||||||
|
Reference in New Issue
Block a user