blob: d659dcca7319e105a00964c8b87028060d1391e6 [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,
Jingwen Chence679d22020-09-23 04:30:02 +000051 "ln": nil,
Colin Cross98be1bb2019-12-13 20:41:13 -080052 "turbine": nil,
53 "java": nil,
54 "javac": nil,
55 }))
Colin Cross69f59a32019-02-15 10:39:37 -080056}
57
Colin Cross758290d2019-02-01 16:42:32 -080058func ExampleRuleBuilder() {
Colin Crossf1a035e2020-11-16 17:32:30 -080059 ctx := builderContext()
Colin Cross758290d2019-02-01 16:42:32 -080060
Colin Crossf1a035e2020-11-16 17:32:30 -080061 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -080062
63 rule.Command().
64 Tool(PathForSource(ctx, "ld")).
65 Inputs(PathsForTesting("a.o", "b.o")).
66 FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -080067 rule.Command().Text("echo success")
68
69 // To add the command to the build graph:
Colin Crossf1a035e2020-11-16 17:32:30 -080070 // rule.Build("link", "link")
Colin Cross758290d2019-02-01 16:42:32 -080071
72 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
73 fmt.Printf("tools: %q\n", rule.Tools())
74 fmt.Printf("inputs: %q\n", rule.Inputs())
75 fmt.Printf("outputs: %q\n", rule.Outputs())
76
77 // Output:
Colin Cross7b6a55f2021-11-09 12:34:39 -080078 // commands: "ld a.o b.o -o out/soong/linked && echo success"
Colin Cross758290d2019-02-01 16:42:32 -080079 // tools: ["ld"]
80 // inputs: ["a.o" "b.o"]
Colin Cross7b6a55f2021-11-09 12:34:39 -080081 // outputs: ["out/soong/linked"]
Colin Cross758290d2019-02-01 16:42:32 -080082}
83
Jingwen Chence679d22020-09-23 04:30:02 +000084func ExampleRuleBuilder_SymlinkOutputs() {
Colin Crossf1a035e2020-11-16 17:32:30 -080085 ctx := builderContext()
Jingwen Chence679d22020-09-23 04:30:02 +000086
Colin Crossf1a035e2020-11-16 17:32:30 -080087 rule := NewRuleBuilder(pctx, ctx)
Jingwen Chence679d22020-09-23 04:30:02 +000088
89 rule.Command().
90 Tool(PathForSource(ctx, "ln")).
91 FlagWithInput("-s ", PathForTesting("a.o")).
92 SymlinkOutput(PathForOutput(ctx, "a"))
Colin Cross7b6a55f2021-11-09 12:34:39 -080093 rule.Command().Text("cp out/soong/a out/soong/b").
Jingwen Chence679d22020-09-23 04:30:02 +000094 ImplicitSymlinkOutput(PathForOutput(ctx, "b"))
95
96 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
97 fmt.Printf("tools: %q\n", rule.Tools())
98 fmt.Printf("inputs: %q\n", rule.Inputs())
99 fmt.Printf("outputs: %q\n", rule.Outputs())
100 fmt.Printf("symlink_outputs: %q\n", rule.SymlinkOutputs())
101
102 // Output:
Colin Cross7b6a55f2021-11-09 12:34:39 -0800103 // commands: "ln -s a.o out/soong/a && cp out/soong/a out/soong/b"
Jingwen Chence679d22020-09-23 04:30:02 +0000104 // tools: ["ln"]
105 // inputs: ["a.o"]
Colin Cross7b6a55f2021-11-09 12:34:39 -0800106 // outputs: ["out/soong/a" "out/soong/b"]
107 // symlink_outputs: ["out/soong/a" "out/soong/b"]
Jingwen Chence679d22020-09-23 04:30:02 +0000108}
109
Colin Cross5cb5b092019-02-02 21:25:18 -0800110func ExampleRuleBuilder_Temporary() {
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
125 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
126 fmt.Printf("tools: %q\n", rule.Tools())
127 fmt.Printf("inputs: %q\n", rule.Inputs())
128 fmt.Printf("outputs: %q\n", rule.Outputs())
129
130 // Output:
Colin Cross7b6a55f2021-11-09 12:34:39 -0800131 // commands: "cp a out/soong/b && cp out/soong/b out/soong/c"
Colin Cross5cb5b092019-02-02 21:25:18 -0800132 // tools: ["cp"]
133 // inputs: ["a"]
Colin Cross7b6a55f2021-11-09 12:34:39 -0800134 // outputs: ["out/soong/c"]
Colin Cross5cb5b092019-02-02 21:25:18 -0800135}
136
137func ExampleRuleBuilder_DeleteTemporaryFiles() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800138 ctx := builderContext()
Colin Cross5cb5b092019-02-02 21:25:18 -0800139
Colin Crossf1a035e2020-11-16 17:32:30 -0800140 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -0800141
142 rule.Command().
143 Tool(PathForSource(ctx, "cp")).
144 Input(PathForSource(ctx, "a")).
145 Output(PathForOutput(ctx, "b"))
146 rule.Command().
147 Tool(PathForSource(ctx, "cp")).
148 Input(PathForOutput(ctx, "b")).
149 Output(PathForOutput(ctx, "c"))
150 rule.Temporary(PathForOutput(ctx, "b"))
Colin Cross5cb5b092019-02-02 21:25:18 -0800151 rule.DeleteTemporaryFiles()
152
153 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
154 fmt.Printf("tools: %q\n", rule.Tools())
155 fmt.Printf("inputs: %q\n", rule.Inputs())
156 fmt.Printf("outputs: %q\n", rule.Outputs())
157
158 // Output:
Colin Cross7b6a55f2021-11-09 12:34:39 -0800159 // 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 -0800160 // tools: ["cp"]
161 // inputs: ["a"]
Colin Cross7b6a55f2021-11-09 12:34:39 -0800162 // outputs: ["out/soong/c"]
Colin Cross5cb5b092019-02-02 21:25:18 -0800163}
164
Colin Crossdeabb942019-02-11 14:11:09 -0800165func ExampleRuleBuilder_Installs() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800166 ctx := builderContext()
Colin Crossdeabb942019-02-11 14:11:09 -0800167
Colin Crossf1a035e2020-11-16 17:32:30 -0800168 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -0800169
170 out := PathForOutput(ctx, "linked")
171
172 rule.Command().
173 Tool(PathForSource(ctx, "ld")).
174 Inputs(PathsForTesting("a.o", "b.o")).
175 FlagWithOutput("-o ", out)
176 rule.Install(out, "/bin/linked")
177 rule.Install(out, "/sbin/linked")
Colin Crossdeabb942019-02-11 14:11:09 -0800178
179 fmt.Printf("rule.Installs().String() = %q\n", rule.Installs().String())
180
181 // Output:
Colin Cross7b6a55f2021-11-09 12:34:39 -0800182 // rule.Installs().String() = "out/soong/linked:/bin/linked out/soong/linked:/sbin/linked"
Colin Crossdeabb942019-02-11 14:11:09 -0800183}
184
Colin Cross758290d2019-02-01 16:42:32 -0800185func ExampleRuleBuilderCommand() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800186 ctx := builderContext()
Colin Cross758290d2019-02-01 16:42:32 -0800187
Colin Crossf1a035e2020-11-16 17:32:30 -0800188 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -0800189
Colin Cross758290d2019-02-01 16:42:32 -0800190 // chained
Colin Cross69f59a32019-02-15 10:39:37 -0800191 rule.Command().
192 Tool(PathForSource(ctx, "ld")).
193 Inputs(PathsForTesting("a.o", "b.o")).
194 FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -0800195
196 // unchained
197 cmd := rule.Command()
Colin Cross69f59a32019-02-15 10:39:37 -0800198 cmd.Tool(PathForSource(ctx, "ld"))
199 cmd.Inputs(PathsForTesting("a.o", "b.o"))
200 cmd.FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -0800201
202 // mixed:
Colin Cross69f59a32019-02-15 10:39:37 -0800203 cmd = rule.Command().Tool(PathForSource(ctx, "ld"))
204 cmd.Inputs(PathsForTesting("a.o", "b.o"))
205 cmd.FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -0800206}
207
208func ExampleRuleBuilderCommand_Flag() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800209 ctx := builderContext()
210 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800211 Tool(PathForSource(ctx, "ls")).Flag("-l"))
Colin Cross758290d2019-02-01 16:42:32 -0800212 // Output:
213 // ls -l
214}
215
Colin Cross92b7d582019-03-29 15:32:51 -0700216func ExampleRuleBuilderCommand_Flags() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800217 ctx := builderContext()
218 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross92b7d582019-03-29 15:32:51 -0700219 Tool(PathForSource(ctx, "ls")).Flags([]string{"-l", "-a"}))
220 // Output:
221 // ls -l -a
222}
223
Colin Cross758290d2019-02-01 16:42:32 -0800224func ExampleRuleBuilderCommand_FlagWithArg() {
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, "ls")).
Colin Cross758290d2019-02-01 16:42:32 -0800228 FlagWithArg("--sort=", "time"))
229 // Output:
230 // ls --sort=time
231}
232
Colin Crossc7ed0042019-02-11 14:11:09 -0800233func ExampleRuleBuilderCommand_FlagForEachArg() {
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, "ls")).
Colin Crossc7ed0042019-02-11 14:11:09 -0800237 FlagForEachArg("--sort=", []string{"time", "size"}))
238 // Output:
239 // ls --sort=time --sort=size
240}
241
Colin Cross758290d2019-02-01 16:42:32 -0800242func ExampleRuleBuilderCommand_FlagForEachInput() {
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, "turbine")).
246 FlagForEachInput("--classpath ", PathsForTesting("a.jar", "b.jar")))
Colin Cross758290d2019-02-01 16:42:32 -0800247 // Output:
248 // turbine --classpath a.jar --classpath b.jar
249}
250
251func ExampleRuleBuilderCommand_FlagWithInputList() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800252 ctx := builderContext()
253 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800254 Tool(PathForSource(ctx, "java")).
255 FlagWithInputList("-classpath=", PathsForTesting("a.jar", "b.jar"), ":"))
Colin Cross758290d2019-02-01 16:42:32 -0800256 // Output:
257 // java -classpath=a.jar:b.jar
258}
259
260func ExampleRuleBuilderCommand_FlagWithInput() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800261 ctx := builderContext()
262 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800263 Tool(PathForSource(ctx, "java")).
264 FlagWithInput("-classpath=", PathForSource(ctx, "a")))
Colin Cross758290d2019-02-01 16:42:32 -0800265 // Output:
266 // java -classpath=a
267}
268
269func ExampleRuleBuilderCommand_FlagWithList() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800270 ctx := builderContext()
271 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800272 Tool(PathForSource(ctx, "ls")).
Colin Cross758290d2019-02-01 16:42:32 -0800273 FlagWithList("--sort=", []string{"time", "size"}, ","))
274 // Output:
275 // ls --sort=time,size
276}
277
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700278func ExampleRuleBuilderCommand_FlagWithRspFileInputList() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800279 ctx := builderContext()
280 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700281 Tool(PathForSource(ctx, "javac")).
Colin Cross70c47412021-03-12 17:48:14 -0800282 FlagWithRspFileInputList("@", PathForOutput(ctx, "foo.rsp"), PathsForTesting("a.java", "b.java")).
283 String())
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700284 // Output:
Colin Cross7b6a55f2021-11-09 12:34:39 -0800285 // javac @out/soong/foo.rsp
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700286}
287
288func ExampleRuleBuilderCommand_String() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800289 ctx := builderContext()
290 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700291 Text("FOO=foo").
292 Text("echo $FOO").
293 String())
294 // Output:
295 // FOO=foo echo $FOO
296}
297
Colin Crossfeec25b2019-01-30 17:32:39 -0800298func TestRuleBuilder(t *testing.T) {
Colin Cross69f59a32019-02-15 10:39:37 -0800299 fs := map[string][]byte{
Colin Crossda71eda2020-02-21 16:55:19 -0800300 "dep_fixer": nil,
301 "input": nil,
302 "Implicit": nil,
303 "Input": nil,
304 "OrderOnly": nil,
305 "OrderOnlys": nil,
306 "Tool": nil,
307 "input2": nil,
308 "tool2": nil,
309 "input3": nil,
Colin Cross69f59a32019-02-15 10:39:37 -0800310 }
311
Colin Crossab020a72021-03-12 17:52:23 -0800312 pathCtx := PathContextForTesting(TestConfig("out_local", nil, "", fs))
Colin Crossf1a035e2020-11-16 17:32:30 -0800313 ctx := builderContextForTests{
314 PathContext: pathCtx,
315 }
Colin Cross69f59a32019-02-15 10:39:37 -0800316
Dan Willemsen633c5022019-04-12 11:11:38 -0700317 addCommands := func(rule *RuleBuilder) {
318 cmd := rule.Command().
Colin Crossab020a72021-03-12 17:52:23 -0800319 DepFile(PathForOutput(ctx, "module/DepFile")).
Dan Willemsen633c5022019-04-12 11:11:38 -0700320 Flag("Flag").
321 FlagWithArg("FlagWithArg=", "arg").
Colin Crossab020a72021-03-12 17:52:23 -0800322 FlagWithDepFile("FlagWithDepFile=", PathForOutput(ctx, "module/depfile")).
Dan Willemsen633c5022019-04-12 11:11:38 -0700323 FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")).
Colin Crossab020a72021-03-12 17:52:23 -0800324 FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "module/output")).
325 FlagWithRspFileInputList("FlagWithRspFileInputList=", PathForOutput(ctx, "rsp"),
326 Paths{
327 PathForSource(ctx, "RspInput"),
328 PathForOutput(ctx, "other/RspOutput2"),
329 }).
Dan Willemsen633c5022019-04-12 11:11:38 -0700330 Implicit(PathForSource(ctx, "Implicit")).
Colin Crossab020a72021-03-12 17:52:23 -0800331 ImplicitDepFile(PathForOutput(ctx, "module/ImplicitDepFile")).
332 ImplicitOutput(PathForOutput(ctx, "module/ImplicitOutput")).
Dan Willemsen633c5022019-04-12 11:11:38 -0700333 Input(PathForSource(ctx, "Input")).
Colin Crossab020a72021-03-12 17:52:23 -0800334 Output(PathForOutput(ctx, "module/Output")).
Colin Crossda71eda2020-02-21 16:55:19 -0800335 OrderOnly(PathForSource(ctx, "OrderOnly")).
Colin Crossae89abe2021-04-21 11:45:23 -0700336 Validation(PathForSource(ctx, "Validation")).
Colin Crossab020a72021-03-12 17:52:23 -0800337 SymlinkOutput(PathForOutput(ctx, "module/SymlinkOutput")).
338 ImplicitSymlinkOutput(PathForOutput(ctx, "module/ImplicitSymlinkOutput")).
Dan Willemsen633c5022019-04-12 11:11:38 -0700339 Text("Text").
340 Tool(PathForSource(ctx, "Tool"))
Colin Crossfeec25b2019-01-30 17:32:39 -0800341
Dan Willemsen633c5022019-04-12 11:11:38 -0700342 rule.Command().
343 Text("command2").
Colin Crossab020a72021-03-12 17:52:23 -0800344 DepFile(PathForOutput(ctx, "module/depfile2")).
Dan Willemsen633c5022019-04-12 11:11:38 -0700345 Input(PathForSource(ctx, "input2")).
Colin Crossab020a72021-03-12 17:52:23 -0800346 Output(PathForOutput(ctx, "module/output2")).
Colin Crossda71eda2020-02-21 16:55:19 -0800347 OrderOnlys(PathsForSource(ctx, []string{"OrderOnlys"})).
Colin Crossae89abe2021-04-21 11:45:23 -0700348 Validations(PathsForSource(ctx, []string{"Validations"})).
Dan Willemsen633c5022019-04-12 11:11:38 -0700349 Tool(PathForSource(ctx, "tool2"))
Colin Crossfeec25b2019-01-30 17:32:39 -0800350
Dan Willemsen633c5022019-04-12 11:11:38 -0700351 // Test updates to the first command after the second command has been started
352 cmd.Text("after command2")
353 // Test updating a command when the previous update did not replace the cmd variable
354 cmd.Text("old cmd")
Colin Crossfeec25b2019-01-30 17:32:39 -0800355
Dan Willemsen633c5022019-04-12 11:11:38 -0700356 // Test a command that uses the output of a previous command as an input
357 rule.Command().
358 Text("command3").
359 Input(PathForSource(ctx, "input3")).
Colin Crossab020a72021-03-12 17:52:23 -0800360 Input(PathForOutput(ctx, "module/output2")).
361 Output(PathForOutput(ctx, "module/output3")).
362 Text(cmd.PathForInput(PathForSource(ctx, "input3"))).
363 Text(cmd.PathForOutput(PathForOutput(ctx, "module/output2")))
Colin Crossfeec25b2019-01-30 17:32:39 -0800364 }
Colin Cross1d2cf042019-03-29 15:33:06 -0700365
Colin Cross69f59a32019-02-15 10:39:37 -0800366 wantInputs := PathsForSource(ctx, []string{"Implicit", "Input", "input", "input2", "input3"})
Colin Crossab020a72021-03-12 17:52:23 -0800367 wantRspFileInputs := Paths{PathForSource(ctx, "RspInput"),
368 PathForOutput(ctx, "other/RspOutput2")}
369 wantOutputs := PathsForOutput(ctx, []string{
370 "module/ImplicitOutput", "module/ImplicitSymlinkOutput", "module/Output", "module/SymlinkOutput",
371 "module/output", "module/output2", "module/output3"})
372 wantDepFiles := PathsForOutput(ctx, []string{
373 "module/DepFile", "module/depfile", "module/ImplicitDepFile", "module/depfile2"})
Colin Cross69f59a32019-02-15 10:39:37 -0800374 wantTools := PathsForSource(ctx, []string{"Tool", "tool2"})
Colin Crossda71eda2020-02-21 16:55:19 -0800375 wantOrderOnlys := PathsForSource(ctx, []string{"OrderOnly", "OrderOnlys"})
Colin Crossae89abe2021-04-21 11:45:23 -0700376 wantValidations := PathsForSource(ctx, []string{"Validation", "Validations"})
Colin Crossab020a72021-03-12 17:52:23 -0800377 wantSymlinkOutputs := PathsForOutput(ctx, []string{
378 "module/ImplicitSymlinkOutput", "module/SymlinkOutput"})
Colin Crossfeec25b2019-01-30 17:32:39 -0800379
Dan Willemsen633c5022019-04-12 11:11:38 -0700380 t.Run("normal", func(t *testing.T) {
Colin Crossf1a035e2020-11-16 17:32:30 -0800381 rule := NewRuleBuilder(pctx, ctx)
Dan Willemsen633c5022019-04-12 11:11:38 -0700382 addCommands(rule)
Colin Cross1d2cf042019-03-29 15:33:06 -0700383
Dan Willemsen633c5022019-04-12 11:11:38 -0700384 wantCommands := []string{
Colin Cross7b6a55f2021-11-09 12:34:39 -0800385 "out_local/soong/module/DepFile Flag FlagWithArg=arg FlagWithDepFile=out_local/soong/module/depfile " +
386 "FlagWithInput=input FlagWithOutput=out_local/soong/module/output FlagWithRspFileInputList=out_local/soong/rsp " +
387 "Input out_local/soong/module/Output out_local/soong/module/SymlinkOutput Text Tool after command2 old cmd",
388 "command2 out_local/soong/module/depfile2 input2 out_local/soong/module/output2 tool2",
389 "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 -0700390 }
Colin Cross1d2cf042019-03-29 15:33:06 -0700391
Colin Cross7b6a55f2021-11-09 12:34:39 -0800392 wantDepMergerCommand := "out_local/soong/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer " +
393 "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 -0800394
Paul Duffind250ff62021-03-16 21:51:29 +0000395 AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
Dan Willemsen633c5022019-04-12 11:11:38 -0700396
Paul Duffind250ff62021-03-16 21:51:29 +0000397 AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
Colin Crossab020a72021-03-12 17:52:23 -0800398 AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
Paul Duffind250ff62021-03-16 21:51:29 +0000399 AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
400 AssertDeepEquals(t, "rule.SymlinkOutputs()", wantSymlinkOutputs, rule.SymlinkOutputs())
401 AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
402 AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
403 AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
Colin Crossae89abe2021-04-21 11:45:23 -0700404 AssertDeepEquals(t, "rule.Validations()", wantValidations, rule.Validations())
Dan Willemsen633c5022019-04-12 11:11:38 -0700405
Paul Duffind250ff62021-03-16 21:51:29 +0000406 AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
Dan Willemsen633c5022019-04-12 11:11:38 -0700407 })
408
409 t.Run("sbox", func(t *testing.T) {
Colin Crossab020a72021-03-12 17:52:23 -0800410 rule := NewRuleBuilder(pctx, ctx).Sbox(PathForOutput(ctx, "module"),
Colin Crosse16ce362020-11-12 08:29:30 -0800411 PathForOutput(ctx, "sbox.textproto"))
Dan Willemsen633c5022019-04-12 11:11:38 -0700412 addCommands(rule)
413
414 wantCommands := []string{
Colin Crossab020a72021-03-12 17:52:23 -0800415 "__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
416 "FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
Colin Cross7b6a55f2021-11-09 12:34:39 -0800417 "FlagWithRspFileInputList=out_local/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
Colin Crossab020a72021-03-12 17:52:23 -0800418 "__SBOX_SANDBOX_DIR__/out/SymlinkOutput Text Tool after command2 old cmd",
Colin Crosse16ce362020-11-12 08:29:30 -0800419 "command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 tool2",
Colin Crossab020a72021-03-12 17:52:23 -0800420 "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 -0700421 }
422
Colin Cross7b6a55f2021-11-09 12:34:39 -0800423 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 -0800424
Paul Duffind250ff62021-03-16 21:51:29 +0000425 AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
Dan Willemsen633c5022019-04-12 11:11:38 -0700426
Paul Duffind250ff62021-03-16 21:51:29 +0000427 AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
Colin Crossab020a72021-03-12 17:52:23 -0800428 AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
Paul Duffind250ff62021-03-16 21:51:29 +0000429 AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
Colin Crossab020a72021-03-12 17:52:23 -0800430 AssertDeepEquals(t, "rule.SymlinkOutputs()", wantSymlinkOutputs, rule.SymlinkOutputs())
Paul Duffind250ff62021-03-16 21:51:29 +0000431 AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
432 AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
433 AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
Colin Crossae89abe2021-04-21 11:45:23 -0700434 AssertDeepEquals(t, "rule.Validations()", wantValidations, rule.Validations())
Dan Willemsen633c5022019-04-12 11:11:38 -0700435
Paul Duffind250ff62021-03-16 21:51:29 +0000436 AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
Dan Willemsen633c5022019-04-12 11:11:38 -0700437 })
Colin Crossba9e4032020-11-24 16:32:22 -0800438
439 t.Run("sbox tools", func(t *testing.T) {
Colin Crossab020a72021-03-12 17:52:23 -0800440 rule := NewRuleBuilder(pctx, ctx).Sbox(PathForOutput(ctx, "module"),
Colin Crossba9e4032020-11-24 16:32:22 -0800441 PathForOutput(ctx, "sbox.textproto")).SandboxTools()
442 addCommands(rule)
443
444 wantCommands := []string{
Colin Crossab020a72021-03-12 17:52:23 -0800445 "__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
446 "FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
Colin Cross7b6a55f2021-11-09 12:34:39 -0800447 "FlagWithRspFileInputList=out_local/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
Colin Crossab020a72021-03-12 17:52:23 -0800448 "__SBOX_SANDBOX_DIR__/out/SymlinkOutput Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
Colin Crossba9e4032020-11-24 16:32:22 -0800449 "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 -0800450 "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 -0800451 }
452
453 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"
454
Paul Duffind250ff62021-03-16 21:51:29 +0000455 AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
Colin Crossba9e4032020-11-24 16:32:22 -0800456
Paul Duffind250ff62021-03-16 21:51:29 +0000457 AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
Colin Crossab020a72021-03-12 17:52:23 -0800458 AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
Paul Duffind250ff62021-03-16 21:51:29 +0000459 AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
Colin Crossab020a72021-03-12 17:52:23 -0800460 AssertDeepEquals(t, "rule.SymlinkOutputs()", wantSymlinkOutputs, rule.SymlinkOutputs())
Paul Duffind250ff62021-03-16 21:51:29 +0000461 AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
462 AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
463 AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
Colin Crossae89abe2021-04-21 11:45:23 -0700464 AssertDeepEquals(t, "rule.Validations()", wantValidations, rule.Validations())
Colin Crossba9e4032020-11-24 16:32:22 -0800465
Paul Duffind250ff62021-03-16 21:51:29 +0000466 AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
Colin Crossba9e4032020-11-24 16:32:22 -0800467 })
Colin Cross045bfd92021-03-24 16:38:03 -0700468
469 t.Run("sbox inputs", func(t *testing.T) {
470 rule := NewRuleBuilder(pctx, ctx).Sbox(PathForOutput(ctx, "module"),
471 PathForOutput(ctx, "sbox.textproto")).SandboxInputs()
472 addCommands(rule)
473
474 wantCommands := []string{
475 "__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
476 "FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
Cole Fauste8561c62023-11-30 17:26:37 -0800477 "FlagWithRspFileInputList=__SBOX_SANDBOX_DIR__/out/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
Colin Cross045bfd92021-03-24 16:38:03 -0700478 "__SBOX_SANDBOX_DIR__/out/SymlinkOutput Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
479 "command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/tools/src/tool2",
480 "command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
481 }
482
483 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"
484
485 AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
486
487 AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
488 AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
489 AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
490 AssertDeepEquals(t, "rule.SymlinkOutputs()", wantSymlinkOutputs, rule.SymlinkOutputs())
491 AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
492 AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
493 AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
Colin Crossae89abe2021-04-21 11:45:23 -0700494 AssertDeepEquals(t, "rule.Validations()", wantValidations, rule.Validations())
Colin Cross045bfd92021-03-24 16:38:03 -0700495
496 AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
497 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800498}
499
500func testRuleBuilderFactory() Module {
501 module := &testRuleBuilderModule{}
502 module.AddProperties(&module.properties)
503 InitAndroidModule(module)
504 return module
505}
506
507type testRuleBuilderModule struct {
508 ModuleBase
509 properties struct {
Sam Delmerico285b66a2023-09-25 12:13:17 +0000510 Srcs []string
511 Flags []string
Dan Willemsen633c5022019-04-12 11:11:38 -0700512
Sam Delmerico285b66a2023-09-25 12:13:17 +0000513 Restat bool
514 Sbox bool
515 Sbox_inputs bool
516 Unescape_ninja_vars bool
Colin Crossfeec25b2019-01-30 17:32:39 -0800517 }
518}
519
520func (t *testRuleBuilderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Colin Cross3d680512020-11-13 16:23:53 -0800521 in := PathsForSource(ctx, t.properties.Srcs)
Colin Crossda6401b2021-04-21 11:32:19 -0700522 implicit := PathForSource(ctx, "implicit")
523 orderOnly := PathForSource(ctx, "orderonly")
Colin Crossae89abe2021-04-21 11:45:23 -0700524 validation := PathForSource(ctx, "validation")
Colin Crosse16ce362020-11-12 08:29:30 -0800525 out := PathForModuleOut(ctx, "gen", ctx.ModuleName())
526 outDep := PathForModuleOut(ctx, "gen", ctx.ModuleName()+".d")
527 outDir := PathForModuleOut(ctx, "gen")
Colin Crossce3a51d2021-03-19 16:22:12 -0700528 rspFile := PathForModuleOut(ctx, "rsp")
529 rspFile2 := PathForModuleOut(ctx, "rsp2")
530 rspFileContents := PathsForSource(ctx, []string{"rsp_in"})
531 rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
Colin Crosse16ce362020-11-12 08:29:30 -0800532 manifestPath := PathForModuleOut(ctx, "sbox.textproto")
Colin Crossfeec25b2019-01-30 17:32:39 -0800533
Sam Delmerico285b66a2023-09-25 12:13:17 +0000534 testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, t.properties.Flags,
535 out, outDep, outDir,
536 manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs, t.properties.Unescape_ninja_vars,
Colin Crossda6401b2021-04-21 11:32:19 -0700537 rspFile, rspFileContents, rspFile2, rspFileContents2)
Colin Cross786cd6d2019-02-01 16:41:11 -0800538}
539
540type testRuleBuilderSingleton struct{}
541
542func testRuleBuilderSingletonFactory() Singleton {
543 return &testRuleBuilderSingleton{}
544}
545
546func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) {
Colin Crossda6401b2021-04-21 11:32:19 -0700547 in := PathsForSource(ctx, []string{"in"})
548 implicit := PathForSource(ctx, "implicit")
549 orderOnly := PathForSource(ctx, "orderonly")
Colin Crossae89abe2021-04-21 11:45:23 -0700550 validation := PathForSource(ctx, "validation")
Colin Crosse16ce362020-11-12 08:29:30 -0800551 out := PathForOutput(ctx, "singleton/gen/baz")
552 outDep := PathForOutput(ctx, "singleton/gen/baz.d")
553 outDir := PathForOutput(ctx, "singleton/gen")
Colin Crossce3a51d2021-03-19 16:22:12 -0700554 rspFile := PathForOutput(ctx, "singleton/rsp")
555 rspFile2 := PathForOutput(ctx, "singleton/rsp2")
556 rspFileContents := PathsForSource(ctx, []string{"rsp_in"})
557 rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
Colin Crosse16ce362020-11-12 08:29:30 -0800558 manifestPath := PathForOutput(ctx, "singleton/sbox.textproto")
Colin Crossda6401b2021-04-21 11:32:19 -0700559
Sam Delmerico285b66a2023-09-25 12:13:17 +0000560 testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, nil, out, outDep, outDir,
561 manifestPath, true, false, false, false,
Colin Crossce3a51d2021-03-19 16:22:12 -0700562 rspFile, rspFileContents, rspFile2, rspFileContents2)
Colin Cross786cd6d2019-02-01 16:41:11 -0800563}
564
Colin Crossae89abe2021-04-21 11:45:23 -0700565func testRuleBuilder_Build(ctx BuilderContext, in Paths, implicit, orderOnly, validation Path,
Sam Delmerico285b66a2023-09-25 12:13:17 +0000566 flags []string,
Colin Crossda6401b2021-04-21 11:32:19 -0700567 out, outDep, outDir, manifestPath WritablePath,
Sam Delmerico285b66a2023-09-25 12:13:17 +0000568 restat, sbox, sboxInputs, unescapeNinjaVars bool,
Colin Crossce3a51d2021-03-19 16:22:12 -0700569 rspFile WritablePath, rspFileContents Paths, rspFile2 WritablePath, rspFileContents2 Paths) {
570
Sam Delmerico285b66a2023-09-25 12:13:17 +0000571 rule := NewRuleBuilder(pctx_ruleBuilderTest, ctx)
Colin Cross786cd6d2019-02-01 16:41:11 -0800572
Dan Willemsen633c5022019-04-12 11:11:38 -0700573 if sbox {
Colin Crosse16ce362020-11-12 08:29:30 -0800574 rule.Sbox(outDir, manifestPath)
Colin Crossce3a51d2021-03-19 16:22:12 -0700575 if sboxInputs {
576 rule.SandboxInputs()
577 }
Dan Willemsen633c5022019-04-12 11:11:38 -0700578 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800579
Colin Crossce3a51d2021-03-19 16:22:12 -0700580 rule.Command().
581 Tool(PathForSource(ctx, "cp")).
Sam Delmerico285b66a2023-09-25 12:13:17 +0000582 Flags(flags).
Colin Crossce3a51d2021-03-19 16:22:12 -0700583 Inputs(in).
Colin Crossda6401b2021-04-21 11:32:19 -0700584 Implicit(implicit).
585 OrderOnly(orderOnly).
Colin Crossae89abe2021-04-21 11:45:23 -0700586 Validation(validation).
Colin Crossce3a51d2021-03-19 16:22:12 -0700587 Output(out).
588 ImplicitDepFile(outDep).
589 FlagWithRspFileInputList("@", rspFile, rspFileContents).
590 FlagWithRspFileInputList("@", rspFile2, rspFileContents2)
Dan Willemsen633c5022019-04-12 11:11:38 -0700591
592 if restat {
593 rule.Restat()
594 }
Colin Crossbaa676f2019-02-25 14:56:01 -0800595
Sam Delmerico285b66a2023-09-25 12:13:17 +0000596 if unescapeNinjaVars {
597 rule.BuildWithUnescapedNinjaVars("rule", "desc")
598 } else {
599 rule.Build("rule", "desc")
600 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800601}
602
Paul Duffind250ff62021-03-16 21:51:29 +0000603var prepareForRuleBuilderTest = FixtureRegisterWithContext(func(ctx RegistrationContext) {
604 ctx.RegisterModuleType("rule_builder_test", testRuleBuilderFactory)
605 ctx.RegisterSingletonType("rule_builder_test", testRuleBuilderSingletonFactory)
606})
607
Colin Crossfeec25b2019-01-30 17:32:39 -0800608func TestRuleBuilder_Build(t *testing.T) {
Paul Duffind250ff62021-03-16 21:51:29 +0000609 fs := MockFS{
Colin Crossda6401b2021-04-21 11:32:19 -0700610 "in": nil,
611 "cp": nil,
Colin Cross98be1bb2019-12-13 20:41:13 -0800612 }
613
Colin Crossfeec25b2019-01-30 17:32:39 -0800614 bp := `
615 rule_builder_test {
616 name: "foo",
Colin Crossda6401b2021-04-21 11:32:19 -0700617 srcs: ["in"],
Dan Willemsen633c5022019-04-12 11:11:38 -0700618 restat: true,
619 }
620 rule_builder_test {
621 name: "foo_sbox",
Colin Crossda6401b2021-04-21 11:32:19 -0700622 srcs: ["in"],
Dan Willemsen633c5022019-04-12 11:11:38 -0700623 sbox: true,
Colin Crossfeec25b2019-01-30 17:32:39 -0800624 }
Colin Crossce3a51d2021-03-19 16:22:12 -0700625 rule_builder_test {
626 name: "foo_sbox_inputs",
Colin Crossda6401b2021-04-21 11:32:19 -0700627 srcs: ["in"],
Colin Crossce3a51d2021-03-19 16:22:12 -0700628 sbox: true,
629 sbox_inputs: true,
630 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800631 `
632
Paul Duffin30ac3e72021-03-20 00:36:14 +0000633 result := GroupFixturePreparers(
Paul Duffind250ff62021-03-16 21:51:29 +0000634 prepareForRuleBuilderTest,
635 FixtureWithRootAndroidBp(bp),
636 fs.AddToFixture(),
Paul Duffin30ac3e72021-03-20 00:36:14 +0000637 ).RunTest(t)
Colin Crossfeec25b2019-01-30 17:32:39 -0800638
Colin Crossce3a51d2021-03-19 16:22:12 -0700639 check := func(t *testing.T, params TestingBuildParams, rspFile2Params TestingBuildParams,
640 wantCommand, wantOutput, wantDepfile, wantRspFile, wantRspFile2 string,
641 wantRestat bool, extraImplicits, extraCmdDeps []string) {
642
Dan Willemsenc89b6f12019-08-29 14:47:40 -0700643 t.Helper()
Colin Cross3d680512020-11-13 16:23:53 -0800644 command := params.RuleParams.Command
Colin Crosse16ce362020-11-12 08:29:30 -0800645 re := regexp.MustCompile(" # hash of input list: [a-z0-9]*$")
Colin Cross3d680512020-11-13 16:23:53 -0800646 command = re.ReplaceAllLiteralString(command, "")
Paul Duffind250ff62021-03-16 21:51:29 +0000647
648 AssertStringEquals(t, "RuleParams.Command", wantCommand, command)
Dan Willemsen633c5022019-04-12 11:11:38 -0700649
650 wantDeps := append([]string{"cp"}, extraCmdDeps...)
Paul Duffind250ff62021-03-16 21:51:29 +0000651 AssertArrayString(t, "RuleParams.CommandDeps", wantDeps, params.RuleParams.CommandDeps)
Dan Willemsen633c5022019-04-12 11:11:38 -0700652
Paul Duffind250ff62021-03-16 21:51:29 +0000653 AssertBoolEquals(t, "RuleParams.Restat", wantRestat, params.RuleParams.Restat)
Colin Crossfeec25b2019-01-30 17:32:39 -0800654
Colin Crossce3a51d2021-03-19 16:22:12 -0700655 wantInputs := []string{"rsp_in"}
656 AssertArrayString(t, "Inputs", wantInputs, params.Inputs.Strings())
657
Colin Crossda6401b2021-04-21 11:32:19 -0700658 wantImplicits := append([]string{"implicit", "in"}, extraImplicits...)
Colin Crossce3a51d2021-03-19 16:22:12 -0700659 // The second rsp file and the files listed in it should be in implicits
660 wantImplicits = append(wantImplicits, "rsp_in2", wantRspFile2)
Paul Duffin709e0e32021-03-22 10:09:02 +0000661 AssertPathsRelativeToTopEquals(t, "Implicits", wantImplicits, params.Implicits)
Colin Crossfeec25b2019-01-30 17:32:39 -0800662
Colin Crossda6401b2021-04-21 11:32:19 -0700663 wantOrderOnlys := []string{"orderonly"}
664 AssertPathsRelativeToTopEquals(t, "OrderOnly", wantOrderOnlys, params.OrderOnly)
665
Colin Crossae89abe2021-04-21 11:45:23 -0700666 wantValidations := []string{"validation"}
667 AssertPathsRelativeToTopEquals(t, "Validations", wantValidations, params.Validations)
668
Colin Crossce3a51d2021-03-19 16:22:12 -0700669 wantRspFileContent := "$in"
670 AssertStringEquals(t, "RspfileContent", wantRspFileContent, params.RuleParams.RspfileContent)
671
672 AssertStringEquals(t, "Rspfile", wantRspFile, params.RuleParams.Rspfile)
673
Paul Duffin709e0e32021-03-22 10:09:02 +0000674 AssertPathRelativeToTopEquals(t, "Output", wantOutput, params.Output)
Colin Crossbaa676f2019-02-25 14:56:01 -0800675
Dan Willemsen633c5022019-04-12 11:11:38 -0700676 if len(params.ImplicitOutputs) != 0 {
677 t.Errorf("want ImplicitOutputs = [], got %q", params.ImplicitOutputs.Strings())
678 }
679
Paul Duffin709e0e32021-03-22 10:09:02 +0000680 AssertPathRelativeToTopEquals(t, "Depfile", wantDepfile, params.Depfile)
Dan Willemsen633c5022019-04-12 11:11:38 -0700681
682 if params.Deps != blueprint.DepsGCC {
683 t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps)
Colin Crossbaa676f2019-02-25 14:56:01 -0800684 }
Colin Crossce3a51d2021-03-19 16:22:12 -0700685
Colin Crossf61d03d2023-11-02 16:56:39 -0700686 rspFile2Content := ContentFromFileRuleForTests(t, result.TestContext, rspFile2Params)
Colin Crossce3a51d2021-03-19 16:22:12 -0700687 AssertStringEquals(t, "rspFile2 content", "rsp_in2\n", rspFile2Content)
Colin Crossfeec25b2019-01-30 17:32:39 -0800688 }
689
Colin Cross4c83e5c2019-02-25 14:54:28 -0800690 t.Run("module", func(t *testing.T) {
Paul Duffin709e0e32021-03-22 10:09:02 +0000691 outFile := "out/soong/.intermediates/foo/gen/foo"
Colin Crossce3a51d2021-03-19 16:22:12 -0700692 rspFile := "out/soong/.intermediates/foo/rsp"
693 rspFile2 := "out/soong/.intermediates/foo/rsp2"
694 module := result.ModuleForTests("foo", "")
Paul Duffina71a67a2021-03-29 00:42:57 +0100695 check(t, module.Rule("rule"), module.Output(rspFile2),
Colin Crossda6401b2021-04-21 11:32:19 -0700696 "cp in "+outFile+" @"+rspFile+" @"+rspFile2,
Colin Crossce3a51d2021-03-19 16:22:12 -0700697 outFile, outFile+".d", rspFile, rspFile2, true, nil, nil)
Dan Willemsen633c5022019-04-12 11:11:38 -0700698 })
699 t.Run("sbox", func(t *testing.T) {
Paul Duffin709e0e32021-03-22 10:09:02 +0000700 outDir := "out/soong/.intermediates/foo_sbox"
Colin Crosse52c2ac2022-03-28 17:03:35 -0700701 sboxOutDir := filepath.Join(outDir, "gen")
702 outFile := filepath.Join(sboxOutDir, "foo_sbox")
703 depFile := filepath.Join(sboxOutDir, "foo_sbox.d")
Colin Crossce3a51d2021-03-19 16:22:12 -0700704 rspFile := filepath.Join(outDir, "rsp")
705 rspFile2 := filepath.Join(outDir, "rsp2")
706 manifest := filepath.Join(outDir, "sbox.textproto")
707 sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox")
708 sandboxPath := shared.TempDirForOutDir("out/soong")
709
Colin Crosse52c2ac2022-03-28 17:03:35 -0700710 cmd := sbox + ` --sandbox-path ` + sandboxPath + ` --output-dir ` + sboxOutDir + ` --manifest ` + manifest
Colin Crossce3a51d2021-03-19 16:22:12 -0700711 module := result.ModuleForTests("foo_sbox", "")
Paul Duffina71a67a2021-03-29 00:42:57 +0100712 check(t, module.Output("gen/foo_sbox"), module.Output(rspFile2),
Colin Crossce3a51d2021-03-19 16:22:12 -0700713 cmd, outFile, depFile, rspFile, rspFile2, false, []string{manifest}, []string{sbox})
714 })
715 t.Run("sbox_inputs", func(t *testing.T) {
716 outDir := "out/soong/.intermediates/foo_sbox_inputs"
Colin Crosse52c2ac2022-03-28 17:03:35 -0700717 sboxOutDir := filepath.Join(outDir, "gen")
718 outFile := filepath.Join(sboxOutDir, "foo_sbox_inputs")
719 depFile := filepath.Join(sboxOutDir, "foo_sbox_inputs.d")
Colin Crossce3a51d2021-03-19 16:22:12 -0700720 rspFile := filepath.Join(outDir, "rsp")
721 rspFile2 := filepath.Join(outDir, "rsp2")
Colin Crosse16ce362020-11-12 08:29:30 -0800722 manifest := filepath.Join(outDir, "sbox.textproto")
Paul Duffin709e0e32021-03-22 10:09:02 +0000723 sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox")
724 sandboxPath := shared.TempDirForOutDir("out/soong")
Dan Willemsen633c5022019-04-12 11:11:38 -0700725
Colin Crosse52c2ac2022-03-28 17:03:35 -0700726 cmd := sbox + ` --sandbox-path ` + sandboxPath + ` --output-dir ` + sboxOutDir + ` --manifest ` + manifest
Dan Willemsen633c5022019-04-12 11:11:38 -0700727
Colin Crossce3a51d2021-03-19 16:22:12 -0700728 module := result.ModuleForTests("foo_sbox_inputs", "")
Paul Duffina71a67a2021-03-29 00:42:57 +0100729 check(t, module.Output("gen/foo_sbox_inputs"), module.Output(rspFile2),
Colin Crossce3a51d2021-03-19 16:22:12 -0700730 cmd, outFile, depFile, rspFile, rspFile2, false, []string{manifest}, []string{sbox})
Colin Cross4c83e5c2019-02-25 14:54:28 -0800731 })
732 t.Run("singleton", func(t *testing.T) {
Paul Duffin709e0e32021-03-22 10:09:02 +0000733 outFile := filepath.Join("out/soong/singleton/gen/baz")
Colin Crossce3a51d2021-03-19 16:22:12 -0700734 rspFile := filepath.Join("out/soong/singleton/rsp")
735 rspFile2 := filepath.Join("out/soong/singleton/rsp2")
736 singleton := result.SingletonForTests("rule_builder_test")
Paul Duffina71a67a2021-03-29 00:42:57 +0100737 check(t, singleton.Rule("rule"), singleton.Output(rspFile2),
Colin Crossda6401b2021-04-21 11:32:19 -0700738 "cp in "+outFile+" @"+rspFile+" @"+rspFile2,
Colin Crossce3a51d2021-03-19 16:22:12 -0700739 outFile, outFile+".d", rspFile, rspFile2, true, nil, nil)
Colin Cross4c83e5c2019-02-25 14:54:28 -0800740 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800741}
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700742
Colin Cross3d680512020-11-13 16:23:53 -0800743func TestRuleBuilderHashInputs(t *testing.T) {
744 // The basic idea here is to verify that the command (in the case of a
745 // non-sbox rule) or the sbox textproto manifest contain a hash of the
746 // inputs.
747
748 // By including a hash of the inputs, we cause the rule to re-run if
749 // the list of inputs changes because the command line or a dependency
750 // changes.
751
Colin Crossda6401b2021-04-21 11:32:19 -0700752 hashOf := func(s string) string {
753 sum := sha256.Sum256([]byte(s))
754 return hex.EncodeToString(sum[:])
755 }
756
Colin Cross3d680512020-11-13 16:23:53 -0800757 bp := `
758 rule_builder_test {
759 name: "hash0",
760 srcs: ["in1.txt", "in2.txt"],
761 }
762 rule_builder_test {
763 name: "hash0_sbox",
764 srcs: ["in1.txt", "in2.txt"],
765 sbox: true,
766 }
767 rule_builder_test {
768 name: "hash1",
769 srcs: ["in1.txt", "in2.txt", "in3.txt"],
770 }
771 rule_builder_test {
772 name: "hash1_sbox",
773 srcs: ["in1.txt", "in2.txt", "in3.txt"],
774 sbox: true,
775 }
776 `
777 testcases := []struct {
778 name string
779 expectedHash string
780 }{
781 {
Colin Crossda6401b2021-04-21 11:32:19 -0700782 name: "hash0",
783 expectedHash: hashOf("implicit\nin1.txt\nin2.txt"),
Colin Cross3d680512020-11-13 16:23:53 -0800784 },
785 {
Colin Crossda6401b2021-04-21 11:32:19 -0700786 name: "hash1",
787 expectedHash: hashOf("implicit\nin1.txt\nin2.txt\nin3.txt"),
Colin Cross3d680512020-11-13 16:23:53 -0800788 },
789 }
790
Paul Duffin30ac3e72021-03-20 00:36:14 +0000791 result := GroupFixturePreparers(
Paul Duffind250ff62021-03-16 21:51:29 +0000792 prepareForRuleBuilderTest,
793 FixtureWithRootAndroidBp(bp),
Paul Duffin30ac3e72021-03-20 00:36:14 +0000794 ).RunTest(t)
Colin Cross3d680512020-11-13 16:23:53 -0800795
796 for _, test := range testcases {
797 t.Run(test.name, func(t *testing.T) {
798 t.Run("sbox", func(t *testing.T) {
Paul Duffind250ff62021-03-16 21:51:29 +0000799 gen := result.ModuleForTests(test.name+"_sbox", "")
Colin Crossf61d03d2023-11-02 16:56:39 -0700800 manifest := RuleBuilderSboxProtoForTests(t, result.TestContext, gen.Output("sbox.textproto"))
Colin Crosse16ce362020-11-12 08:29:30 -0800801 hash := manifest.Commands[0].GetInputHash()
802
Paul Duffind250ff62021-03-16 21:51:29 +0000803 AssertStringEquals(t, "hash", test.expectedHash, hash)
Colin Cross3d680512020-11-13 16:23:53 -0800804 })
805 t.Run("", func(t *testing.T) {
Paul Duffind250ff62021-03-16 21:51:29 +0000806 gen := result.ModuleForTests(test.name+"", "")
Colin Crosse16ce362020-11-12 08:29:30 -0800807 command := gen.Output("gen/" + test.name).RuleParams.Command
Colin Cross3d680512020-11-13 16:23:53 -0800808 if g, w := command, " # hash of input list: "+test.expectedHash; !strings.HasSuffix(g, w) {
809 t.Errorf("Expected command line to end with %q, got %q", w, g)
810 }
811 })
812 })
813 }
814}
Sam Delmerico285b66a2023-09-25 12:13:17 +0000815
816func TestRuleBuilderWithNinjaVarEscaping(t *testing.T) {
817 bp := `
818 rule_builder_test {
819 name: "foo_sbox_escaped_ninja",
820 flags: ["${cmdFlags}"],
821 sbox: true,
822 sbox_inputs: true,
823 }
824 rule_builder_test {
825 name: "foo_sbox",
826 flags: ["${cmdFlags}"],
827 sbox: true,
828 sbox_inputs: true,
829 unescape_ninja_vars: true,
830 }
831 `
832 result := GroupFixturePreparers(
833 prepareForRuleBuilderTest,
834 FixtureWithRootAndroidBp(bp),
835 ).RunTest(t)
836
837 escapedNinjaMod := result.ModuleForTests("foo_sbox_escaped_ninja", "").Rule("writeFile")
838 AssertStringDoesContain(
839 t,
840 "",
841 escapedNinjaMod.BuildParams.Args["content"],
842 "$${cmdFlags}",
843 )
844
845 unescapedNinjaMod := result.ModuleForTests("foo_sbox", "").Rule("unescapedWriteFile")
846 AssertStringDoesContain(
847 t,
848 "",
849 unescapedNinjaMod.BuildParams.Args["content"],
850 "${cmdFlags}",
851 )
852 AssertStringDoesNotContain(
853 t,
854 "",
855 unescapedNinjaMod.BuildParams.Args["content"],
856 "$${cmdFlags}",
857 )
858}