Merge "Automate dependency on inputs of genrule module type." am: 888d92e941
am: 7550d065da
Change-Id: I0f56b7be4f3ff9bae18c23ea610c098277503e3b
This commit is contained in:
@@ -36,6 +36,7 @@ var (
|
|||||||
outputRoot string
|
outputRoot string
|
||||||
keepOutDir bool
|
keepOutDir bool
|
||||||
depfileOut string
|
depfileOut string
|
||||||
|
inputHash string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -51,6 +52,8 @@ func init() {
|
|||||||
flag.StringVar(&depfileOut, "depfile-out", "",
|
flag.StringVar(&depfileOut, "depfile-out", "",
|
||||||
"file path of the depfile to generate. This value will replace '__SBOX_DEPFILE__' in the command and will be treated as an output but won't be added to __SBOX_OUT_FILES__")
|
"file path of the depfile to generate. This value will replace '__SBOX_DEPFILE__' in the command and will be treated as an output but won't be added to __SBOX_OUT_FILES__")
|
||||||
|
|
||||||
|
flag.StringVar(&inputHash, "input-hash", "",
|
||||||
|
"This option is ignored. Typical usage is to supply a hash of the list of input names so that the module will be rebuilt if the list (and thus the hash) changes.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func usageViolation(violation string) {
|
func usageViolation(violation string) {
|
||||||
@@ -59,7 +62,7 @@ func usageViolation(violation string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr,
|
fmt.Fprintf(os.Stderr,
|
||||||
"Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> [--depfile-out depFile] <outputFile> [<outputFile>...]\n"+
|
"Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> [--depfile-out depFile] [--input-hash hash] <outputFile> [<outputFile>...]\n"+
|
||||||
"\n"+
|
"\n"+
|
||||||
"Deletes <outputRoot>,"+
|
"Deletes <outputRoot>,"+
|
||||||
"runs <commandToRun>,"+
|
"runs <commandToRun>,"+
|
||||||
|
@@ -26,6 +26,7 @@ import (
|
|||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
"android/soong/shared"
|
"android/soong/shared"
|
||||||
|
"crypto/sha256"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -309,6 +310,7 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
addLocationLabel(out.Rel(), []string{filepath.Join("__SBOX_OUT_DIR__", out.Rel())})
|
addLocationLabel(out.Rel(), []string{filepath.Join("__SBOX_OUT_DIR__", out.Rel())})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
referencedIn := false
|
||||||
referencedDepfile := false
|
referencedDepfile := false
|
||||||
|
|
||||||
rawCommand, err := android.ExpandNinjaEscaped(task.cmd, func(name string) (string, bool, error) {
|
rawCommand, err := android.ExpandNinjaEscaped(task.cmd, func(name string) (string, bool, error) {
|
||||||
@@ -333,6 +335,7 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
}
|
}
|
||||||
return locationLabels[firstLabel][0], false, nil
|
return locationLabels[firstLabel][0], false, nil
|
||||||
case "in":
|
case "in":
|
||||||
|
referencedIn = true
|
||||||
return "${in}", true, nil
|
return "${in}", true, nil
|
||||||
case "out":
|
case "out":
|
||||||
return "__SBOX_OUT_FILES__", false, nil
|
return "__SBOX_OUT_FILES__", false, nil
|
||||||
@@ -398,8 +401,16 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
// Escape the command for the shell
|
// Escape the command for the shell
|
||||||
rawCommand = "'" + strings.Replace(rawCommand, "'", `'\''`, -1) + "'"
|
rawCommand = "'" + strings.Replace(rawCommand, "'", `'\''`, -1) + "'"
|
||||||
g.rawCommands = append(g.rawCommands, rawCommand)
|
g.rawCommands = append(g.rawCommands, rawCommand)
|
||||||
sandboxCommand := fmt.Sprintf("rm -rf %s && $sboxCmd --sandbox-path %s --output-root %s -c %s %s $allouts",
|
|
||||||
task.genDir, sandboxPath, task.genDir, rawCommand, depfilePlaceholder)
|
sandboxCommand := fmt.Sprintf("rm -rf %s && $sboxCmd --sandbox-path %s --output-root %s",
|
||||||
|
task.genDir, sandboxPath, task.genDir)
|
||||||
|
|
||||||
|
if !referencedIn {
|
||||||
|
sandboxCommand = sandboxCommand + hashSrcFiles(srcFiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
sandboxCommand = sandboxCommand + fmt.Sprintf(" -c %s %s $allouts",
|
||||||
|
rawCommand, depfilePlaceholder)
|
||||||
|
|
||||||
ruleParams := blueprint.RuleParams{
|
ruleParams := blueprint.RuleParams{
|
||||||
Command: sandboxCommand,
|
Command: sandboxCommand,
|
||||||
@@ -463,6 +474,14 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hashSrcFiles(srcFiles android.Paths) string {
|
||||||
|
h := sha256.New()
|
||||||
|
for _, src := range srcFiles {
|
||||||
|
h.Write([]byte(src.String()))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(" --input-hash %x", h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Module) generateSourceFile(ctx android.ModuleContext, task generateTask, rule blueprint.Rule) {
|
func (g *Module) generateSourceFile(ctx android.ModuleContext, task generateTask, rule blueprint.Rule) {
|
||||||
desc := "generate"
|
desc := "generate"
|
||||||
if len(task.out) == 0 {
|
if len(task.out) == 0 {
|
||||||
|
@@ -502,6 +502,93 @@ func TestGenruleCmd(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenruleHashInputs(t *testing.T) {
|
||||||
|
|
||||||
|
// The basic idea here is to verify that the sbox command (which is
|
||||||
|
// in the Command field of the generate rule) contains a hash of the
|
||||||
|
// inputs, but only if $(in) is not referenced in the genrule cmd
|
||||||
|
// property.
|
||||||
|
|
||||||
|
// By including a hash of the inputs, we cause the rule to re-run if
|
||||||
|
// the list of inputs changes (because the sbox command changes).
|
||||||
|
|
||||||
|
// However, if the genrule cmd property already contains $(in), then
|
||||||
|
// the dependency is already expressed, so we don't need to include the
|
||||||
|
// hash in that case.
|
||||||
|
|
||||||
|
bp := `
|
||||||
|
genrule {
|
||||||
|
name: "hash0",
|
||||||
|
srcs: ["in1.txt", "in2.txt"],
|
||||||
|
out: ["out"],
|
||||||
|
cmd: "echo foo > $(out)",
|
||||||
|
}
|
||||||
|
genrule {
|
||||||
|
name: "hash1",
|
||||||
|
srcs: ["*.txt"],
|
||||||
|
out: ["out"],
|
||||||
|
cmd: "echo bar > $(out)",
|
||||||
|
}
|
||||||
|
genrule {
|
||||||
|
name: "hash2",
|
||||||
|
srcs: ["*.txt"],
|
||||||
|
out: ["out"],
|
||||||
|
cmd: "echo $(in) > $(out)",
|
||||||
|
}
|
||||||
|
`
|
||||||
|
testcases := []struct {
|
||||||
|
name string
|
||||||
|
expectedHash string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "hash0",
|
||||||
|
// sha256 value obtained from: echo -n 'in1.txtin2.txt' | sha256sum
|
||||||
|
expectedHash: "031097e11e0a8c822c960eb9742474f46336360a515744000d086d94335a9cb9",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "hash1",
|
||||||
|
// sha256 value obtained from: echo -n 'in1.txtin2.txtin3.txt' | sha256sum
|
||||||
|
expectedHash: "de5d22a4a7ab50d250cc59fcdf7a7e0775790d270bfca3a7a9e1f18a70dd996c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "hash2",
|
||||||
|
// $(in) is present, option should not appear
|
||||||
|
expectedHash: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
config := testConfig(bp, nil)
|
||||||
|
ctx := testContext(config)
|
||||||
|
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
|
||||||
|
if errs == nil {
|
||||||
|
_, errs = ctx.PrepareBuildActions(config)
|
||||||
|
}
|
||||||
|
if errs != nil {
|
||||||
|
t.Fatal(errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testcases {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
gen := ctx.ModuleForTests(test.name, "")
|
||||||
|
command := gen.Rule("generator").RuleParams.Command
|
||||||
|
|
||||||
|
if len(test.expectedHash) > 0 {
|
||||||
|
// We add spaces before and after to make sure that
|
||||||
|
// this option doesn't abutt another sbox option.
|
||||||
|
expectedInputHashOption := " --input-hash " + test.expectedHash + " "
|
||||||
|
|
||||||
|
if !strings.Contains(command, expectedInputHashOption) {
|
||||||
|
t.Errorf("Expected command \"%s\" to contain \"%s\"", command, expectedInputHashOption)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if strings.Contains(command, "--input-hash") {
|
||||||
|
t.Errorf("Unexpected \"--input-hash\" found in command: \"%s\"", command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGenSrcs(t *testing.T) {
|
func TestGenSrcs(t *testing.T) {
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
name string
|
name string
|
||||||
|
Reference in New Issue
Block a user