blob: 6a8a964a1628aa0e5cfde502d943da2756b11007 [file] [log] [blame]
Colin Crossfeec25b2019-01-30 17:32:39 -08001// Copyright 2019 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17import (
Colin Crossda6401b2021-04-21 11:32:19 -070018 "crypto/sha256"
19 "encoding/hex"
Colin Cross758290d2019-02-01 16:42:32 -080020 "fmt"
Colin Crossfeec25b2019-01-30 17:32:39 -080021 "path/filepath"
Colin Cross3d680512020-11-13 16:23:53 -080022 "regexp"
Colin Cross758290d2019-02-01 16:42:32 -080023 "strings"
Colin Crossfeec25b2019-01-30 17:32:39 -080024 "testing"
Dan Willemsen633c5022019-04-12 11:11:38 -070025
26 "github.com/google/blueprint"
27
28 "android/soong/shared"
Colin Crossfeec25b2019-01-30 17:32:39 -080029)
30
Sam Delmerico285b66a2023-09-25 12:13:17 +000031var (
32 pctx_ruleBuilderTest = NewPackageContext("android/soong/rule_builder")
33 pctx_ruleBuilderTestSubContext = NewPackageContext("android/soong/rule_builder/config")
34)
35
36func init() {
37 pctx_ruleBuilderTest.Import("android/soong/rule_builder/config")
38 pctx_ruleBuilderTest.StaticVariable("cmdFlags", "${config.ConfigFlags}")
39 pctx_ruleBuilderTestSubContext.StaticVariable("ConfigFlags", "--some-clang-flag")
40}
41
Colin Crossf1a035e2020-11-16 17:32:30 -080042func builderContext() BuilderContext {
43 return BuilderContextForTesting(TestConfig("out", nil, "", map[string][]byte{
Colin Cross98be1bb2019-12-13 20:41:13 -080044 "ld": nil,
45 "a.o": nil,
46 "b.o": nil,
47 "cp": nil,
48 "a": nil,
49 "b": nil,
50 "ls": nil,
51 "turbine": nil,
52 "java": nil,
53 "javac": nil,
54 }))
Colin Cross69f59a32019-02-15 10:39:37 -080055}
56
Colin Cross758290d2019-02-01 16:42:32 -080057func ExampleRuleBuilder() {
Colin Crossf1a035e2020-11-16 17:32:30 -080058 ctx := builderContext()
Colin Cross758290d2019-02-01 16:42:32 -080059
Colin Crossf1a035e2020-11-16 17:32:30 -080060 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -080061
62 rule.Command().
63 Tool(PathForSource(ctx, "ld")).
64 Inputs(PathsForTesting("a.o", "b.o")).
65 FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -080066 rule.Command().Text("echo success")
67
68 // To add the command to the build graph:
Colin Crossf1a035e2020-11-16 17:32:30 -080069 // rule.Build("link", "link")
Colin Cross758290d2019-02-01 16:42:32 -080070
71 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
72 fmt.Printf("tools: %q\n", rule.Tools())
73 fmt.Printf("inputs: %q\n", rule.Inputs())
74 fmt.Printf("outputs: %q\n", rule.Outputs())
75
76 // Output:
Colin Cross7b6a55f2021-11-09 12:34:39 -080077 // commands: "ld a.o b.o -o out/soong/linked && echo success"
Colin Cross758290d2019-02-01 16:42:32 -080078 // tools: ["ld"]
79 // inputs: ["a.o" "b.o"]
Colin Cross7b6a55f2021-11-09 12:34:39 -080080 // outputs: ["out/soong/linked"]
Colin Cross758290d2019-02-01 16:42:32 -080081}
82
Colin Cross5cb5b092019-02-02 21:25:18 -080083func ExampleRuleBuilder_Temporary() {
Colin Crossf1a035e2020-11-16 17:32:30 -080084 ctx := builderContext()
Colin Cross5cb5b092019-02-02 21:25:18 -080085
Colin Crossf1a035e2020-11-16 17:32:30 -080086 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -080087
88 rule.Command().
89 Tool(PathForSource(ctx, "cp")).
90 Input(PathForSource(ctx, "a")).
91 Output(PathForOutput(ctx, "b"))
92 rule.Command().
93 Tool(PathForSource(ctx, "cp")).
94 Input(PathForOutput(ctx, "b")).
95 Output(PathForOutput(ctx, "c"))
96 rule.Temporary(PathForOutput(ctx, "b"))
Colin Cross5cb5b092019-02-02 21:25:18 -080097
98 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
99 fmt.Printf("tools: %q\n", rule.Tools())
100 fmt.Printf("inputs: %q\n", rule.Inputs())
101 fmt.Printf("outputs: %q\n", rule.Outputs())
102
103 // Output:
Colin Cross7b6a55f2021-11-09 12:34:39 -0800104 // commands: "cp a out/soong/b && cp out/soong/b out/soong/c"
Colin Cross5cb5b092019-02-02 21:25:18 -0800105 // tools: ["cp"]
106 // inputs: ["a"]
Colin Cross7b6a55f2021-11-09 12:34:39 -0800107 // outputs: ["out/soong/c"]
Colin Cross5cb5b092019-02-02 21:25:18 -0800108}
109
110func ExampleRuleBuilder_DeleteTemporaryFiles() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800111 ctx := builderContext()
Colin Cross5cb5b092019-02-02 21:25:18 -0800112
Colin Crossf1a035e2020-11-16 17:32:30 -0800113 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -0800114
115 rule.Command().
116 Tool(PathForSource(ctx, "cp")).
117 Input(PathForSource(ctx, "a")).
118 Output(PathForOutput(ctx, "b"))
119 rule.Command().
120 Tool(PathForSource(ctx, "cp")).
121 Input(PathForOutput(ctx, "b")).
122 Output(PathForOutput(ctx, "c"))
123 rule.Temporary(PathForOutput(ctx, "b"))
Colin Cross5cb5b092019-02-02 21:25:18 -0800124 rule.DeleteTemporaryFiles()
125
126 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
127 fmt.Printf("tools: %q\n", rule.Tools())
128 fmt.Printf("inputs: %q\n", rule.Inputs())
129 fmt.Printf("outputs: %q\n", rule.Outputs())
130
131 // Output:
Colin Cross7b6a55f2021-11-09 12:34:39 -0800132 // commands: "cp a out/soong/b && cp out/soong/b out/soong/c && rm -f out/soong/b"
Colin Cross5cb5b092019-02-02 21:25:18 -0800133 // tools: ["cp"]
134 // inputs: ["a"]
Colin Cross7b6a55f2021-11-09 12:34:39 -0800135 // outputs: ["out/soong/c"]
Colin Cross5cb5b092019-02-02 21:25:18 -0800136}
137
Colin Crossdeabb942019-02-11 14:11:09 -0800138func ExampleRuleBuilder_Installs() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800139 ctx := builderContext()
Colin Crossdeabb942019-02-11 14:11:09 -0800140
Colin Crossf1a035e2020-11-16 17:32:30 -0800141 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -0800142
143 out := PathForOutput(ctx, "linked")
144
145 rule.Command().
146 Tool(PathForSource(ctx, "ld")).
147 Inputs(PathsForTesting("a.o", "b.o")).
148 FlagWithOutput("-o ", out)
149 rule.Install(out, "/bin/linked")
150 rule.Install(out, "/sbin/linked")
Colin Crossdeabb942019-02-11 14:11:09 -0800151
152 fmt.Printf("rule.Installs().String() = %q\n", rule.Installs().String())
153
154 // Output:
Colin Cross7b6a55f2021-11-09 12:34:39 -0800155 // rule.Installs().String() = "out/soong/linked:/bin/linked out/soong/linked:/sbin/linked"
Colin Crossdeabb942019-02-11 14:11:09 -0800156}
157
Colin Cross758290d2019-02-01 16:42:32 -0800158func ExampleRuleBuilderCommand() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800159 ctx := builderContext()
Colin Cross758290d2019-02-01 16:42:32 -0800160
Colin Crossf1a035e2020-11-16 17:32:30 -0800161 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -0800162
Colin Cross758290d2019-02-01 16:42:32 -0800163 // chained
Colin Cross69f59a32019-02-15 10:39:37 -0800164 rule.Command().
165 Tool(PathForSource(ctx, "ld")).
166 Inputs(PathsForTesting("a.o", "b.o")).
167 FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -0800168
169 // unchained
170 cmd := rule.Command()
Colin Cross69f59a32019-02-15 10:39:37 -0800171 cmd.Tool(PathForSource(ctx, "ld"))
172 cmd.Inputs(PathsForTesting("a.o", "b.o"))
173 cmd.FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -0800174
175 // mixed:
Colin Cross69f59a32019-02-15 10:39:37 -0800176 cmd = rule.Command().Tool(PathForSource(ctx, "ld"))
177 cmd.Inputs(PathsForTesting("a.o", "b.o"))
178 cmd.FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -0800179}
180
181func ExampleRuleBuilderCommand_Flag() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800182 ctx := builderContext()
183 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800184 Tool(PathForSource(ctx, "ls")).Flag("-l"))
Colin Cross758290d2019-02-01 16:42:32 -0800185 // Output:
186 // ls -l
187}
188
Colin Cross92b7d582019-03-29 15:32:51 -0700189func ExampleRuleBuilderCommand_Flags() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800190 ctx := builderContext()
191 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross92b7d582019-03-29 15:32:51 -0700192 Tool(PathForSource(ctx, "ls")).Flags([]string{"-l", "-a"}))
193 // Output:
194 // ls -l -a
195}
196
Colin Cross758290d2019-02-01 16:42:32 -0800197func ExampleRuleBuilderCommand_FlagWithArg() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800198 ctx := builderContext()
199 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800200 Tool(PathForSource(ctx, "ls")).
Colin Cross758290d2019-02-01 16:42:32 -0800201 FlagWithArg("--sort=", "time"))
202 // Output:
203 // ls --sort=time
204}
205
Colin Crossc7ed0042019-02-11 14:11:09 -0800206func ExampleRuleBuilderCommand_FlagForEachArg() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800207 ctx := builderContext()
208 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800209 Tool(PathForSource(ctx, "ls")).
Colin Crossc7ed0042019-02-11 14:11:09 -0800210 FlagForEachArg("--sort=", []string{"time", "size"}))
211 // Output:
212 // ls --sort=time --sort=size
213}
214
Colin Cross758290d2019-02-01 16:42:32 -0800215func ExampleRuleBuilderCommand_FlagForEachInput() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800216 ctx := builderContext()
217 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800218 Tool(PathForSource(ctx, "turbine")).
219 FlagForEachInput("--classpath ", PathsForTesting("a.jar", "b.jar")))
Colin Cross758290d2019-02-01 16:42:32 -0800220 // Output:
221 // turbine --classpath a.jar --classpath b.jar
222}
223
224func ExampleRuleBuilderCommand_FlagWithInputList() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800225 ctx := builderContext()
226 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800227 Tool(PathForSource(ctx, "java")).
228 FlagWithInputList("-classpath=", PathsForTesting("a.jar", "b.jar"), ":"))
Colin Cross758290d2019-02-01 16:42:32 -0800229 // Output:
230 // java -classpath=a.jar:b.jar
231}
232
233func ExampleRuleBuilderCommand_FlagWithInput() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800234 ctx := builderContext()
235 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800236 Tool(PathForSource(ctx, "java")).
237 FlagWithInput("-classpath=", PathForSource(ctx, "a")))
Colin Cross758290d2019-02-01 16:42:32 -0800238 // Output:
239 // java -classpath=a
240}
241
242func ExampleRuleBuilderCommand_FlagWithList() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800243 ctx := builderContext()
244 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800245 Tool(PathForSource(ctx, "ls")).
Colin Cross758290d2019-02-01 16:42:32 -0800246 FlagWithList("--sort=", []string{"time", "size"}, ","))
247 // Output:
248 // ls --sort=time,size
249}
250
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700251func ExampleRuleBuilderCommand_FlagWithRspFileInputList() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800252 ctx := builderContext()
253 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700254 Tool(PathForSource(ctx, "javac")).
Colin Cross70c47412021-03-12 17:48:14 -0800255 FlagWithRspFileInputList("@", PathForOutput(ctx, "foo.rsp"), PathsForTesting("a.java", "b.java")).
256 String())
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700257 // Output:
Colin Cross7b6a55f2021-11-09 12:34:39 -0800258 // javac @out/soong/foo.rsp
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700259}
260
261func ExampleRuleBuilderCommand_String() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800262 ctx := builderContext()
263 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700264 Text("FOO=foo").
265 Text("echo $FOO").
266 String())
267 // Output:
268 // FOO=foo echo $FOO
269}
270
Colin Crossfeec25b2019-01-30 17:32:39 -0800271func TestRuleBuilder(t *testing.T) {
Colin Cross69f59a32019-02-15 10:39:37 -0800272 fs := map[string][]byte{
Colin Crossda71eda2020-02-21 16:55:19 -0800273 "dep_fixer": nil,
274 "input": nil,
275 "Implicit": nil,
276 "Input": nil,
277 "OrderOnly": nil,
278 "OrderOnlys": nil,
279 "Tool": nil,
280 "input2": nil,
281 "tool2": nil,
282 "input3": nil,
Colin Cross69f59a32019-02-15 10:39:37 -0800283 }
284
Colin Crossab020a72021-03-12 17:52:23 -0800285 pathCtx := PathContextForTesting(TestConfig("out_local", nil, "", fs))
Colin Crossf1a035e2020-11-16 17:32:30 -0800286 ctx := builderContextForTests{
287 PathContext: pathCtx,
288 }
Colin Cross69f59a32019-02-15 10:39:37 -0800289
Dan Willemsen633c5022019-04-12 11:11:38 -0700290 addCommands := func(rule *RuleBuilder) {
291 cmd := rule.Command().
Colin Crossab020a72021-03-12 17:52:23 -0800292 DepFile(PathForOutput(ctx, "module/DepFile")).
Dan Willemsen633c5022019-04-12 11:11:38 -0700293 Flag("Flag").
294 FlagWithArg("FlagWithArg=", "arg").
Colin Crossab020a72021-03-12 17:52:23 -0800295 FlagWithDepFile("FlagWithDepFile=", PathForOutput(ctx, "module/depfile")).
Dan Willemsen633c5022019-04-12 11:11:38 -0700296 FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")).
Colin Crossab020a72021-03-12 17:52:23 -0800297 FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "module/output")).
298 FlagWithRspFileInputList("FlagWithRspFileInputList=", PathForOutput(ctx, "rsp"),
299 Paths{
300 PathForSource(ctx, "RspInput"),
301 PathForOutput(ctx, "other/RspOutput2"),
302 }).
Dan Willemsen633c5022019-04-12 11:11:38 -0700303 Implicit(PathForSource(ctx, "Implicit")).
Colin Crossab020a72021-03-12 17:52:23 -0800304 ImplicitDepFile(PathForOutput(ctx, "module/ImplicitDepFile")).
305 ImplicitOutput(PathForOutput(ctx, "module/ImplicitOutput")).
Dan Willemsen633c5022019-04-12 11:11:38 -0700306 Input(PathForSource(ctx, "Input")).
Colin Crossab020a72021-03-12 17:52:23 -0800307 Output(PathForOutput(ctx, "module/Output")).
Colin Crossda71eda2020-02-21 16:55:19 -0800308 OrderOnly(PathForSource(ctx, "OrderOnly")).
Colin Crossae89abe2021-04-21 11:45:23 -0700309 Validation(PathForSource(ctx, "Validation")).
Dan Willemsen633c5022019-04-12 11:11:38 -0700310 Text("Text").
311 Tool(PathForSource(ctx, "Tool"))
Colin Crossfeec25b2019-01-30 17:32:39 -0800312
Dan Willemsen633c5022019-04-12 11:11:38 -0700313 rule.Command().
314 Text("command2").
Colin Crossab020a72021-03-12 17:52:23 -0800315 DepFile(PathForOutput(ctx, "module/depfile2")).
Dan Willemsen633c5022019-04-12 11:11:38 -0700316 Input(PathForSource(ctx, "input2")).
Colin Crossab020a72021-03-12 17:52:23 -0800317 Output(PathForOutput(ctx, "module/output2")).
Colin Crossda71eda2020-02-21 16:55:19 -0800318 OrderOnlys(PathsForSource(ctx, []string{"OrderOnlys"})).
Colin Crossae89abe2021-04-21 11:45:23 -0700319 Validations(PathsForSource(ctx, []string{"Validations"})).
Dan Willemsen633c5022019-04-12 11:11:38 -0700320 Tool(PathForSource(ctx, "tool2"))
Colin Crossfeec25b2019-01-30 17:32:39 -0800321
Dan Willemsen633c5022019-04-12 11:11:38 -0700322 // Test updates to the first command after the second command has been started
323 cmd.Text("after command2")
324 // Test updating a command when the previous update did not replace the cmd variable
325 cmd.Text("old cmd")
Colin Crossfeec25b2019-01-30 17:32:39 -0800326
Dan Willemsen633c5022019-04-12 11:11:38 -0700327 // Test a command that uses the output of a previous command as an input
328 rule.Command().
329 Text("command3").
330 Input(PathForSource(ctx, "input3")).
Colin Crossab020a72021-03-12 17:52:23 -0800331 Input(PathForOutput(ctx, "module/output2")).
332 Output(PathForOutput(ctx, "module/output3")).
333 Text(cmd.PathForInput(PathForSource(ctx, "input3"))).
334 Text(cmd.PathForOutput(PathForOutput(ctx, "module/output2")))
Colin Crossfeec25b2019-01-30 17:32:39 -0800335 }
Colin Cross1d2cf042019-03-29 15:33:06 -0700336
Colin Cross69f59a32019-02-15 10:39:37 -0800337 wantInputs := PathsForSource(ctx, []string{"Implicit", "Input", "input", "input2", "input3"})
Colin Crossab020a72021-03-12 17:52:23 -0800338 wantRspFileInputs := Paths{PathForSource(ctx, "RspInput"),
339 PathForOutput(ctx, "other/RspOutput2")}
340 wantOutputs := PathsForOutput(ctx, []string{
Cole Faust9a346f62024-01-18 20:12:02 +0000341 "module/ImplicitOutput", "module/Output", "module/output", "module/output2",
342 "module/output3"})
Colin Crossab020a72021-03-12 17:52:23 -0800343 wantDepFiles := PathsForOutput(ctx, []string{
344 "module/DepFile", "module/depfile", "module/ImplicitDepFile", "module/depfile2"})
Colin Cross69f59a32019-02-15 10:39:37 -0800345 wantTools := PathsForSource(ctx, []string{"Tool", "tool2"})
Colin Crossda71eda2020-02-21 16:55:19 -0800346 wantOrderOnlys := PathsForSource(ctx, []string{"OrderOnly", "OrderOnlys"})
Colin Crossae89abe2021-04-21 11:45:23 -0700347 wantValidations := PathsForSource(ctx, []string{"Validation", "Validations"})
Colin Crossfeec25b2019-01-30 17:32:39 -0800348
Dan Willemsen633c5022019-04-12 11:11:38 -0700349 t.Run("normal", func(t *testing.T) {
Colin Crossf1a035e2020-11-16 17:32:30 -0800350 rule := NewRuleBuilder(pctx, ctx)
Dan Willemsen633c5022019-04-12 11:11:38 -0700351 addCommands(rule)
Colin Cross1d2cf042019-03-29 15:33:06 -0700352
Dan Willemsen633c5022019-04-12 11:11:38 -0700353 wantCommands := []string{
Colin Cross7b6a55f2021-11-09 12:34:39 -0800354 "out_local/soong/module/DepFile Flag FlagWithArg=arg FlagWithDepFile=out_local/soong/module/depfile " +
355 "FlagWithInput=input FlagWithOutput=out_local/soong/module/output FlagWithRspFileInputList=out_local/soong/rsp " +
Cole Faust9a346f62024-01-18 20:12:02 +0000356 "Input out_local/soong/module/Output Text Tool after command2 old cmd",
Colin Cross7b6a55f2021-11-09 12:34:39 -0800357 "command2 out_local/soong/module/depfile2 input2 out_local/soong/module/output2 tool2",
358 "command3 input3 out_local/soong/module/output2 out_local/soong/module/output3 input3 out_local/soong/module/output2",
Dan Willemsen633c5022019-04-12 11:11:38 -0700359 }
Colin Cross1d2cf042019-03-29 15:33:06 -0700360
Colin Cross7b6a55f2021-11-09 12:34:39 -0800361 wantDepMergerCommand := "out_local/soong/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer " +
362 "out_local/soong/module/DepFile out_local/soong/module/depfile out_local/soong/module/ImplicitDepFile out_local/soong/module/depfile2"
Colin Crossab020a72021-03-12 17:52:23 -0800363
Paul Duffind250ff62021-03-16 21:51:29 +0000364 AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
Dan Willemsen633c5022019-04-12 11:11:38 -0700365
Paul Duffind250ff62021-03-16 21:51:29 +0000366 AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
Colin Crossab020a72021-03-12 17:52:23 -0800367 AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
Paul Duffind250ff62021-03-16 21:51:29 +0000368 AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
Paul Duffind250ff62021-03-16 21:51:29 +0000369 AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
370 AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
371 AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
Colin Crossae89abe2021-04-21 11:45:23 -0700372 AssertDeepEquals(t, "rule.Validations()", wantValidations, rule.Validations())
Dan Willemsen633c5022019-04-12 11:11:38 -0700373
Paul Duffind250ff62021-03-16 21:51:29 +0000374 AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
Dan Willemsen633c5022019-04-12 11:11:38 -0700375 })
376
377 t.Run("sbox", func(t *testing.T) {
Colin Crossab020a72021-03-12 17:52:23 -0800378 rule := NewRuleBuilder(pctx, ctx).Sbox(PathForOutput(ctx, "module"),
Colin Crosse16ce362020-11-12 08:29:30 -0800379 PathForOutput(ctx, "sbox.textproto"))
Dan Willemsen633c5022019-04-12 11:11:38 -0700380 addCommands(rule)
381
382 wantCommands := []string{
Colin Crossab020a72021-03-12 17:52:23 -0800383 "__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
384 "FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
Colin Cross7b6a55f2021-11-09 12:34:39 -0800385 "FlagWithRspFileInputList=out_local/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
Cole Faust9a346f62024-01-18 20:12:02 +0000386 "Text Tool after command2 old cmd",
Colin Crosse16ce362020-11-12 08:29:30 -0800387 "command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 tool2",
Colin Crossab020a72021-03-12 17:52:23 -0800388 "command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
Dan Willemsen633c5022019-04-12 11:11:38 -0700389 }
390
Colin Cross7b6a55f2021-11-09 12:34:39 -0800391 wantDepMergerCommand := "out_local/soong/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
Colin Crossab020a72021-03-12 17:52:23 -0800392
Paul Duffind250ff62021-03-16 21:51:29 +0000393 AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
Dan Willemsen633c5022019-04-12 11:11:38 -0700394
Paul Duffind250ff62021-03-16 21:51:29 +0000395 AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
Colin Crossab020a72021-03-12 17:52:23 -0800396 AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
Paul Duffind250ff62021-03-16 21:51:29 +0000397 AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
398 AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
399 AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
400 AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
Colin Crossae89abe2021-04-21 11:45:23 -0700401 AssertDeepEquals(t, "rule.Validations()", wantValidations, rule.Validations())
Dan Willemsen633c5022019-04-12 11:11:38 -0700402
Paul Duffind250ff62021-03-16 21:51:29 +0000403 AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
Dan Willemsen633c5022019-04-12 11:11:38 -0700404 })
Colin Crossba9e4032020-11-24 16:32:22 -0800405
406 t.Run("sbox tools", func(t *testing.T) {
Colin Crossab020a72021-03-12 17:52:23 -0800407 rule := NewRuleBuilder(pctx, ctx).Sbox(PathForOutput(ctx, "module"),
Colin Crossba9e4032020-11-24 16:32:22 -0800408 PathForOutput(ctx, "sbox.textproto")).SandboxTools()
409 addCommands(rule)
410
411 wantCommands := []string{
Colin Crossab020a72021-03-12 17:52:23 -0800412 "__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
413 "FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
Colin Cross7b6a55f2021-11-09 12:34:39 -0800414 "FlagWithRspFileInputList=out_local/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
Cole Faust9a346f62024-01-18 20:12:02 +0000415 "Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
Colin Crossba9e4032020-11-24 16:32:22 -0800416 "command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/tools/src/tool2",
Colin Crossab020a72021-03-12 17:52:23 -0800417 "command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
Colin Crossba9e4032020-11-24 16:32:22 -0800418 }
419
420 wantDepMergerCommand := "__SBOX_SANDBOX_DIR__/tools/out/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
421
Paul Duffind250ff62021-03-16 21:51:29 +0000422 AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
Colin Crossba9e4032020-11-24 16:32:22 -0800423
Paul Duffind250ff62021-03-16 21:51:29 +0000424 AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
Colin Crossab020a72021-03-12 17:52:23 -0800425 AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
Paul Duffind250ff62021-03-16 21:51:29 +0000426 AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
427 AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
428 AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
429 AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
Colin Crossae89abe2021-04-21 11:45:23 -0700430 AssertDeepEquals(t, "rule.Validations()", wantValidations, rule.Validations())
Colin Crossba9e4032020-11-24 16:32:22 -0800431
Paul Duffind250ff62021-03-16 21:51:29 +0000432 AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
Colin Crossba9e4032020-11-24 16:32:22 -0800433 })
Colin Cross045bfd92021-03-24 16:38:03 -0700434
435 t.Run("sbox inputs", func(t *testing.T) {
436 rule := NewRuleBuilder(pctx, ctx).Sbox(PathForOutput(ctx, "module"),
437 PathForOutput(ctx, "sbox.textproto")).SandboxInputs()
438 addCommands(rule)
439
440 wantCommands := []string{
441 "__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
442 "FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
Cole Fauste8561c62023-11-30 17:26:37 -0800443 "FlagWithRspFileInputList=__SBOX_SANDBOX_DIR__/out/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
Cole Faust9a346f62024-01-18 20:12:02 +0000444 "Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
Colin Cross045bfd92021-03-24 16:38:03 -0700445 "command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/tools/src/tool2",
446 "command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
447 }
448
449 wantDepMergerCommand := "__SBOX_SANDBOX_DIR__/tools/out/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
450
451 AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
452
453 AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
454 AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
455 AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
Colin Cross045bfd92021-03-24 16:38:03 -0700456 AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
457 AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
458 AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
Colin Crossae89abe2021-04-21 11:45:23 -0700459 AssertDeepEquals(t, "rule.Validations()", wantValidations, rule.Validations())
Colin Cross045bfd92021-03-24 16:38:03 -0700460
461 AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
462 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800463}
464
465func testRuleBuilderFactory() Module {
466 module := &testRuleBuilderModule{}
467 module.AddProperties(&module.properties)
468 InitAndroidModule(module)
469 return module
470}
471
472type testRuleBuilderModule struct {
473 ModuleBase
474 properties struct {
Sam Delmerico285b66a2023-09-25 12:13:17 +0000475 Srcs []string
476 Flags []string
Dan Willemsen633c5022019-04-12 11:11:38 -0700477
Sam Delmerico285b66a2023-09-25 12:13:17 +0000478 Restat bool
479 Sbox bool
480 Sbox_inputs bool
481 Unescape_ninja_vars bool
Colin Crossfeec25b2019-01-30 17:32:39 -0800482 }
483}
484
485func (t *testRuleBuilderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Colin Cross3d680512020-11-13 16:23:53 -0800486 in := PathsForSource(ctx, t.properties.Srcs)
Colin Crossda6401b2021-04-21 11:32:19 -0700487 implicit := PathForSource(ctx, "implicit")
488 orderOnly := PathForSource(ctx, "orderonly")
Colin Crossae89abe2021-04-21 11:45:23 -0700489 validation := PathForSource(ctx, "validation")
Colin Crosse16ce362020-11-12 08:29:30 -0800490 out := PathForModuleOut(ctx, "gen", ctx.ModuleName())
491 outDep := PathForModuleOut(ctx, "gen", ctx.ModuleName()+".d")
492 outDir := PathForModuleOut(ctx, "gen")
Colin Crossce3a51d2021-03-19 16:22:12 -0700493 rspFile := PathForModuleOut(ctx, "rsp")
494 rspFile2 := PathForModuleOut(ctx, "rsp2")
495 rspFileContents := PathsForSource(ctx, []string{"rsp_in"})
496 rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
Colin Crosse16ce362020-11-12 08:29:30 -0800497 manifestPath := PathForModuleOut(ctx, "sbox.textproto")
Colin Crossfeec25b2019-01-30 17:32:39 -0800498
Sam Delmerico285b66a2023-09-25 12:13:17 +0000499 testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, t.properties.Flags,
500 out, outDep, outDir,
501 manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs, t.properties.Unescape_ninja_vars,
Colin Crossda6401b2021-04-21 11:32:19 -0700502 rspFile, rspFileContents, rspFile2, rspFileContents2)
Colin Cross786cd6d2019-02-01 16:41:11 -0800503}
504
505type testRuleBuilderSingleton struct{}
506
507func testRuleBuilderSingletonFactory() Singleton {
508 return &testRuleBuilderSingleton{}
509}
510
511func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) {
Colin Crossda6401b2021-04-21 11:32:19 -0700512 in := PathsForSource(ctx, []string{"in"})
513 implicit := PathForSource(ctx, "implicit")
514 orderOnly := PathForSource(ctx, "orderonly")
Colin Crossae89abe2021-04-21 11:45:23 -0700515 validation := PathForSource(ctx, "validation")
Colin Crosse16ce362020-11-12 08:29:30 -0800516 out := PathForOutput(ctx, "singleton/gen/baz")
517 outDep := PathForOutput(ctx, "singleton/gen/baz.d")
518 outDir := PathForOutput(ctx, "singleton/gen")
Colin Crossce3a51d2021-03-19 16:22:12 -0700519 rspFile := PathForOutput(ctx, "singleton/rsp")
520 rspFile2 := PathForOutput(ctx, "singleton/rsp2")
521 rspFileContents := PathsForSource(ctx, []string{"rsp_in"})
522 rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
Colin Crosse16ce362020-11-12 08:29:30 -0800523 manifestPath := PathForOutput(ctx, "singleton/sbox.textproto")
Colin Crossda6401b2021-04-21 11:32:19 -0700524
Sam Delmerico285b66a2023-09-25 12:13:17 +0000525 testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, nil, out, outDep, outDir,
526 manifestPath, true, false, false, false,
Colin Crossce3a51d2021-03-19 16:22:12 -0700527 rspFile, rspFileContents, rspFile2, rspFileContents2)
Colin Cross786cd6d2019-02-01 16:41:11 -0800528}
529
Colin Crossae89abe2021-04-21 11:45:23 -0700530func testRuleBuilder_Build(ctx BuilderContext, in Paths, implicit, orderOnly, validation Path,
Sam Delmerico285b66a2023-09-25 12:13:17 +0000531 flags []string,
Colin Crossda6401b2021-04-21 11:32:19 -0700532 out, outDep, outDir, manifestPath WritablePath,
Sam Delmerico285b66a2023-09-25 12:13:17 +0000533 restat, sbox, sboxInputs, unescapeNinjaVars bool,
Colin Crossce3a51d2021-03-19 16:22:12 -0700534 rspFile WritablePath, rspFileContents Paths, rspFile2 WritablePath, rspFileContents2 Paths) {
535
Sam Delmerico285b66a2023-09-25 12:13:17 +0000536 rule := NewRuleBuilder(pctx_ruleBuilderTest, ctx)
Colin Cross786cd6d2019-02-01 16:41:11 -0800537
Dan Willemsen633c5022019-04-12 11:11:38 -0700538 if sbox {
Colin Crosse16ce362020-11-12 08:29:30 -0800539 rule.Sbox(outDir, manifestPath)
Colin Crossce3a51d2021-03-19 16:22:12 -0700540 if sboxInputs {
541 rule.SandboxInputs()
542 }
Dan Willemsen633c5022019-04-12 11:11:38 -0700543 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800544
Colin Crossce3a51d2021-03-19 16:22:12 -0700545 rule.Command().
546 Tool(PathForSource(ctx, "cp")).
Sam Delmerico285b66a2023-09-25 12:13:17 +0000547 Flags(flags).
Colin Crossce3a51d2021-03-19 16:22:12 -0700548 Inputs(in).
Colin Crossda6401b2021-04-21 11:32:19 -0700549 Implicit(implicit).
550 OrderOnly(orderOnly).
Colin Crossae89abe2021-04-21 11:45:23 -0700551 Validation(validation).
Colin Crossce3a51d2021-03-19 16:22:12 -0700552 Output(out).
553 ImplicitDepFile(outDep).
554 FlagWithRspFileInputList("@", rspFile, rspFileContents).
555 FlagWithRspFileInputList("@", rspFile2, rspFileContents2)
Dan Willemsen633c5022019-04-12 11:11:38 -0700556
557 if restat {
558 rule.Restat()
559 }
Colin Crossbaa676f2019-02-25 14:56:01 -0800560
Sam Delmerico285b66a2023-09-25 12:13:17 +0000561 if unescapeNinjaVars {
562 rule.BuildWithUnescapedNinjaVars("rule", "desc")
563 } else {
564 rule.Build("rule", "desc")
565 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800566}
567
Paul Duffind250ff62021-03-16 21:51:29 +0000568var prepareForRuleBuilderTest = FixtureRegisterWithContext(func(ctx RegistrationContext) {
569 ctx.RegisterModuleType("rule_builder_test", testRuleBuilderFactory)
570 ctx.RegisterSingletonType("rule_builder_test", testRuleBuilderSingletonFactory)
571})
572
Colin Crossfeec25b2019-01-30 17:32:39 -0800573func TestRuleBuilder_Build(t *testing.T) {
Paul Duffind250ff62021-03-16 21:51:29 +0000574 fs := MockFS{
Colin Crossda6401b2021-04-21 11:32:19 -0700575 "in": nil,
576 "cp": nil,
Colin Cross98be1bb2019-12-13 20:41:13 -0800577 }
578
Colin Crossfeec25b2019-01-30 17:32:39 -0800579 bp := `
580 rule_builder_test {
581 name: "foo",
Colin Crossda6401b2021-04-21 11:32:19 -0700582 srcs: ["in"],
Dan Willemsen633c5022019-04-12 11:11:38 -0700583 restat: true,
584 }
585 rule_builder_test {
586 name: "foo_sbox",
Colin Crossda6401b2021-04-21 11:32:19 -0700587 srcs: ["in"],
Dan Willemsen633c5022019-04-12 11:11:38 -0700588 sbox: true,
Colin Crossfeec25b2019-01-30 17:32:39 -0800589 }
Colin Crossce3a51d2021-03-19 16:22:12 -0700590 rule_builder_test {
591 name: "foo_sbox_inputs",
Colin Crossda6401b2021-04-21 11:32:19 -0700592 srcs: ["in"],
Colin Crossce3a51d2021-03-19 16:22:12 -0700593 sbox: true,
594 sbox_inputs: true,
595 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800596 `
597
Paul Duffin30ac3e72021-03-20 00:36:14 +0000598 result := GroupFixturePreparers(
Paul Duffind250ff62021-03-16 21:51:29 +0000599 prepareForRuleBuilderTest,
600 FixtureWithRootAndroidBp(bp),
601 fs.AddToFixture(),
Paul Duffin30ac3e72021-03-20 00:36:14 +0000602 ).RunTest(t)
Colin Crossfeec25b2019-01-30 17:32:39 -0800603
Colin Crossce3a51d2021-03-19 16:22:12 -0700604 check := func(t *testing.T, params TestingBuildParams, rspFile2Params TestingBuildParams,
605 wantCommand, wantOutput, wantDepfile, wantRspFile, wantRspFile2 string,
606 wantRestat bool, extraImplicits, extraCmdDeps []string) {
607
Dan Willemsenc89b6f12019-08-29 14:47:40 -0700608 t.Helper()
Colin Cross3d680512020-11-13 16:23:53 -0800609 command := params.RuleParams.Command
Colin Crosse16ce362020-11-12 08:29:30 -0800610 re := regexp.MustCompile(" # hash of input list: [a-z0-9]*$")
Colin Cross3d680512020-11-13 16:23:53 -0800611 command = re.ReplaceAllLiteralString(command, "")
Paul Duffind250ff62021-03-16 21:51:29 +0000612
613 AssertStringEquals(t, "RuleParams.Command", wantCommand, command)
Dan Willemsen633c5022019-04-12 11:11:38 -0700614
615 wantDeps := append([]string{"cp"}, extraCmdDeps...)
Paul Duffind250ff62021-03-16 21:51:29 +0000616 AssertArrayString(t, "RuleParams.CommandDeps", wantDeps, params.RuleParams.CommandDeps)
Dan Willemsen633c5022019-04-12 11:11:38 -0700617
Paul Duffind250ff62021-03-16 21:51:29 +0000618 AssertBoolEquals(t, "RuleParams.Restat", wantRestat, params.RuleParams.Restat)
Colin Crossfeec25b2019-01-30 17:32:39 -0800619
Colin Crossce3a51d2021-03-19 16:22:12 -0700620 wantInputs := []string{"rsp_in"}
621 AssertArrayString(t, "Inputs", wantInputs, params.Inputs.Strings())
622
Colin Crossda6401b2021-04-21 11:32:19 -0700623 wantImplicits := append([]string{"implicit", "in"}, extraImplicits...)
Colin Crossce3a51d2021-03-19 16:22:12 -0700624 // The second rsp file and the files listed in it should be in implicits
625 wantImplicits = append(wantImplicits, "rsp_in2", wantRspFile2)
Paul Duffin709e0e32021-03-22 10:09:02 +0000626 AssertPathsRelativeToTopEquals(t, "Implicits", wantImplicits, params.Implicits)
Colin Crossfeec25b2019-01-30 17:32:39 -0800627
Colin Crossda6401b2021-04-21 11:32:19 -0700628 wantOrderOnlys := []string{"orderonly"}
629 AssertPathsRelativeToTopEquals(t, "OrderOnly", wantOrderOnlys, params.OrderOnly)
630
Colin Crossae89abe2021-04-21 11:45:23 -0700631 wantValidations := []string{"validation"}
632 AssertPathsRelativeToTopEquals(t, "Validations", wantValidations, params.Validations)
633
Colin Crossce3a51d2021-03-19 16:22:12 -0700634 wantRspFileContent := "$in"
635 AssertStringEquals(t, "RspfileContent", wantRspFileContent, params.RuleParams.RspfileContent)
636
637 AssertStringEquals(t, "Rspfile", wantRspFile, params.RuleParams.Rspfile)
638
Paul Duffin709e0e32021-03-22 10:09:02 +0000639 AssertPathRelativeToTopEquals(t, "Output", wantOutput, params.Output)
Colin Crossbaa676f2019-02-25 14:56:01 -0800640
Dan Willemsen633c5022019-04-12 11:11:38 -0700641 if len(params.ImplicitOutputs) != 0 {
642 t.Errorf("want ImplicitOutputs = [], got %q", params.ImplicitOutputs.Strings())
643 }
644
Paul Duffin709e0e32021-03-22 10:09:02 +0000645 AssertPathRelativeToTopEquals(t, "Depfile", wantDepfile, params.Depfile)
Dan Willemsen633c5022019-04-12 11:11:38 -0700646
647 if params.Deps != blueprint.DepsGCC {
648 t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps)
Colin Crossbaa676f2019-02-25 14:56:01 -0800649 }
Colin Crossce3a51d2021-03-19 16:22:12 -0700650
Colin Crossf61d03d2023-11-02 16:56:39 -0700651 rspFile2Content := ContentFromFileRuleForTests(t, result.TestContext, rspFile2Params)
Colin Crossce3a51d2021-03-19 16:22:12 -0700652 AssertStringEquals(t, "rspFile2 content", "rsp_in2\n", rspFile2Content)
Colin Crossfeec25b2019-01-30 17:32:39 -0800653 }
654
Colin Cross4c83e5c2019-02-25 14:54:28 -0800655 t.Run("module", func(t *testing.T) {
Paul Duffin709e0e32021-03-22 10:09:02 +0000656 outFile := "out/soong/.intermediates/foo/gen/foo"
Colin Crossce3a51d2021-03-19 16:22:12 -0700657 rspFile := "out/soong/.intermediates/foo/rsp"
658 rspFile2 := "out/soong/.intermediates/foo/rsp2"
659 module := result.ModuleForTests("foo", "")
Paul Duffina71a67a2021-03-29 00:42:57 +0100660 check(t, module.Rule("rule"), module.Output(rspFile2),
Colin Crossda6401b2021-04-21 11:32:19 -0700661 "cp in "+outFile+" @"+rspFile+" @"+rspFile2,
Colin Crossce3a51d2021-03-19 16:22:12 -0700662 outFile, outFile+".d", rspFile, rspFile2, true, nil, nil)
Dan Willemsen633c5022019-04-12 11:11:38 -0700663 })
664 t.Run("sbox", func(t *testing.T) {
Paul Duffin709e0e32021-03-22 10:09:02 +0000665 outDir := "out/soong/.intermediates/foo_sbox"
Colin Crosse52c2ac2022-03-28 17:03:35 -0700666 sboxOutDir := filepath.Join(outDir, "gen")
667 outFile := filepath.Join(sboxOutDir, "foo_sbox")
668 depFile := filepath.Join(sboxOutDir, "foo_sbox.d")
Colin Crossce3a51d2021-03-19 16:22:12 -0700669 rspFile := filepath.Join(outDir, "rsp")
670 rspFile2 := filepath.Join(outDir, "rsp2")
671 manifest := filepath.Join(outDir, "sbox.textproto")
672 sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox")
673 sandboxPath := shared.TempDirForOutDir("out/soong")
674
Colin Crosse52c2ac2022-03-28 17:03:35 -0700675 cmd := sbox + ` --sandbox-path ` + sandboxPath + ` --output-dir ` + sboxOutDir + ` --manifest ` + manifest
Colin Crossce3a51d2021-03-19 16:22:12 -0700676 module := result.ModuleForTests("foo_sbox", "")
Paul Duffina71a67a2021-03-29 00:42:57 +0100677 check(t, module.Output("gen/foo_sbox"), module.Output(rspFile2),
Colin Crossce3a51d2021-03-19 16:22:12 -0700678 cmd, outFile, depFile, rspFile, rspFile2, false, []string{manifest}, []string{sbox})
679 })
680 t.Run("sbox_inputs", func(t *testing.T) {
681 outDir := "out/soong/.intermediates/foo_sbox_inputs"
Colin Crosse52c2ac2022-03-28 17:03:35 -0700682 sboxOutDir := filepath.Join(outDir, "gen")
683 outFile := filepath.Join(sboxOutDir, "foo_sbox_inputs")
684 depFile := filepath.Join(sboxOutDir, "foo_sbox_inputs.d")
Colin Crossce3a51d2021-03-19 16:22:12 -0700685 rspFile := filepath.Join(outDir, "rsp")
686 rspFile2 := filepath.Join(outDir, "rsp2")
Colin Crosse16ce362020-11-12 08:29:30 -0800687 manifest := filepath.Join(outDir, "sbox.textproto")
Paul Duffin709e0e32021-03-22 10:09:02 +0000688 sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox")
689 sandboxPath := shared.TempDirForOutDir("out/soong")
Dan Willemsen633c5022019-04-12 11:11:38 -0700690
Colin Crosse52c2ac2022-03-28 17:03:35 -0700691 cmd := sbox + ` --sandbox-path ` + sandboxPath + ` --output-dir ` + sboxOutDir + ` --manifest ` + manifest
Dan Willemsen633c5022019-04-12 11:11:38 -0700692
Colin Crossce3a51d2021-03-19 16:22:12 -0700693 module := result.ModuleForTests("foo_sbox_inputs", "")
Paul Duffina71a67a2021-03-29 00:42:57 +0100694 check(t, module.Output("gen/foo_sbox_inputs"), module.Output(rspFile2),
Colin Crossce3a51d2021-03-19 16:22:12 -0700695 cmd, outFile, depFile, rspFile, rspFile2, false, []string{manifest}, []string{sbox})
Colin Cross4c83e5c2019-02-25 14:54:28 -0800696 })
697 t.Run("singleton", func(t *testing.T) {
Paul Duffin709e0e32021-03-22 10:09:02 +0000698 outFile := filepath.Join("out/soong/singleton/gen/baz")
Colin Crossce3a51d2021-03-19 16:22:12 -0700699 rspFile := filepath.Join("out/soong/singleton/rsp")
700 rspFile2 := filepath.Join("out/soong/singleton/rsp2")
701 singleton := result.SingletonForTests("rule_builder_test")
Paul Duffina71a67a2021-03-29 00:42:57 +0100702 check(t, singleton.Rule("rule"), singleton.Output(rspFile2),
Colin Crossda6401b2021-04-21 11:32:19 -0700703 "cp in "+outFile+" @"+rspFile+" @"+rspFile2,
Colin Crossce3a51d2021-03-19 16:22:12 -0700704 outFile, outFile+".d", rspFile, rspFile2, true, nil, nil)
Colin Cross4c83e5c2019-02-25 14:54:28 -0800705 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800706}
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700707
Colin Cross3d680512020-11-13 16:23:53 -0800708func TestRuleBuilderHashInputs(t *testing.T) {
709 // The basic idea here is to verify that the command (in the case of a
710 // non-sbox rule) or the sbox textproto manifest contain a hash of the
711 // inputs.
712
713 // By including a hash of the inputs, we cause the rule to re-run if
714 // the list of inputs changes because the command line or a dependency
715 // changes.
716
Colin Crossda6401b2021-04-21 11:32:19 -0700717 hashOf := func(s string) string {
718 sum := sha256.Sum256([]byte(s))
719 return hex.EncodeToString(sum[:])
720 }
721
Colin Cross3d680512020-11-13 16:23:53 -0800722 bp := `
723 rule_builder_test {
724 name: "hash0",
725 srcs: ["in1.txt", "in2.txt"],
726 }
727 rule_builder_test {
728 name: "hash0_sbox",
729 srcs: ["in1.txt", "in2.txt"],
730 sbox: true,
731 }
732 rule_builder_test {
733 name: "hash1",
734 srcs: ["in1.txt", "in2.txt", "in3.txt"],
735 }
736 rule_builder_test {
737 name: "hash1_sbox",
738 srcs: ["in1.txt", "in2.txt", "in3.txt"],
739 sbox: true,
740 }
741 `
742 testcases := []struct {
743 name string
744 expectedHash string
745 }{
746 {
Colin Crossda6401b2021-04-21 11:32:19 -0700747 name: "hash0",
748 expectedHash: hashOf("implicit\nin1.txt\nin2.txt"),
Colin Cross3d680512020-11-13 16:23:53 -0800749 },
750 {
Colin Crossda6401b2021-04-21 11:32:19 -0700751 name: "hash1",
752 expectedHash: hashOf("implicit\nin1.txt\nin2.txt\nin3.txt"),
Colin Cross3d680512020-11-13 16:23:53 -0800753 },
754 }
755
Paul Duffin30ac3e72021-03-20 00:36:14 +0000756 result := GroupFixturePreparers(
Paul Duffind250ff62021-03-16 21:51:29 +0000757 prepareForRuleBuilderTest,
758 FixtureWithRootAndroidBp(bp),
Paul Duffin30ac3e72021-03-20 00:36:14 +0000759 ).RunTest(t)
Colin Cross3d680512020-11-13 16:23:53 -0800760
761 for _, test := range testcases {
762 t.Run(test.name, func(t *testing.T) {
763 t.Run("sbox", func(t *testing.T) {
Paul Duffind250ff62021-03-16 21:51:29 +0000764 gen := result.ModuleForTests(test.name+"_sbox", "")
Colin Crossf61d03d2023-11-02 16:56:39 -0700765 manifest := RuleBuilderSboxProtoForTests(t, result.TestContext, gen.Output("sbox.textproto"))
Colin Crosse16ce362020-11-12 08:29:30 -0800766 hash := manifest.Commands[0].GetInputHash()
767
Paul Duffind250ff62021-03-16 21:51:29 +0000768 AssertStringEquals(t, "hash", test.expectedHash, hash)
Colin Cross3d680512020-11-13 16:23:53 -0800769 })
770 t.Run("", func(t *testing.T) {
Paul Duffind250ff62021-03-16 21:51:29 +0000771 gen := result.ModuleForTests(test.name+"", "")
Colin Crosse16ce362020-11-12 08:29:30 -0800772 command := gen.Output("gen/" + test.name).RuleParams.Command
Colin Cross3d680512020-11-13 16:23:53 -0800773 if g, w := command, " # hash of input list: "+test.expectedHash; !strings.HasSuffix(g, w) {
774 t.Errorf("Expected command line to end with %q, got %q", w, g)
775 }
776 })
777 })
778 }
779}
Sam Delmerico285b66a2023-09-25 12:13:17 +0000780
781func TestRuleBuilderWithNinjaVarEscaping(t *testing.T) {
782 bp := `
783 rule_builder_test {
Colin Cross31a67452023-11-02 16:57:08 -0700784 name: "foo_sbox_escaped",
Sam Delmerico285b66a2023-09-25 12:13:17 +0000785 flags: ["${cmdFlags}"],
786 sbox: true,
787 sbox_inputs: true,
788 }
789 rule_builder_test {
Colin Cross31a67452023-11-02 16:57:08 -0700790 name: "foo_sbox_unescaped",
Sam Delmerico285b66a2023-09-25 12:13:17 +0000791 flags: ["${cmdFlags}"],
792 sbox: true,
793 sbox_inputs: true,
794 unescape_ninja_vars: true,
795 }
796 `
797 result := GroupFixturePreparers(
798 prepareForRuleBuilderTest,
799 FixtureWithRootAndroidBp(bp),
800 ).RunTest(t)
801
Colin Cross31a67452023-11-02 16:57:08 -0700802 escapedNinjaMod := result.ModuleForTests("foo_sbox_escaped", "").Output("sbox.textproto")
803 AssertStringEquals(t, "expected rule", "android/soong/android.rawFileCopy", escapedNinjaMod.Rule.String())
Sam Delmerico285b66a2023-09-25 12:13:17 +0000804 AssertStringDoesContain(
805 t,
806 "",
Colin Cross31a67452023-11-02 16:57:08 -0700807 ContentFromFileRuleForTests(t, result.TestContext, escapedNinjaMod),
808 "${cmdFlags}",
Sam Delmerico285b66a2023-09-25 12:13:17 +0000809 )
810
Colin Cross31a67452023-11-02 16:57:08 -0700811 unescapedNinjaMod := result.ModuleForTests("foo_sbox_unescaped", "").Rule("unescapedWriteFile")
Sam Delmerico285b66a2023-09-25 12:13:17 +0000812 AssertStringDoesContain(
813 t,
814 "",
815 unescapedNinjaMod.BuildParams.Args["content"],
816 "${cmdFlags}",
817 )
818 AssertStringDoesNotContain(
819 t,
820 "",
821 unescapedNinjaMod.BuildParams.Args["content"],
822 "$${cmdFlags}",
823 )
824}