blob: bd3582070e630fa7c25bd2e3a0287f4a76b92637 [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 Cross758290d2019-02-01 16:42:32 -080018 "fmt"
Colin Crossfeec25b2019-01-30 17:32:39 -080019 "path/filepath"
Colin Cross3d680512020-11-13 16:23:53 -080020 "regexp"
Colin Cross758290d2019-02-01 16:42:32 -080021 "strings"
Colin Crossfeec25b2019-01-30 17:32:39 -080022 "testing"
Dan Willemsen633c5022019-04-12 11:11:38 -070023
24 "github.com/google/blueprint"
25
26 "android/soong/shared"
Colin Crossfeec25b2019-01-30 17:32:39 -080027)
28
Colin Crossf1a035e2020-11-16 17:32:30 -080029func builderContext() BuilderContext {
30 return BuilderContextForTesting(TestConfig("out", nil, "", map[string][]byte{
Colin Cross98be1bb2019-12-13 20:41:13 -080031 "ld": nil,
32 "a.o": nil,
33 "b.o": nil,
34 "cp": nil,
35 "a": nil,
36 "b": nil,
37 "ls": nil,
Jingwen Chence679d22020-09-23 04:30:02 +000038 "ln": nil,
Colin Cross98be1bb2019-12-13 20:41:13 -080039 "turbine": nil,
40 "java": nil,
41 "javac": nil,
42 }))
Colin Cross69f59a32019-02-15 10:39:37 -080043}
44
Colin Cross758290d2019-02-01 16:42:32 -080045func ExampleRuleBuilder() {
Colin Crossf1a035e2020-11-16 17:32:30 -080046 ctx := builderContext()
Colin Cross758290d2019-02-01 16:42:32 -080047
Colin Crossf1a035e2020-11-16 17:32:30 -080048 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -080049
50 rule.Command().
51 Tool(PathForSource(ctx, "ld")).
52 Inputs(PathsForTesting("a.o", "b.o")).
53 FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -080054 rule.Command().Text("echo success")
55
56 // To add the command to the build graph:
Colin Crossf1a035e2020-11-16 17:32:30 -080057 // rule.Build("link", "link")
Colin Cross758290d2019-02-01 16:42:32 -080058
59 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
60 fmt.Printf("tools: %q\n", rule.Tools())
61 fmt.Printf("inputs: %q\n", rule.Inputs())
62 fmt.Printf("outputs: %q\n", rule.Outputs())
63
64 // Output:
Colin Cross69f59a32019-02-15 10:39:37 -080065 // commands: "ld a.o b.o -o out/linked && echo success"
Colin Cross758290d2019-02-01 16:42:32 -080066 // tools: ["ld"]
67 // inputs: ["a.o" "b.o"]
Colin Cross69f59a32019-02-15 10:39:37 -080068 // outputs: ["out/linked"]
Colin Cross758290d2019-02-01 16:42:32 -080069}
70
Jingwen Chence679d22020-09-23 04:30:02 +000071func ExampleRuleBuilder_SymlinkOutputs() {
Colin Crossf1a035e2020-11-16 17:32:30 -080072 ctx := builderContext()
Jingwen Chence679d22020-09-23 04:30:02 +000073
Colin Crossf1a035e2020-11-16 17:32:30 -080074 rule := NewRuleBuilder(pctx, ctx)
Jingwen Chence679d22020-09-23 04:30:02 +000075
76 rule.Command().
77 Tool(PathForSource(ctx, "ln")).
78 FlagWithInput("-s ", PathForTesting("a.o")).
79 SymlinkOutput(PathForOutput(ctx, "a"))
80 rule.Command().Text("cp out/a out/b").
81 ImplicitSymlinkOutput(PathForOutput(ctx, "b"))
82
83 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
84 fmt.Printf("tools: %q\n", rule.Tools())
85 fmt.Printf("inputs: %q\n", rule.Inputs())
86 fmt.Printf("outputs: %q\n", rule.Outputs())
87 fmt.Printf("symlink_outputs: %q\n", rule.SymlinkOutputs())
88
89 // Output:
90 // commands: "ln -s a.o out/a && cp out/a out/b"
91 // tools: ["ln"]
92 // inputs: ["a.o"]
93 // outputs: ["out/a" "out/b"]
94 // symlink_outputs: ["out/a" "out/b"]
95}
96
Colin Cross5cb5b092019-02-02 21:25:18 -080097func ExampleRuleBuilder_Temporary() {
Colin Crossf1a035e2020-11-16 17:32:30 -080098 ctx := builderContext()
Colin Cross5cb5b092019-02-02 21:25:18 -080099
Colin Crossf1a035e2020-11-16 17:32:30 -0800100 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -0800101
102 rule.Command().
103 Tool(PathForSource(ctx, "cp")).
104 Input(PathForSource(ctx, "a")).
105 Output(PathForOutput(ctx, "b"))
106 rule.Command().
107 Tool(PathForSource(ctx, "cp")).
108 Input(PathForOutput(ctx, "b")).
109 Output(PathForOutput(ctx, "c"))
110 rule.Temporary(PathForOutput(ctx, "b"))
Colin Cross5cb5b092019-02-02 21:25:18 -0800111
112 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
113 fmt.Printf("tools: %q\n", rule.Tools())
114 fmt.Printf("inputs: %q\n", rule.Inputs())
115 fmt.Printf("outputs: %q\n", rule.Outputs())
116
117 // Output:
Colin Cross69f59a32019-02-15 10:39:37 -0800118 // commands: "cp a out/b && cp out/b out/c"
Colin Cross5cb5b092019-02-02 21:25:18 -0800119 // tools: ["cp"]
120 // inputs: ["a"]
Colin Cross69f59a32019-02-15 10:39:37 -0800121 // outputs: ["out/c"]
Colin Cross5cb5b092019-02-02 21:25:18 -0800122}
123
124func ExampleRuleBuilder_DeleteTemporaryFiles() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800125 ctx := builderContext()
Colin Cross5cb5b092019-02-02 21:25:18 -0800126
Colin Crossf1a035e2020-11-16 17:32:30 -0800127 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -0800128
129 rule.Command().
130 Tool(PathForSource(ctx, "cp")).
131 Input(PathForSource(ctx, "a")).
132 Output(PathForOutput(ctx, "b"))
133 rule.Command().
134 Tool(PathForSource(ctx, "cp")).
135 Input(PathForOutput(ctx, "b")).
136 Output(PathForOutput(ctx, "c"))
137 rule.Temporary(PathForOutput(ctx, "b"))
Colin Cross5cb5b092019-02-02 21:25:18 -0800138 rule.DeleteTemporaryFiles()
139
140 fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
141 fmt.Printf("tools: %q\n", rule.Tools())
142 fmt.Printf("inputs: %q\n", rule.Inputs())
143 fmt.Printf("outputs: %q\n", rule.Outputs())
144
145 // Output:
Colin Cross69f59a32019-02-15 10:39:37 -0800146 // commands: "cp a out/b && cp out/b out/c && rm -f out/b"
Colin Cross5cb5b092019-02-02 21:25:18 -0800147 // tools: ["cp"]
148 // inputs: ["a"]
Colin Cross69f59a32019-02-15 10:39:37 -0800149 // outputs: ["out/c"]
Colin Cross5cb5b092019-02-02 21:25:18 -0800150}
151
Colin Crossdeabb942019-02-11 14:11:09 -0800152func ExampleRuleBuilder_Installs() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800153 ctx := builderContext()
Colin Crossdeabb942019-02-11 14:11:09 -0800154
Colin Crossf1a035e2020-11-16 17:32:30 -0800155 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -0800156
157 out := PathForOutput(ctx, "linked")
158
159 rule.Command().
160 Tool(PathForSource(ctx, "ld")).
161 Inputs(PathsForTesting("a.o", "b.o")).
162 FlagWithOutput("-o ", out)
163 rule.Install(out, "/bin/linked")
164 rule.Install(out, "/sbin/linked")
Colin Crossdeabb942019-02-11 14:11:09 -0800165
166 fmt.Printf("rule.Installs().String() = %q\n", rule.Installs().String())
167
168 // Output:
Colin Cross69f59a32019-02-15 10:39:37 -0800169 // rule.Installs().String() = "out/linked:/bin/linked out/linked:/sbin/linked"
Colin Crossdeabb942019-02-11 14:11:09 -0800170}
171
Colin Cross758290d2019-02-01 16:42:32 -0800172func ExampleRuleBuilderCommand() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800173 ctx := builderContext()
Colin Cross758290d2019-02-01 16:42:32 -0800174
Colin Crossf1a035e2020-11-16 17:32:30 -0800175 rule := NewRuleBuilder(pctx, ctx)
Colin Cross69f59a32019-02-15 10:39:37 -0800176
Colin Cross758290d2019-02-01 16:42:32 -0800177 // chained
Colin Cross69f59a32019-02-15 10:39:37 -0800178 rule.Command().
179 Tool(PathForSource(ctx, "ld")).
180 Inputs(PathsForTesting("a.o", "b.o")).
181 FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -0800182
183 // unchained
184 cmd := rule.Command()
Colin Cross69f59a32019-02-15 10:39:37 -0800185 cmd.Tool(PathForSource(ctx, "ld"))
186 cmd.Inputs(PathsForTesting("a.o", "b.o"))
187 cmd.FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -0800188
189 // mixed:
Colin Cross69f59a32019-02-15 10:39:37 -0800190 cmd = rule.Command().Tool(PathForSource(ctx, "ld"))
191 cmd.Inputs(PathsForTesting("a.o", "b.o"))
192 cmd.FlagWithOutput("-o ", PathForOutput(ctx, "linked"))
Colin Cross758290d2019-02-01 16:42:32 -0800193}
194
195func ExampleRuleBuilderCommand_Flag() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800196 ctx := builderContext()
197 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800198 Tool(PathForSource(ctx, "ls")).Flag("-l"))
Colin Cross758290d2019-02-01 16:42:32 -0800199 // Output:
200 // ls -l
201}
202
Colin Cross92b7d582019-03-29 15:32:51 -0700203func ExampleRuleBuilderCommand_Flags() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800204 ctx := builderContext()
205 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross92b7d582019-03-29 15:32:51 -0700206 Tool(PathForSource(ctx, "ls")).Flags([]string{"-l", "-a"}))
207 // Output:
208 // ls -l -a
209}
210
Colin Cross758290d2019-02-01 16:42:32 -0800211func ExampleRuleBuilderCommand_FlagWithArg() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800212 ctx := builderContext()
213 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800214 Tool(PathForSource(ctx, "ls")).
Colin Cross758290d2019-02-01 16:42:32 -0800215 FlagWithArg("--sort=", "time"))
216 // Output:
217 // ls --sort=time
218}
219
Colin Crossc7ed0042019-02-11 14:11:09 -0800220func ExampleRuleBuilderCommand_FlagForEachArg() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800221 ctx := builderContext()
222 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800223 Tool(PathForSource(ctx, "ls")).
Colin Crossc7ed0042019-02-11 14:11:09 -0800224 FlagForEachArg("--sort=", []string{"time", "size"}))
225 // Output:
226 // ls --sort=time --sort=size
227}
228
Colin Cross758290d2019-02-01 16:42:32 -0800229func ExampleRuleBuilderCommand_FlagForEachInput() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800230 ctx := builderContext()
231 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800232 Tool(PathForSource(ctx, "turbine")).
233 FlagForEachInput("--classpath ", PathsForTesting("a.jar", "b.jar")))
Colin Cross758290d2019-02-01 16:42:32 -0800234 // Output:
235 // turbine --classpath a.jar --classpath b.jar
236}
237
238func ExampleRuleBuilderCommand_FlagWithInputList() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800239 ctx := builderContext()
240 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800241 Tool(PathForSource(ctx, "java")).
242 FlagWithInputList("-classpath=", PathsForTesting("a.jar", "b.jar"), ":"))
Colin Cross758290d2019-02-01 16:42:32 -0800243 // Output:
244 // java -classpath=a.jar:b.jar
245}
246
247func ExampleRuleBuilderCommand_FlagWithInput() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800248 ctx := builderContext()
249 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800250 Tool(PathForSource(ctx, "java")).
251 FlagWithInput("-classpath=", PathForSource(ctx, "a")))
Colin Cross758290d2019-02-01 16:42:32 -0800252 // Output:
253 // java -classpath=a
254}
255
256func ExampleRuleBuilderCommand_FlagWithList() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800257 ctx := builderContext()
258 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross69f59a32019-02-15 10:39:37 -0800259 Tool(PathForSource(ctx, "ls")).
Colin Cross758290d2019-02-01 16:42:32 -0800260 FlagWithList("--sort=", []string{"time", "size"}, ","))
261 // Output:
262 // ls --sort=time,size
263}
264
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700265func ExampleRuleBuilderCommand_FlagWithRspFileInputList() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800266 ctx := builderContext()
267 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700268 Tool(PathForSource(ctx, "javac")).
Colin Cross70c47412021-03-12 17:48:14 -0800269 FlagWithRspFileInputList("@", PathForOutput(ctx, "foo.rsp"), PathsForTesting("a.java", "b.java")).
270 String())
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700271 // Output:
Colin Cross70c47412021-03-12 17:48:14 -0800272 // javac @out/foo.rsp
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700273}
274
275func ExampleRuleBuilderCommand_String() {
Colin Crossf1a035e2020-11-16 17:32:30 -0800276 ctx := builderContext()
277 fmt.Println(NewRuleBuilder(pctx, ctx).Command().
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700278 Text("FOO=foo").
279 Text("echo $FOO").
280 String())
281 // Output:
282 // FOO=foo echo $FOO
283}
284
Colin Crossfeec25b2019-01-30 17:32:39 -0800285func TestRuleBuilder(t *testing.T) {
Colin Cross69f59a32019-02-15 10:39:37 -0800286 fs := map[string][]byte{
Colin Crossda71eda2020-02-21 16:55:19 -0800287 "dep_fixer": nil,
288 "input": nil,
289 "Implicit": nil,
290 "Input": nil,
291 "OrderOnly": nil,
292 "OrderOnlys": nil,
293 "Tool": nil,
294 "input2": nil,
295 "tool2": nil,
296 "input3": nil,
Colin Cross69f59a32019-02-15 10:39:37 -0800297 }
298
Colin Crossf1a035e2020-11-16 17:32:30 -0800299 pathCtx := PathContextForTesting(TestConfig("out", nil, "", fs))
300 ctx := builderContextForTests{
301 PathContext: pathCtx,
302 }
Colin Cross69f59a32019-02-15 10:39:37 -0800303
Dan Willemsen633c5022019-04-12 11:11:38 -0700304 addCommands := func(rule *RuleBuilder) {
305 cmd := rule.Command().
306 DepFile(PathForOutput(ctx, "DepFile")).
307 Flag("Flag").
308 FlagWithArg("FlagWithArg=", "arg").
309 FlagWithDepFile("FlagWithDepFile=", PathForOutput(ctx, "depfile")).
310 FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")).
311 FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "output")).
312 Implicit(PathForSource(ctx, "Implicit")).
313 ImplicitDepFile(PathForOutput(ctx, "ImplicitDepFile")).
314 ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")).
315 Input(PathForSource(ctx, "Input")).
316 Output(PathForOutput(ctx, "Output")).
Colin Crossda71eda2020-02-21 16:55:19 -0800317 OrderOnly(PathForSource(ctx, "OrderOnly")).
Jingwen Chence679d22020-09-23 04:30:02 +0000318 SymlinkOutput(PathForOutput(ctx, "SymlinkOutput")).
319 ImplicitSymlinkOutput(PathForOutput(ctx, "ImplicitSymlinkOutput")).
Dan Willemsen633c5022019-04-12 11:11:38 -0700320 Text("Text").
321 Tool(PathForSource(ctx, "Tool"))
Colin Crossfeec25b2019-01-30 17:32:39 -0800322
Dan Willemsen633c5022019-04-12 11:11:38 -0700323 rule.Command().
324 Text("command2").
325 DepFile(PathForOutput(ctx, "depfile2")).
326 Input(PathForSource(ctx, "input2")).
327 Output(PathForOutput(ctx, "output2")).
Colin Crossda71eda2020-02-21 16:55:19 -0800328 OrderOnlys(PathsForSource(ctx, []string{"OrderOnlys"})).
Dan Willemsen633c5022019-04-12 11:11:38 -0700329 Tool(PathForSource(ctx, "tool2"))
Colin Crossfeec25b2019-01-30 17:32:39 -0800330
Dan Willemsen633c5022019-04-12 11:11:38 -0700331 // Test updates to the first command after the second command has been started
332 cmd.Text("after command2")
333 // Test updating a command when the previous update did not replace the cmd variable
334 cmd.Text("old cmd")
Colin Crossfeec25b2019-01-30 17:32:39 -0800335
Dan Willemsen633c5022019-04-12 11:11:38 -0700336 // Test a command that uses the output of a previous command as an input
337 rule.Command().
338 Text("command3").
339 Input(PathForSource(ctx, "input3")).
340 Input(PathForOutput(ctx, "output2")).
341 Output(PathForOutput(ctx, "output3"))
Colin Crossfeec25b2019-01-30 17:32:39 -0800342 }
Colin Cross1d2cf042019-03-29 15:33:06 -0700343
Colin Cross69f59a32019-02-15 10:39:37 -0800344 wantInputs := PathsForSource(ctx, []string{"Implicit", "Input", "input", "input2", "input3"})
Jingwen Chence679d22020-09-23 04:30:02 +0000345 wantOutputs := PathsForOutput(ctx, []string{"ImplicitOutput", "ImplicitSymlinkOutput", "Output", "SymlinkOutput", "output", "output2", "output3"})
Colin Cross1d2cf042019-03-29 15:33:06 -0700346 wantDepFiles := PathsForOutput(ctx, []string{"DepFile", "depfile", "ImplicitDepFile", "depfile2"})
Colin Cross69f59a32019-02-15 10:39:37 -0800347 wantTools := PathsForSource(ctx, []string{"Tool", "tool2"})
Colin Crossda71eda2020-02-21 16:55:19 -0800348 wantOrderOnlys := PathsForSource(ctx, []string{"OrderOnly", "OrderOnlys"})
Jingwen Chence679d22020-09-23 04:30:02 +0000349 wantSymlinkOutputs := PathsForOutput(ctx, []string{"ImplicitSymlinkOutput", "SymlinkOutput"})
Colin Crossfeec25b2019-01-30 17:32:39 -0800350
Dan Willemsen633c5022019-04-12 11:11:38 -0700351 t.Run("normal", func(t *testing.T) {
Colin Crossf1a035e2020-11-16 17:32:30 -0800352 rule := NewRuleBuilder(pctx, ctx)
Dan Willemsen633c5022019-04-12 11:11:38 -0700353 addCommands(rule)
Colin Cross1d2cf042019-03-29 15:33:06 -0700354
Dan Willemsen633c5022019-04-12 11:11:38 -0700355 wantCommands := []string{
Jingwen Chence679d22020-09-23 04:30:02 +0000356 "out/DepFile Flag FlagWithArg=arg FlagWithDepFile=out/depfile FlagWithInput=input FlagWithOutput=out/output Input out/Output out/SymlinkOutput Text Tool after command2 old cmd",
Dan Willemsen633c5022019-04-12 11:11:38 -0700357 "command2 out/depfile2 input2 out/output2 tool2",
358 "command3 input3 out/output2 out/output3",
359 }
Colin Cross1d2cf042019-03-29 15:33:06 -0700360
Dan Willemsen633c5022019-04-12 11:11:38 -0700361 wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer out/DepFile out/depfile out/ImplicitDepFile out/depfile2"
362
Paul Duffind250ff62021-03-16 21:51:29 +0000363 AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
Dan Willemsen633c5022019-04-12 11:11:38 -0700364
Paul Duffind250ff62021-03-16 21:51:29 +0000365 AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
366 AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
367 AssertDeepEquals(t, "rule.SymlinkOutputs()", wantSymlinkOutputs, rule.SymlinkOutputs())
368 AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
369 AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
370 AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
Dan Willemsen633c5022019-04-12 11:11:38 -0700371
Paul Duffind250ff62021-03-16 21:51:29 +0000372 AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
Dan Willemsen633c5022019-04-12 11:11:38 -0700373 })
374
375 t.Run("sbox", func(t *testing.T) {
Colin Crossf1a035e2020-11-16 17:32:30 -0800376 rule := NewRuleBuilder(pctx, ctx).Sbox(PathForOutput(ctx, ""),
Colin Crosse16ce362020-11-12 08:29:30 -0800377 PathForOutput(ctx, "sbox.textproto"))
Dan Willemsen633c5022019-04-12 11:11:38 -0700378 addCommands(rule)
379
380 wantCommands := []string{
Colin Crosse16ce362020-11-12 08:29:30 -0800381 "__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output Input __SBOX_SANDBOX_DIR__/out/Output __SBOX_SANDBOX_DIR__/out/SymlinkOutput Text Tool after command2 old cmd",
382 "command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 tool2",
383 "command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3",
Dan Willemsen633c5022019-04-12 11:11:38 -0700384 }
385
Colin Crosse16ce362020-11-12 08:29:30 -0800386 wantDepMergerCommand := "out/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"
Dan Willemsen633c5022019-04-12 11:11:38 -0700387
Paul Duffind250ff62021-03-16 21:51:29 +0000388 AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
Dan Willemsen633c5022019-04-12 11:11:38 -0700389
Paul Duffind250ff62021-03-16 21:51:29 +0000390 AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
391 AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
392 AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
393 AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
394 AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
Dan Willemsen633c5022019-04-12 11:11:38 -0700395
Paul Duffind250ff62021-03-16 21:51:29 +0000396 AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
Dan Willemsen633c5022019-04-12 11:11:38 -0700397 })
Colin Crossba9e4032020-11-24 16:32:22 -0800398
399 t.Run("sbox tools", func(t *testing.T) {
400 rule := NewRuleBuilder(pctx, ctx).Sbox(PathForOutput(ctx, ""),
401 PathForOutput(ctx, "sbox.textproto")).SandboxTools()
402 addCommands(rule)
403
404 wantCommands := []string{
405 "__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output Input __SBOX_SANDBOX_DIR__/out/Output __SBOX_SANDBOX_DIR__/out/SymlinkOutput Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
406 "command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/tools/src/tool2",
407 "command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3",
408 }
409
410 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"
411
Paul Duffind250ff62021-03-16 21:51:29 +0000412 AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
Colin Crossba9e4032020-11-24 16:32:22 -0800413
Paul Duffind250ff62021-03-16 21:51:29 +0000414 AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
415 AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
416 AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
417 AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
418 AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
Colin Crossba9e4032020-11-24 16:32:22 -0800419
Paul Duffind250ff62021-03-16 21:51:29 +0000420 AssertSame(t, "rule.depFileMergerCmd()", wantDepMergerCommand, rule.depFileMergerCmd(rule.DepFiles()).String())
Colin Crossba9e4032020-11-24 16:32:22 -0800421 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800422}
423
424func testRuleBuilderFactory() Module {
425 module := &testRuleBuilderModule{}
426 module.AddProperties(&module.properties)
427 InitAndroidModule(module)
428 return module
429}
430
431type testRuleBuilderModule struct {
432 ModuleBase
433 properties struct {
Colin Cross3d680512020-11-13 16:23:53 -0800434 Srcs []string
Dan Willemsen633c5022019-04-12 11:11:38 -0700435
436 Restat bool
437 Sbox bool
Colin Crossfeec25b2019-01-30 17:32:39 -0800438 }
439}
440
441func (t *testRuleBuilderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Colin Cross3d680512020-11-13 16:23:53 -0800442 in := PathsForSource(ctx, t.properties.Srcs)
Colin Crosse16ce362020-11-12 08:29:30 -0800443 out := PathForModuleOut(ctx, "gen", ctx.ModuleName())
444 outDep := PathForModuleOut(ctx, "gen", ctx.ModuleName()+".d")
445 outDir := PathForModuleOut(ctx, "gen")
446 manifestPath := PathForModuleOut(ctx, "sbox.textproto")
Colin Crossfeec25b2019-01-30 17:32:39 -0800447
Colin Crosse16ce362020-11-12 08:29:30 -0800448 testRuleBuilder_Build(ctx, in, out, outDep, outDir, manifestPath, t.properties.Restat, t.properties.Sbox)
Colin Cross786cd6d2019-02-01 16:41:11 -0800449}
450
451type testRuleBuilderSingleton struct{}
452
453func testRuleBuilderSingletonFactory() Singleton {
454 return &testRuleBuilderSingleton{}
455}
456
457func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) {
458 in := PathForSource(ctx, "bar")
Colin Crosse16ce362020-11-12 08:29:30 -0800459 out := PathForOutput(ctx, "singleton/gen/baz")
460 outDep := PathForOutput(ctx, "singleton/gen/baz.d")
461 outDir := PathForOutput(ctx, "singleton/gen")
462 manifestPath := PathForOutput(ctx, "singleton/sbox.textproto")
463 testRuleBuilder_Build(ctx, Paths{in}, out, outDep, outDir, manifestPath, true, false)
Colin Cross786cd6d2019-02-01 16:41:11 -0800464}
465
Colin Crosse16ce362020-11-12 08:29:30 -0800466func testRuleBuilder_Build(ctx BuilderContext, in Paths, out, outDep, outDir, manifestPath WritablePath, restat, sbox bool) {
Colin Crossf1a035e2020-11-16 17:32:30 -0800467 rule := NewRuleBuilder(pctx, ctx)
Colin Cross786cd6d2019-02-01 16:41:11 -0800468
Dan Willemsen633c5022019-04-12 11:11:38 -0700469 if sbox {
Colin Crosse16ce362020-11-12 08:29:30 -0800470 rule.Sbox(outDir, manifestPath)
Dan Willemsen633c5022019-04-12 11:11:38 -0700471 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800472
Colin Cross3d680512020-11-13 16:23:53 -0800473 rule.Command().Tool(PathForSource(ctx, "cp")).Inputs(in).Output(out).ImplicitDepFile(outDep)
Dan Willemsen633c5022019-04-12 11:11:38 -0700474
475 if restat {
476 rule.Restat()
477 }
Colin Crossbaa676f2019-02-25 14:56:01 -0800478
Colin Crossf1a035e2020-11-16 17:32:30 -0800479 rule.Build("rule", "desc")
Colin Crossfeec25b2019-01-30 17:32:39 -0800480}
481
Paul Duffind250ff62021-03-16 21:51:29 +0000482var prepareForRuleBuilderTest = FixtureRegisterWithContext(func(ctx RegistrationContext) {
483 ctx.RegisterModuleType("rule_builder_test", testRuleBuilderFactory)
484 ctx.RegisterSingletonType("rule_builder_test", testRuleBuilderSingletonFactory)
485})
486
Colin Crossfeec25b2019-01-30 17:32:39 -0800487func TestRuleBuilder_Build(t *testing.T) {
Paul Duffind250ff62021-03-16 21:51:29 +0000488 fs := MockFS{
Colin Cross98be1bb2019-12-13 20:41:13 -0800489 "bar": nil,
490 "cp": nil,
491 }
492
Colin Crossfeec25b2019-01-30 17:32:39 -0800493 bp := `
494 rule_builder_test {
495 name: "foo",
Colin Cross3d680512020-11-13 16:23:53 -0800496 srcs: ["bar"],
Dan Willemsen633c5022019-04-12 11:11:38 -0700497 restat: true,
498 }
499 rule_builder_test {
500 name: "foo_sbox",
Colin Cross3d680512020-11-13 16:23:53 -0800501 srcs: ["bar"],
Dan Willemsen633c5022019-04-12 11:11:38 -0700502 sbox: true,
Colin Crossfeec25b2019-01-30 17:32:39 -0800503 }
504 `
505
Paul Duffind250ff62021-03-16 21:51:29 +0000506 result := emptyTestFixtureFactory.RunTest(t,
507 prepareForRuleBuilderTest,
508 FixtureWithRootAndroidBp(bp),
509 fs.AddToFixture(),
510 )
Colin Crossfeec25b2019-01-30 17:32:39 -0800511
Colin Crosse16ce362020-11-12 08:29:30 -0800512 check := func(t *testing.T, params TestingBuildParams, wantCommand, wantOutput, wantDepfile string, wantRestat bool, extraImplicits, extraCmdDeps []string) {
Dan Willemsenc89b6f12019-08-29 14:47:40 -0700513 t.Helper()
Colin Cross3d680512020-11-13 16:23:53 -0800514 command := params.RuleParams.Command
Colin Crosse16ce362020-11-12 08:29:30 -0800515 re := regexp.MustCompile(" # hash of input list: [a-z0-9]*$")
Colin Cross3d680512020-11-13 16:23:53 -0800516 command = re.ReplaceAllLiteralString(command, "")
Paul Duffind250ff62021-03-16 21:51:29 +0000517
518 AssertStringEquals(t, "RuleParams.Command", wantCommand, command)
Dan Willemsen633c5022019-04-12 11:11:38 -0700519
520 wantDeps := append([]string{"cp"}, extraCmdDeps...)
Paul Duffind250ff62021-03-16 21:51:29 +0000521 AssertArrayString(t, "RuleParams.CommandDeps", wantDeps, params.RuleParams.CommandDeps)
Dan Willemsen633c5022019-04-12 11:11:38 -0700522
Paul Duffind250ff62021-03-16 21:51:29 +0000523 AssertBoolEquals(t, "RuleParams.Restat", wantRestat, params.RuleParams.Restat)
Colin Crossfeec25b2019-01-30 17:32:39 -0800524
Colin Crosse16ce362020-11-12 08:29:30 -0800525 wantImplicits := append([]string{"bar"}, extraImplicits...)
Paul Duffind250ff62021-03-16 21:51:29 +0000526 AssertArrayString(t, "Implicits", wantImplicits, params.Implicits.Strings())
Colin Crossfeec25b2019-01-30 17:32:39 -0800527
Paul Duffind250ff62021-03-16 21:51:29 +0000528 AssertStringEquals(t, "Output", wantOutput, params.Output.String())
Colin Crossbaa676f2019-02-25 14:56:01 -0800529
Dan Willemsen633c5022019-04-12 11:11:38 -0700530 if len(params.ImplicitOutputs) != 0 {
531 t.Errorf("want ImplicitOutputs = [], got %q", params.ImplicitOutputs.Strings())
532 }
533
Paul Duffind250ff62021-03-16 21:51:29 +0000534 AssertStringEquals(t, "Depfile", wantDepfile, params.Depfile.String())
Dan Willemsen633c5022019-04-12 11:11:38 -0700535
536 if params.Deps != blueprint.DepsGCC {
537 t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps)
Colin Crossbaa676f2019-02-25 14:56:01 -0800538 }
Colin Crossfeec25b2019-01-30 17:32:39 -0800539 }
540
Paul Duffind250ff62021-03-16 21:51:29 +0000541 buildDir := result.Config.BuildDir()
542
Colin Cross4c83e5c2019-02-25 14:54:28 -0800543 t.Run("module", func(t *testing.T) {
Colin Crosse16ce362020-11-12 08:29:30 -0800544 outFile := filepath.Join(buildDir, ".intermediates", "foo", "gen", "foo")
Paul Duffind250ff62021-03-16 21:51:29 +0000545 check(t, result.ModuleForTests("foo", "").Rule("rule"),
Dan Willemsen633c5022019-04-12 11:11:38 -0700546 "cp bar "+outFile,
Colin Crosse16ce362020-11-12 08:29:30 -0800547 outFile, outFile+".d", true, nil, nil)
Dan Willemsen633c5022019-04-12 11:11:38 -0700548 })
549 t.Run("sbox", func(t *testing.T) {
550 outDir := filepath.Join(buildDir, ".intermediates", "foo_sbox")
Colin Crosse16ce362020-11-12 08:29:30 -0800551 outFile := filepath.Join(outDir, "gen/foo_sbox")
552 depFile := filepath.Join(outDir, "gen/foo_sbox.d")
553 manifest := filepath.Join(outDir, "sbox.textproto")
Paul Duffind250ff62021-03-16 21:51:29 +0000554 sbox := filepath.Join(buildDir, "host", result.Config.PrebuiltOS(), "bin/sbox")
Dan Willemsen633c5022019-04-12 11:11:38 -0700555 sandboxPath := shared.TempDirForOutDir(buildDir)
556
Colin Crosse16ce362020-11-12 08:29:30 -0800557 cmd := `rm -rf ` + outDir + `/gen && ` +
558 sbox + ` --sandbox-path ` + sandboxPath + ` --manifest ` + manifest
Dan Willemsen633c5022019-04-12 11:11:38 -0700559
Paul Duffind250ff62021-03-16 21:51:29 +0000560 check(t, result.ModuleForTests("foo_sbox", "").Output("gen/foo_sbox"),
Colin Crosse16ce362020-11-12 08:29:30 -0800561 cmd, outFile, depFile, false, []string{manifest}, []string{sbox})
Colin Cross4c83e5c2019-02-25 14:54:28 -0800562 })
563 t.Run("singleton", func(t *testing.T) {
Colin Crosse16ce362020-11-12 08:29:30 -0800564 outFile := filepath.Join(buildDir, "singleton/gen/baz")
Paul Duffind250ff62021-03-16 21:51:29 +0000565 check(t, result.SingletonForTests("rule_builder_test").Rule("rule"),
Colin Crosse16ce362020-11-12 08:29:30 -0800566 "cp bar "+outFile, outFile, outFile+".d", true, nil, nil)
Colin Cross4c83e5c2019-02-25 14:54:28 -0800567 })
Colin Crossfeec25b2019-01-30 17:32:39 -0800568}
Colin Cross0cb0d7b2019-07-11 10:59:15 -0700569
Colin Cross3d680512020-11-13 16:23:53 -0800570func TestRuleBuilderHashInputs(t *testing.T) {
571 // The basic idea here is to verify that the command (in the case of a
572 // non-sbox rule) or the sbox textproto manifest contain a hash of the
573 // inputs.
574
575 // By including a hash of the inputs, we cause the rule to re-run if
576 // the list of inputs changes because the command line or a dependency
577 // changes.
578
579 bp := `
580 rule_builder_test {
581 name: "hash0",
582 srcs: ["in1.txt", "in2.txt"],
583 }
584 rule_builder_test {
585 name: "hash0_sbox",
586 srcs: ["in1.txt", "in2.txt"],
587 sbox: true,
588 }
589 rule_builder_test {
590 name: "hash1",
591 srcs: ["in1.txt", "in2.txt", "in3.txt"],
592 }
593 rule_builder_test {
594 name: "hash1_sbox",
595 srcs: ["in1.txt", "in2.txt", "in3.txt"],
596 sbox: true,
597 }
598 `
599 testcases := []struct {
600 name string
601 expectedHash string
602 }{
603 {
604 name: "hash0",
605 // sha256 value obtained from: echo -en 'in1.txt\nin2.txt' | sha256sum
606 expectedHash: "18da75b9b1cc74b09e365b4ca2e321b5d618f438cc632b387ad9dc2ab4b20e9d",
607 },
608 {
609 name: "hash1",
610 // sha256 value obtained from: echo -en 'in1.txt\nin2.txt\nin3.txt' | sha256sum
611 expectedHash: "a38d432a4b19df93140e1f1fe26c97ff0387dae01fe506412b47208f0595fb45",
612 },
613 }
614
Paul Duffind250ff62021-03-16 21:51:29 +0000615 result := emptyTestFixtureFactory.RunTest(t,
616 prepareForRuleBuilderTest,
617 FixtureWithRootAndroidBp(bp),
618 )
Colin Cross3d680512020-11-13 16:23:53 -0800619
620 for _, test := range testcases {
621 t.Run(test.name, func(t *testing.T) {
622 t.Run("sbox", func(t *testing.T) {
Paul Duffind250ff62021-03-16 21:51:29 +0000623 gen := result.ModuleForTests(test.name+"_sbox", "")
Colin Crosse16ce362020-11-12 08:29:30 -0800624 manifest := RuleBuilderSboxProtoForTests(t, gen.Output("sbox.textproto"))
625 hash := manifest.Commands[0].GetInputHash()
626
Paul Duffind250ff62021-03-16 21:51:29 +0000627 AssertStringEquals(t, "hash", test.expectedHash, hash)
Colin Cross3d680512020-11-13 16:23:53 -0800628 })
629 t.Run("", func(t *testing.T) {
Paul Duffind250ff62021-03-16 21:51:29 +0000630 gen := result.ModuleForTests(test.name+"", "")
Colin Crosse16ce362020-11-12 08:29:30 -0800631 command := gen.Output("gen/" + test.name).RuleParams.Command
Colin Cross3d680512020-11-13 16:23:53 -0800632 if g, w := command, " # hash of input list: "+test.expectedHash; !strings.HasSuffix(g, w) {
633 t.Errorf("Expected command line to end with %q, got %q", w, g)
634 }
635 })
636 })
637 }
638}