Rewrite depfile from sbox to stay reproducible

sbox will generate a random directory for the output root, and most
tools will encode that directory name in the output target of the
depfile.

So embed the library from dep_fixer into sbox so that it can rewrite the
output filename to a static (reproducible) value. Ninja doesn't care
what that value is, so it's just "outputfile".

Also fix up rule_builder to actually tell sbox about the depfile.

Bug: 144948629
Test: mmma system/iorap; check the contents of:
out/soong/.intermediates/system/iorap/libiorap-binder/android_arm_armv7-a-neon_core_static/gen/aidl/system/iorap/binder/com/google/android/startop/iorap/IIorap.cpp.d

Change-Id: I3640a2e8b0c034f143a35e398a8418a6d621b265
Merged-In: I3640a2e8b0c034f143a35e398a8418a6d621b265
(cherry picked from commit c89b6f1981)
This commit is contained in:
Dan Willemsen 2019-08-29 14:47:40 -07:00 committed by Colin Cross
parent 0ce5d05f76
commit db14db3a06
9 changed files with 64 additions and 21 deletions

View File

@ -342,10 +342,6 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string
sboxOutputs[i] = "__SBOX_OUT_DIR__/" + Rel(ctx, r.sboxOutDir.String(), output.String()) sboxOutputs[i] = "__SBOX_OUT_DIR__/" + Rel(ctx, r.sboxOutDir.String(), output.String())
} }
if depFile != nil {
sboxOutputs = append(sboxOutputs, "__SBOX_OUT_DIR__/"+Rel(ctx, r.sboxOutDir.String(), depFile.String()))
}
commandString = proptools.ShellEscape(commandString) commandString = proptools.ShellEscape(commandString)
if !strings.HasPrefix(commandString, `'`) { if !strings.HasPrefix(commandString, `'`) {
commandString = `'` + commandString + `'` commandString = `'` + commandString + `'`
@ -355,8 +351,13 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string
sboxCmd.Tool(ctx.Config().HostToolPath(ctx, "sbox")). sboxCmd.Tool(ctx.Config().HostToolPath(ctx, "sbox")).
Flag("-c").Text(commandString). Flag("-c").Text(commandString).
Flag("--sandbox-path").Text(shared.TempDirForOutDir(PathForOutput(ctx).String())). Flag("--sandbox-path").Text(shared.TempDirForOutDir(PathForOutput(ctx).String())).
Flag("--output-root").Text(r.sboxOutDir.String()). Flag("--output-root").Text(r.sboxOutDir.String())
Flags(sboxOutputs)
if depFile != nil {
sboxCmd.Flag("--depfile-out").Text(depFile.String())
}
sboxCmd.Flags(sboxOutputs)
commandString = string(sboxCmd.buf) commandString = string(sboxCmd.buf)
tools = append(tools, sboxCmd.tools...) tools = append(tools, sboxCmd.tools...)

View File

@ -454,6 +454,7 @@ func TestRuleBuilder_Build(t *testing.T) {
FailIfErrored(t, errs) FailIfErrored(t, errs)
check := func(t *testing.T, params TestingBuildParams, wantCommand, wantOutput, wantDepfile string, wantRestat bool, extraCmdDeps []string) { check := func(t *testing.T, params TestingBuildParams, wantCommand, wantOutput, wantDepfile string, wantRestat bool, extraCmdDeps []string) {
t.Helper()
if params.RuleParams.Command != wantCommand { if params.RuleParams.Command != wantCommand {
t.Errorf("\nwant RuleParams.Command = %q\n got %q", wantCommand, params.RuleParams.Command) t.Errorf("\nwant RuleParams.Command = %q\n got %q", wantCommand, params.RuleParams.Command)
} }
@ -497,13 +498,14 @@ func TestRuleBuilder_Build(t *testing.T) {
t.Run("sbox", func(t *testing.T) { t.Run("sbox", func(t *testing.T) {
outDir := filepath.Join(buildDir, ".intermediates", "foo_sbox") outDir := filepath.Join(buildDir, ".intermediates", "foo_sbox")
outFile := filepath.Join(outDir, "foo_sbox") outFile := filepath.Join(outDir, "foo_sbox")
depFile := filepath.Join(outDir, "foo_sbox.d")
sbox := filepath.Join(buildDir, "host", config.PrebuiltOS(), "bin/sbox") sbox := filepath.Join(buildDir, "host", config.PrebuiltOS(), "bin/sbox")
sandboxPath := shared.TempDirForOutDir(buildDir) sandboxPath := shared.TempDirForOutDir(buildDir)
cmd := sbox + ` -c 'cp bar __SBOX_OUT_DIR__/foo_sbox' --sandbox-path ` + sandboxPath + " --output-root " + outDir + " __SBOX_OUT_DIR__/foo_sbox __SBOX_OUT_DIR__/foo_sbox.d" cmd := sbox + ` -c 'cp bar __SBOX_OUT_DIR__/foo_sbox' --sandbox-path ` + sandboxPath + " --output-root " + outDir + " --depfile-out " + depFile + " __SBOX_OUT_DIR__/foo_sbox"
check(t, ctx.ModuleForTests("foo_sbox", "").Rule("rule"), check(t, ctx.ModuleForTests("foo_sbox", "").Rule("rule"),
cmd, outFile, outFile+".d", false, []string{sbox}) cmd, outFile, depFile, false, []string{sbox})
}) })
t.Run("singleton", func(t *testing.T) { t.Run("singleton", func(t *testing.T) {
outFile := filepath.Join(buildDir, "baz") outFile := filepath.Join(buildDir, "baz")

View File

@ -14,10 +14,6 @@
blueprint_go_binary { blueprint_go_binary {
name: "dep_fixer", name: "dep_fixer",
deps: ["androidmk-parser"], deps: ["soong-makedeps"],
srcs: [ srcs: ["main.go"],
"main.go",
"deps.go",
],
testSrcs: ["deps_test.go"],
} }

View File

@ -25,6 +25,8 @@ import (
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"android/soong/makedeps"
) )
func main() { func main() {
@ -39,7 +41,7 @@ func main() {
log.Fatal("Expected at least one input file as an argument") log.Fatal("Expected at least one input file as an argument")
} }
var mergedDeps *Deps var mergedDeps *makedeps.Deps
var firstInput []byte var firstInput []byte
for i, arg := range flag.Args() { for i, arg := range flag.Args() {
@ -48,7 +50,7 @@ func main() {
log.Fatalf("Error opening %q: %v", arg, err) log.Fatalf("Error opening %q: %v", arg, err)
} }
deps, err := Parse(arg, bytes.NewBuffer(append([]byte(nil), input...))) deps, err := makedeps.Parse(arg, bytes.NewBuffer(append([]byte(nil), input...)))
if err != nil { if err != nil {
log.Fatalf("Failed to parse: %v", err) log.Fatalf("Failed to parse: %v", err)
} }

View File

@ -14,6 +14,7 @@
blueprint_go_binary { blueprint_go_binary {
name: "sbox", name: "sbox",
deps: ["soong-makedeps"],
srcs: [ srcs: [
"sbox.go", "sbox.go",
], ],

View File

@ -15,6 +15,7 @@
package main package main
import ( import (
"bytes"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
@ -25,6 +26,8 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
"android/soong/makedeps"
) )
var ( var (
@ -152,9 +155,6 @@ func run() error {
return err return err
} }
allOutputs = append(allOutputs, sandboxedDepfile) 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) rawCommand = strings.Replace(rawCommand, "__SBOX_DEPFILE__", filepath.Join(tempDir, sandboxedDepfile), -1)
} }
@ -281,6 +281,26 @@ func run() error {
} }
} }
// Rewrite the depfile so that it doesn't include the (randomized) sandbox directory
if depfileOut != "" {
in, err := ioutil.ReadFile(depfileOut)
if err != nil {
return err
}
deps, err := makedeps.Parse(depfileOut, bytes.NewBuffer(in))
if err != nil {
return err
}
deps.Output = "outputfile"
err = ioutil.WriteFile(depfileOut, deps.Print(), 0666)
if err != nil {
return err
}
}
// TODO(jeffrygaston) if a process creates more output files than it declares, should there be a warning? // TODO(jeffrygaston) if a process creates more output files than it declares, should there be a warning?
return nil return nil
} }

21
makedeps/Android.bp Normal file
View File

@ -0,0 +1,21 @@
// Copyright 2019 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.
bootstrap_go_package {
name: "soong-makedeps",
pkgPath: "android/soong/makedeps",
deps: ["androidmk-parser"],
srcs: ["deps.go"],
testSrcs: ["deps_test.go"],
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package main package makedeps
import ( import (
"bytes" "bytes"

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package main package makedeps
import ( import (
"bytes" "bytes"