Support multiple rsp files in RuleBuilder
The lint rule is manually creating a second rsp file because Ninja only supports on per rule. Move the support into RuleBuilder so that it can apply the same rewrites that it does to the primary one. Test: TestRuleBuilder_Build Change-Id: Iec250a2d60e74ccf1b4ad085a960fec6867ea559
This commit is contained in:
parent
e55bd423df
commit
ce3a51dc96
|
@ -409,30 +409,21 @@ func (r *RuleBuilder) Tools() Paths {
|
|||
func (r *RuleBuilder) RspFileInputs() Paths {
|
||||
var rspFileInputs Paths
|
||||
for _, c := range r.commands {
|
||||
if c.rspFileInputs != nil {
|
||||
if rspFileInputs != nil {
|
||||
panic("Multiple commands in a rule may not have rsp file inputs")
|
||||
}
|
||||
rspFileInputs = c.rspFileInputs
|
||||
for _, rspFile := range c.rspFiles {
|
||||
rspFileInputs = append(rspFileInputs, rspFile.paths...)
|
||||
}
|
||||
}
|
||||
|
||||
return rspFileInputs
|
||||
}
|
||||
|
||||
// RspFile returns the path to the rspfile that was passed to the RuleBuilderCommand.FlagWithRspFileInputList method.
|
||||
func (r *RuleBuilder) RspFile() WritablePath {
|
||||
var rspFile WritablePath
|
||||
func (r *RuleBuilder) rspFiles() []rspFileAndPaths {
|
||||
var rspFiles []rspFileAndPaths
|
||||
for _, c := range r.commands {
|
||||
if c.rspFile != nil {
|
||||
if rspFile != nil {
|
||||
panic("Multiple commands in a rule may not have rsp file inputs")
|
||||
}
|
||||
rspFile = c.rspFile
|
||||
}
|
||||
rspFiles = append(rspFiles, c.rspFiles...)
|
||||
}
|
||||
|
||||
return rspFile
|
||||
return rspFiles
|
||||
}
|
||||
|
||||
// Commands returns a slice containing the built command line for each call to RuleBuilder.Command.
|
||||
|
@ -501,8 +492,7 @@ func (r *RuleBuilder) Build(name string, desc string) {
|
|||
commands := r.Commands()
|
||||
outputs := r.Outputs()
|
||||
inputs := r.Inputs()
|
||||
rspFileInputs := r.RspFileInputs()
|
||||
rspFilePath := r.RspFile()
|
||||
rspFiles := r.rspFiles()
|
||||
|
||||
if len(commands) == 0 {
|
||||
return
|
||||
|
@ -556,10 +546,11 @@ func (r *RuleBuilder) Build(name string, desc string) {
|
|||
})
|
||||
}
|
||||
|
||||
// If using an rsp file copy it into the sbox directory.
|
||||
if rspFilePath != nil {
|
||||
// If using rsp files copy them and their contents into the sbox directory with
|
||||
// the appropriate path mappings.
|
||||
for _, rspFile := range rspFiles {
|
||||
command.RspFiles = append(command.RspFiles, &sbox_proto.RspFile{
|
||||
File: proto.String(rspFilePath.String()),
|
||||
File: proto.String(rspFile.file.String()),
|
||||
// These have to match the logic in sboxPathForInputRel
|
||||
PathMappings: []*sbox_proto.PathMapping{
|
||||
{
|
||||
|
@ -641,9 +632,9 @@ func (r *RuleBuilder) Build(name string, desc string) {
|
|||
remoteInputs = append(remoteInputs, inputs...)
|
||||
remoteInputs = append(remoteInputs, tools...)
|
||||
|
||||
if rspFilePath != nil {
|
||||
remoteInputs = append(remoteInputs, rspFilePath)
|
||||
remoteRspFiles = append(remoteRspFiles, rspFilePath)
|
||||
for _, rspFile := range rspFiles {
|
||||
remoteInputs = append(remoteInputs, rspFile.file)
|
||||
remoteRspFiles = append(remoteRspFiles, rspFile.file)
|
||||
}
|
||||
|
||||
if len(remoteInputs) > 0 {
|
||||
|
@ -673,12 +664,24 @@ func (r *RuleBuilder) Build(name string, desc string) {
|
|||
implicitOutputs := outputs[1:]
|
||||
|
||||
var rspFile, rspFileContent string
|
||||
if rspFilePath != nil {
|
||||
rspFile = rspFilePath.String()
|
||||
var rspFileInputs Paths
|
||||
if len(rspFiles) > 0 {
|
||||
// The first rsp files uses Ninja's rsp file support for the rule
|
||||
rspFile = rspFiles[0].file.String()
|
||||
// Use "$in" for rspFileContent to avoid duplicating the list of files in the dependency
|
||||
// list and in the contents of the rsp file. Inputs to the rule that are not in the
|
||||
// rsp file will be listed in Implicits instead of Inputs so they don't show up in "$in".
|
||||
rspFileContent = "$in"
|
||||
rspFileInputs = append(rspFileInputs, rspFiles[0].paths...)
|
||||
|
||||
for _, rspFile := range rspFiles[1:] {
|
||||
// Any additional rsp files need an extra rule to write the file.
|
||||
writeRspFileRule(r.ctx, rspFile.file, rspFile.paths)
|
||||
// The main rule needs to depend on the inputs listed in the extra rsp file.
|
||||
inputs = append(inputs, rspFile.paths...)
|
||||
// The main rule needs to depend on the extra rsp file.
|
||||
inputs = append(inputs, rspFile.file)
|
||||
}
|
||||
}
|
||||
|
||||
var pool blueprint.Pool
|
||||
|
@ -729,8 +732,12 @@ type RuleBuilderCommand struct {
|
|||
depFiles WritablePaths
|
||||
tools Paths
|
||||
packagedTools []PackagingSpec
|
||||
rspFileInputs Paths
|
||||
rspFile WritablePath
|
||||
rspFiles []rspFileAndPaths
|
||||
}
|
||||
|
||||
type rspFileAndPaths struct {
|
||||
file WritablePath
|
||||
paths Paths
|
||||
}
|
||||
|
||||
func (c *RuleBuilderCommand) addInput(path Path) string {
|
||||
|
@ -1174,22 +1181,19 @@ func (c *RuleBuilderCommand) FlagWithDepFile(flag string, path WritablePath) *Ru
|
|||
return c.Text(flag + c.PathForOutput(path))
|
||||
}
|
||||
|
||||
// FlagWithRspFileInputList adds the specified flag and path to an rspfile to the command line, with no separator
|
||||
// between them. The paths will be written to the rspfile. If sbox is enabled, the rspfile must
|
||||
// be outside the sbox directory.
|
||||
// FlagWithRspFileInputList adds the specified flag and path to an rspfile to the command line, with
|
||||
// no separator between them. The paths will be written to the rspfile. If sbox is enabled, the
|
||||
// rspfile must be outside the sbox directory. The first use of FlagWithRspFileInputList in any
|
||||
// RuleBuilderCommand of a RuleBuilder will use Ninja's rsp file support for the rule, additional
|
||||
// uses will result in an auxiliary rules to write the rspFile contents.
|
||||
func (c *RuleBuilderCommand) FlagWithRspFileInputList(flag string, rspFile WritablePath, paths Paths) *RuleBuilderCommand {
|
||||
if c.rspFileInputs != nil {
|
||||
panic("FlagWithRspFileInputList cannot be called if rsp file inputs have already been provided")
|
||||
}
|
||||
|
||||
// Use an empty slice if paths is nil, the non-nil slice is used as an indicator that the rsp file must be
|
||||
// generated.
|
||||
if paths == nil {
|
||||
paths = Paths{}
|
||||
}
|
||||
|
||||
c.rspFileInputs = paths
|
||||
c.rspFile = rspFile
|
||||
c.rspFiles = append(c.rspFiles, rspFileAndPaths{rspFile, paths})
|
||||
|
||||
if c.rule.sbox {
|
||||
if _, isRel, _ := maybeRelErr(c.rule.outDir.String(), rspFile.String()); isRel {
|
||||
|
|
|
@ -489,8 +489,9 @@ type testRuleBuilderModule struct {
|
|||
properties struct {
|
||||
Srcs []string
|
||||
|
||||
Restat bool
|
||||
Sbox bool
|
||||
Restat bool
|
||||
Sbox bool
|
||||
Sbox_inputs bool
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -499,9 +500,15 @@ func (t *testRuleBuilderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
|||
out := PathForModuleOut(ctx, "gen", ctx.ModuleName())
|
||||
outDep := PathForModuleOut(ctx, "gen", ctx.ModuleName()+".d")
|
||||
outDir := PathForModuleOut(ctx, "gen")
|
||||
rspFile := PathForModuleOut(ctx, "rsp")
|
||||
rspFile2 := PathForModuleOut(ctx, "rsp2")
|
||||
rspFileContents := PathsForSource(ctx, []string{"rsp_in"})
|
||||
rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
|
||||
manifestPath := PathForModuleOut(ctx, "sbox.textproto")
|
||||
|
||||
testRuleBuilder_Build(ctx, in, out, outDep, outDir, manifestPath, t.properties.Restat, t.properties.Sbox)
|
||||
testRuleBuilder_Build(ctx, in, out, outDep, outDir, manifestPath, t.properties.Restat,
|
||||
t.properties.Sbox, t.properties.Sbox_inputs, rspFile, rspFileContents,
|
||||
rspFile2, rspFileContents2)
|
||||
}
|
||||
|
||||
type testRuleBuilderSingleton struct{}
|
||||
|
@ -515,18 +522,35 @@ func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) {
|
|||
out := PathForOutput(ctx, "singleton/gen/baz")
|
||||
outDep := PathForOutput(ctx, "singleton/gen/baz.d")
|
||||
outDir := PathForOutput(ctx, "singleton/gen")
|
||||
rspFile := PathForOutput(ctx, "singleton/rsp")
|
||||
rspFile2 := PathForOutput(ctx, "singleton/rsp2")
|
||||
rspFileContents := PathsForSource(ctx, []string{"rsp_in"})
|
||||
rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
|
||||
manifestPath := PathForOutput(ctx, "singleton/sbox.textproto")
|
||||
testRuleBuilder_Build(ctx, Paths{in}, out, outDep, outDir, manifestPath, true, false)
|
||||
testRuleBuilder_Build(ctx, Paths{in}, out, outDep, outDir, manifestPath, true, false, false,
|
||||
rspFile, rspFileContents, rspFile2, rspFileContents2)
|
||||
}
|
||||
|
||||
func testRuleBuilder_Build(ctx BuilderContext, in Paths, out, outDep, outDir, manifestPath WritablePath, restat, sbox bool) {
|
||||
func testRuleBuilder_Build(ctx BuilderContext, in Paths, out, outDep, outDir, manifestPath WritablePath,
|
||||
restat, sbox, sboxInputs bool,
|
||||
rspFile WritablePath, rspFileContents Paths, rspFile2 WritablePath, rspFileContents2 Paths) {
|
||||
|
||||
rule := NewRuleBuilder(pctx, ctx)
|
||||
|
||||
if sbox {
|
||||
rule.Sbox(outDir, manifestPath)
|
||||
if sboxInputs {
|
||||
rule.SandboxInputs()
|
||||
}
|
||||
}
|
||||
|
||||
rule.Command().Tool(PathForSource(ctx, "cp")).Inputs(in).Output(out).ImplicitDepFile(outDep)
|
||||
rule.Command().
|
||||
Tool(PathForSource(ctx, "cp")).
|
||||
Inputs(in).
|
||||
Output(out).
|
||||
ImplicitDepFile(outDep).
|
||||
FlagWithRspFileInputList("@", rspFile, rspFileContents).
|
||||
FlagWithRspFileInputList("@", rspFile2, rspFileContents2)
|
||||
|
||||
if restat {
|
||||
rule.Restat()
|
||||
|
@ -557,6 +581,12 @@ func TestRuleBuilder_Build(t *testing.T) {
|
|||
srcs: ["bar"],
|
||||
sbox: true,
|
||||
}
|
||||
rule_builder_test {
|
||||
name: "foo_sbox_inputs",
|
||||
srcs: ["bar"],
|
||||
sbox: true,
|
||||
sbox_inputs: true,
|
||||
}
|
||||
`
|
||||
|
||||
result := GroupFixturePreparers(
|
||||
|
@ -565,7 +595,10 @@ func TestRuleBuilder_Build(t *testing.T) {
|
|||
fs.AddToFixture(),
|
||||
).RunTest(t)
|
||||
|
||||
check := func(t *testing.T, params TestingBuildParams, wantCommand, wantOutput, wantDepfile string, wantRestat bool, extraImplicits, extraCmdDeps []string) {
|
||||
check := func(t *testing.T, params TestingBuildParams, rspFile2Params TestingBuildParams,
|
||||
wantCommand, wantOutput, wantDepfile, wantRspFile, wantRspFile2 string,
|
||||
wantRestat bool, extraImplicits, extraCmdDeps []string) {
|
||||
|
||||
t.Helper()
|
||||
command := params.RuleParams.Command
|
||||
re := regexp.MustCompile(" # hash of input list: [a-z0-9]*$")
|
||||
|
@ -578,9 +611,19 @@ func TestRuleBuilder_Build(t *testing.T) {
|
|||
|
||||
AssertBoolEquals(t, "RuleParams.Restat", wantRestat, params.RuleParams.Restat)
|
||||
|
||||
wantInputs := []string{"rsp_in"}
|
||||
AssertArrayString(t, "Inputs", wantInputs, params.Inputs.Strings())
|
||||
|
||||
wantImplicits := append([]string{"bar"}, extraImplicits...)
|
||||
// The second rsp file and the files listed in it should be in implicits
|
||||
wantImplicits = append(wantImplicits, "rsp_in2", wantRspFile2)
|
||||
AssertPathsRelativeToTopEquals(t, "Implicits", wantImplicits, params.Implicits)
|
||||
|
||||
wantRspFileContent := "$in"
|
||||
AssertStringEquals(t, "RspfileContent", wantRspFileContent, params.RuleParams.RspfileContent)
|
||||
|
||||
AssertStringEquals(t, "Rspfile", wantRspFile, params.RuleParams.Rspfile)
|
||||
|
||||
AssertPathRelativeToTopEquals(t, "Output", wantOutput, params.Output)
|
||||
|
||||
if len(params.ImplicitOutputs) != 0 {
|
||||
|
@ -592,18 +635,42 @@ func TestRuleBuilder_Build(t *testing.T) {
|
|||
if params.Deps != blueprint.DepsGCC {
|
||||
t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps)
|
||||
}
|
||||
|
||||
rspFile2Content := ContentFromFileRuleForTests(t, rspFile2Params)
|
||||
AssertStringEquals(t, "rspFile2 content", "rsp_in2\n", rspFile2Content)
|
||||
}
|
||||
|
||||
t.Run("module", func(t *testing.T) {
|
||||
outFile := "out/soong/.intermediates/foo/gen/foo"
|
||||
check(t, result.ModuleForTests("foo", "").Rule("rule").RelativeToTop(),
|
||||
"cp bar "+outFile,
|
||||
outFile, outFile+".d", true, nil, nil)
|
||||
rspFile := "out/soong/.intermediates/foo/rsp"
|
||||
rspFile2 := "out/soong/.intermediates/foo/rsp2"
|
||||
module := result.ModuleForTests("foo", "")
|
||||
check(t, module.Rule("rule").RelativeToTop(), module.Output(rspFile2).RelativeToTop(),
|
||||
"cp bar "+outFile+" @"+rspFile+" @"+rspFile2,
|
||||
outFile, outFile+".d", rspFile, rspFile2, true, nil, nil)
|
||||
})
|
||||
t.Run("sbox", func(t *testing.T) {
|
||||
outDir := "out/soong/.intermediates/foo_sbox"
|
||||
outFile := filepath.Join(outDir, "gen/foo_sbox")
|
||||
depFile := filepath.Join(outDir, "gen/foo_sbox.d")
|
||||
rspFile := filepath.Join(outDir, "rsp")
|
||||
rspFile2 := filepath.Join(outDir, "rsp2")
|
||||
manifest := filepath.Join(outDir, "sbox.textproto")
|
||||
sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox")
|
||||
sandboxPath := shared.TempDirForOutDir("out/soong")
|
||||
|
||||
cmd := `rm -rf ` + outDir + `/gen && ` +
|
||||
sbox + ` --sandbox-path ` + sandboxPath + ` --manifest ` + manifest
|
||||
module := result.ModuleForTests("foo_sbox", "")
|
||||
check(t, module.Output("gen/foo_sbox").RelativeToTop(), module.Output(rspFile2).RelativeToTop(),
|
||||
cmd, outFile, depFile, rspFile, rspFile2, false, []string{manifest}, []string{sbox})
|
||||
})
|
||||
t.Run("sbox_inputs", func(t *testing.T) {
|
||||
outDir := "out/soong/.intermediates/foo_sbox_inputs"
|
||||
outFile := filepath.Join(outDir, "gen/foo_sbox_inputs")
|
||||
depFile := filepath.Join(outDir, "gen/foo_sbox_inputs.d")
|
||||
rspFile := filepath.Join(outDir, "rsp")
|
||||
rspFile2 := filepath.Join(outDir, "rsp2")
|
||||
manifest := filepath.Join(outDir, "sbox.textproto")
|
||||
sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox")
|
||||
sandboxPath := shared.TempDirForOutDir("out/soong")
|
||||
|
@ -611,13 +678,18 @@ func TestRuleBuilder_Build(t *testing.T) {
|
|||
cmd := `rm -rf ` + outDir + `/gen && ` +
|
||||
sbox + ` --sandbox-path ` + sandboxPath + ` --manifest ` + manifest
|
||||
|
||||
check(t, result.ModuleForTests("foo_sbox", "").Output("gen/foo_sbox").RelativeToTop(),
|
||||
cmd, outFile, depFile, false, []string{manifest}, []string{sbox})
|
||||
module := result.ModuleForTests("foo_sbox_inputs", "")
|
||||
check(t, module.Output("gen/foo_sbox_inputs").RelativeToTop(), module.Output(rspFile2).RelativeToTop(),
|
||||
cmd, outFile, depFile, rspFile, rspFile2, false, []string{manifest}, []string{sbox})
|
||||
})
|
||||
t.Run("singleton", func(t *testing.T) {
|
||||
outFile := filepath.Join("out/soong/singleton/gen/baz")
|
||||
check(t, result.SingletonForTests("rule_builder_test").Rule("rule").RelativeToTop(),
|
||||
"cp bar "+outFile, outFile, outFile+".d", true, nil, nil)
|
||||
rspFile := filepath.Join("out/soong/singleton/rsp")
|
||||
rspFile2 := filepath.Join("out/soong/singleton/rsp2")
|
||||
singleton := result.SingletonForTests("rule_builder_test")
|
||||
check(t, singleton.Rule("rule").RelativeToTop(), singleton.Output(rspFile2).RelativeToTop(),
|
||||
"cp bar "+outFile+" @"+rspFile+" @"+rspFile2,
|
||||
outFile, outFile+".d", rspFile, rspFile2, true, nil, nil)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -628,7 +628,7 @@ prebuilt_stubs_sources {
|
|||
}
|
||||
|
||||
t.Run("empty/missing directory", func(t *testing.T) {
|
||||
test(t, "empty-directory", []string{})
|
||||
test(t, "empty-directory", nil)
|
||||
})
|
||||
|
||||
t.Run("non-empty set of sources", func(t *testing.T) {
|
||||
|
|
Loading…
Reference in New Issue